Add screenshare capabilities

This commit is contained in:
Vendicated 2023-04-15 23:40:23 +02:00
parent a12ba017bc
commit 37886808a6
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
7 changed files with 158 additions and 1 deletions

View file

@ -4,7 +4,7 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { app, dialog, ipcMain, session, shell } from "electron";
import { app, desktopCapturer, dialog, ipcMain, session, shell } from "electron";
import { existsSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises";
import { join } from "path";
@ -68,6 +68,8 @@ 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,6 +4,7 @@
* 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";
@ -29,5 +30,15 @@ export const VencordDesktopNative = {
},
win: {
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()
}));
}
}
};

View file

@ -5,6 +5,7 @@
*/
import "./fixes";
import "./screenshare";
console.log("read if cute :3");

View file

@ -0,0 +1,80 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import "./styles.css";
import { Common, Util } from "renderer/vencord";
const { Modals } = Util;
type Sources = Awaited<ReturnType<(typeof VencordDesktopNative)["capturer"]["getSources"]>>;
export function openScreenPicker(screens: Sources) {
return new Promise<string>((resolve, reject) => {
const key = Modals.openModal(props => (
<ModalComponent
screens={screens}
modalProps={props}
submit={resolve}
close={() => {
Modals.closeModal(key);
reject(new Error("Aborted"));
}}
/>
));
});
}
function ModalComponent({
screens,
modalProps,
submit,
close
}: {
screens: Sources;
modalProps: any;
submit: (id: string) => void;
close: () => void;
}) {
const [selected, setSelected] = Common.React.useState(screens[0]?.id);
return (
<Modals.ModalRoot {...modalProps}>
<Modals.ModalHeader>
<Common.Forms.FormTitle tag="h2">Screen Picker</Common.Forms.FormTitle>
<Modals.ModalCloseButton onClick={close} />
</Modals.ModalHeader>
<Modals.ModalContent>
<div className="vcd-screen-picker-grid">
{screens.map(({ id, name, url }) => (
<label key={id} className={selected === id ? "vcd-screen-picker-selected" : ""}>
<input type="radio" name="screen" value={id} onChange={() => setSelected(id)} />
<img src={url} alt="" />
<Common.Forms.Text variant="text-sm/normal">{name}</Common.Forms.Text>
</label>
))}
</div>
</Modals.ModalContent>
<Modals.ModalFooter>
<Common.Button
disabled={!selected}
onClick={() => {
submit(selected);
close();
}}
>
Go Live
</Common.Button>
<Common.Button color={Common.Button.Colors.TRANSPARENT} onClick={close}>
Cancel
</Common.Button>
</Modals.ModalFooter>
</Modals.ModalRoot>
);
}

View file

@ -0,0 +1,32 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { openScreenPicker } from "./ScreenPicker";
navigator.mediaDevices.getDisplayMedia = async options => {
const sources = await VencordDesktopNative.capturer.getSources({
types: ["window", "screen"],
thumbnailSize: {
width: 176,
height: 99
}
});
const id = await openScreenPicker(sources);
return navigator.mediaDevices.getUserMedia({
audio: {
mandatory: {
chromeMediaSource: "desktop"
}
},
video: {
mandatory: {
chromeMediaSource: "desktop",
chromeMediaSourceId: id
}
}
} as any);
};

View file

@ -0,0 +1,29 @@
.vcd-screen-picker-grid {
padding: 1em;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2em 1em;
}
.vcd-screen-picker-grid input {
appearance: none;
cursor: pointer;
}
.vcd-screen-picker-selected img {
outline: 2px solid var(--brand-experiment);
}
.vcd-screen-picker-grid label {
overflow: hidden;
padding: 4px 0px;
}
.vcd-screen-picker-grid div {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
text-align: center;
font-weight: 600;
margin-inline: 0.5em;
}

View file

@ -27,5 +27,7 @@ export const enum IpcEvents {
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
CAPTURER_GET_SOURCES = "VCD_CAPTURER_GET_SOURCES",
CLOSE = "VCD_CLOSE"
}