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

View file

@ -4,9 +4,22 @@
* 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() {
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) => {
const sources = await desktopCapturer.getSources({
types: ["window", "screen"],
@ -24,17 +37,19 @@ export function registerScreenShareHandler() {
const choice = await request.frame
.executeJavaScript(`VencordDesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
.catch(() => "cancelled");
.then(e => e as StreamPick)
.catch(() => null);
if (choice === "cancelled") {
callback({});
return;
}
if (!choice) return callback({});
const source = sources.find(s => s.id === choice);
callback({
video: source,
audio: "loopback"
});
const source = sources.find(s => s.id === choice.id);
if (!source) return callback({});
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
*/
import type { DesktopCapturerSource, SourcesOptions } from "electron";
import type { Settings } from "shared/settings";
import type { LiteralUnion } from "type-fest";
@ -37,13 +36,6 @@ export const VencordDesktopNative = {
focus: () => invoke<void>(IpcEvents.FOCUS)
},
capturer: {
getSources: async (options?: SourcesOptions) => {
const res = await invoke<DesktopCapturerSource[]>(IpcEvents.CAPTURER_GET_SOURCES, options);
return res.map(({ id, name, thumbnail }) => ({
id,
name,
url: thumbnail.toDataURL()
}));
}
getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id)
}
};

View file

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

View file

@ -2,7 +2,17 @@
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;
gap: 2em 1em;
}
@ -13,7 +23,8 @@
}
.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 {
@ -43,7 +54,7 @@
.vcd-screen-picker-preview img {
width: 100%;
height: 100%;
margin-bottom: 0.5em;
}
.vcd-screen-picker-preview {
@ -51,8 +62,7 @@
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
width: 100%;
margin-bottom: 1em;
}
.vcd-screen-picker-radio input {

View file

@ -28,9 +28,9 @@ export const enum IpcEvents {
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",
ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART",
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART",
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART"
}