This commit is contained in:
V 2023-06-21 20:25:43 +02:00
parent 8435cabcec
commit 7e78d5c0ae
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
6 changed files with 87 additions and 52 deletions

View file

@ -4,7 +4,7 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import { app, desktopCapturer, dialog, ipcMain, session, shell } from "electron"; import { app, dialog, ipcMain, session, shell } from "electron";
import { existsSync, readFileSync, watch } from "fs"; import { existsSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises"; import { open, readFile } from "fs/promises";
import { join } from "path"; import { join } from "path";
@ -75,8 +75,6 @@ ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
if (applicable.length) ses.setSpellCheckerLanguages(applicable); if (applicable.length) ses.setSpellCheckerLanguages(applicable);
}); });
ipcMain.handle(IpcEvents.CAPTURER_GET_SOURCES, (_, options) => desktopCapturer.getSources(options));
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => { ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
const res = await dialog.showOpenDialog(mainWin!, { const res = await dialog.showOpenDialog(mainWin!, {
properties: ["openDirectory"] properties: ["openDirectory"]

View file

@ -4,9 +4,22 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import { desktopCapturer, session } from "electron"; import { desktopCapturer, ipcMain, session, Streams } from "electron";
import type { StreamPick } from "renderer/components/ScreenSharePicker";
import { IpcEvents } from "shared/IpcEvents";
export function registerScreenShareHandler() { export function registerScreenShareHandler() {
ipcMain.handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => {
const sources = await desktopCapturer.getSources({
types: ["window", "screen"],
thumbnailSize: {
width: 1920,
height: 1080
}
});
return sources.find(s => s.id === id)?.thumbnail.toDataURL();
});
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => { session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
const sources = await desktopCapturer.getSources({ const sources = await desktopCapturer.getSources({
types: ["window", "screen"], types: ["window", "screen"],
@ -24,17 +37,19 @@ export function registerScreenShareHandler() {
const choice = await request.frame const choice = await request.frame
.executeJavaScript(`VencordDesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`) .executeJavaScript(`VencordDesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
.catch(() => "cancelled"); .then(e => e as StreamPick)
.catch(() => null);
if (choice === "cancelled") { if (!choice) return callback({});
callback({});
return;
}
const source = sources.find(s => s.id === choice); const source = sources.find(s => s.id === choice.id);
callback({ if (!source) return callback({});
video: source,
audio: "loopback" const streams: Streams = {
}); video: source
};
if (choice.audio) streams.audio = "loopback";
callback(streams);
}); });
} }

View file

@ -4,7 +4,6 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import type { DesktopCapturerSource, SourcesOptions } from "electron";
import type { Settings } from "shared/settings"; import type { Settings } from "shared/settings";
import type { LiteralUnion } from "type-fest"; import type { LiteralUnion } from "type-fest";
@ -37,13 +36,6 @@ export const VencordDesktopNative = {
focus: () => invoke<void>(IpcEvents.FOCUS) focus: () => invoke<void>(IpcEvents.FOCUS)
}, },
capturer: { capturer: {
getSources: async (options?: SourcesOptions) => { getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id)
const res = await invoke<DesktopCapturerSource[]>(IpcEvents.CAPTURER_GET_SOURCES, options);
return res.map(({ id, name, thumbnail }) => ({
id,
name,
url: thumbnail.toDataURL()
}));
}
} }
}; };

View file

@ -6,9 +6,9 @@
import "./screenSharePicker.css"; import "./screenSharePicker.css";
import { Modals, openModal } from "@vencord/types/utils"; import { closeModal, Modals, openModal, useAwaiter } from "@vencord/types/utils";
import { Button, Card, Forms, Switch, Text, useState } from "@vencord/types/webpack/common"; import { Button, Card, Forms, Switch, Text, useState } from "@vencord/types/webpack/common";
import { Dispatch, SetStateAction } from "react"; import type { Dispatch, SetStateAction } from "react";
const StreamResolutions = ["720", "1080", "1440", "Source"] as const; const StreamResolutions = ["720", "1080", "1440", "Source"] as const;
const StreamFps = ["15", "30", "60"] as const; const StreamFps = ["15", "30", "60"] as const;
@ -22,6 +22,10 @@ interface StreamSettings {
audio: boolean; audio: boolean;
} }
export interface StreamPick extends StreamSettings {
id: string;
}
interface Source { interface Source {
id: string; id: string;
name: string; name: string;
@ -29,18 +33,26 @@ interface Source {
} }
export function openScreenSharePicker(screens: Source[]) { export function openScreenSharePicker(screens: Source[]) {
return new Promise<string>((resolve, reject) => { return new Promise<StreamPick>((resolve, reject) => {
openModal(props => ( const key = openModal(
<ModalComponent props => (
screens={screens} <ModalComponent
modalProps={props} screens={screens}
submit={resolve} modalProps={props}
close={() => { submit={resolve}
props.onClose(); close={() => {
reject(new Error("Aborted")); props.onClose();
}} reject("Aborted");
/> }}
)); />
),
{
onCloseRequest() {
closeModal(key);
reject("Aborted");
}
}
);
}); });
} }
@ -68,11 +80,16 @@ function StreamSettings({
settings: StreamSettings; settings: StreamSettings;
setSettings: Dispatch<SetStateAction<StreamSettings>>; setSettings: Dispatch<SetStateAction<StreamSettings>>;
}) { }) {
const [thumb] = useAwaiter(() => VencordDesktopNative.capturer.getLargeThumbnail(source.id), {
fallbackValue: source.url,
deps: [source.id]
});
return ( return (
<div> <div>
<Forms.FormTitle>What you're streaming</Forms.FormTitle> <Forms.FormTitle>What you're streaming</Forms.FormTitle>
<Card className="vcd-screen-picker-card vcd-screen-picker-preview"> <Card className="vcd-screen-picker-card vcd-screen-picker-preview">
<img src={source.url} alt="" /> <img src={thumb} alt="" />
<Text variant="text-sm/normal">{source.name}</Text> <Text variant="text-sm/normal">{source.name}</Text>
</Card> </Card>
@ -85,7 +102,7 @@ function StreamSettings({
<div className="vcd-screen-picker-radios"> <div className="vcd-screen-picker-radios">
{StreamResolutions.map(res => ( {StreamResolutions.map(res => (
<label className="vcd-screen-picker-radio" data-checked={settings.resolution === res}> <label className="vcd-screen-picker-radio" data-checked={settings.resolution === res}>
<Forms.FormTitle>{res}</Forms.FormTitle> <Text variant="text-sm/bold">{res}</Text>
<input <input
type="radio" type="radio"
name="resolution" name="resolution"
@ -103,7 +120,7 @@ function StreamSettings({
<div className="vcd-screen-picker-radios"> <div className="vcd-screen-picker-radios">
{StreamFps.map(fps => ( {StreamFps.map(fps => (
<label className="vcd-screen-picker-radio" data-checked={settings.fps === fps}> <label className="vcd-screen-picker-radio" data-checked={settings.fps === fps}>
<Forms.FormTitle>{fps}</Forms.FormTitle> <Text variant="text-sm/bold">{fps}</Text>
<input <input
type="radio" type="radio"
name="fps" name="fps"
@ -138,7 +155,7 @@ function ModalComponent({
}: { }: {
screens: Source[]; screens: Source[];
modalProps: any; modalProps: any;
submit: (id: string) => void; submit: (data: StreamPick) => void;
close: () => void; close: () => void;
}) { }) {
const [selected, setSelected] = useState<string>(); const [selected, setSelected] = useState<string>();
@ -150,8 +167,8 @@ function ModalComponent({
return ( return (
<Modals.ModalRoot {...modalProps}> <Modals.ModalRoot {...modalProps}>
<Modals.ModalHeader> <Modals.ModalHeader className="vcd-screen-picker-header">
<Forms.FormTitle tag="h2">Screen Picker</Forms.FormTitle> <Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
<Modals.ModalCloseButton onClick={close} /> <Modals.ModalCloseButton onClick={close} />
</Modals.ModalHeader> </Modals.ModalHeader>
@ -167,11 +184,14 @@ function ModalComponent({
)} )}
</Modals.ModalContent> </Modals.ModalContent>
<Modals.ModalFooter> <Modals.ModalFooter className="vcd-screen-picker-footer">
<Button <Button
disabled={!selected} disabled={!selected}
onClick={() => { onClick={() => {
submit(selected!); submit({
id: selected!,
...settings
});
close(); close();
}} }}
> >

View file

@ -2,7 +2,17 @@
padding: 1em; padding: 1em;
} }
.vcd-screen-picker-grid { display: grid; .vcd-screen-picker-header h1 {
margin: 0;
}
.vcd-screen-picker-footer {
display: flex;
gap: 1em;
}
.vcd-screen-picker-grid {
display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 2em 1em; gap: 2em 1em;
} }
@ -13,7 +23,8 @@
} }
.vcd-screen-picker-selected img { .vcd-screen-picker-selected img {
outline: 2px solid var(--brand-experiment); border: 2px solid var(--brand-experiment);
border-radius: 3px;
} }
.vcd-screen-picker-grid label { .vcd-screen-picker-grid label {
@ -43,7 +54,7 @@
.vcd-screen-picker-preview img { .vcd-screen-picker-preview img {
width: 100%; width: 100%;
height: 100%; margin-bottom: 0.5em;
} }
.vcd-screen-picker-preview { .vcd-screen-picker-preview {
@ -51,8 +62,7 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; margin-bottom: 1em;
width: 100%;
} }
.vcd-screen-picker-radio input { .vcd-screen-picker-radio input {

View file

@ -28,9 +28,9 @@ export const enum IpcEvents {
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES", SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
CAPTURER_GET_SOURCES = "VCD_CAPTURER_GET_SOURCES", CAPTURER_GET_LARGE_THUMBNAIL = "VCD_CAPTURER_GET_LARGE_THUMBNAIL",
AUTOSTART_ENABLED = "VCD_AUTOSTART_ENABLED", AUTOSTART_ENABLED = "VCD_AUTOSTART_ENABLED",
ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART", ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART",
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART", DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART"
} }