mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-08 22:23:02 -04:00
Add Some Philhk Plugins
This commit is contained in:
parent
41021fe666
commit
6164e729e2
94 changed files with 5489 additions and 7 deletions
|
@ -77,6 +77,7 @@
|
|||
"stylelint-config-standard": "^33.0.0",
|
||||
"tsx": "^3.12.7",
|
||||
"type-fest": "^3.9.0",
|
||||
"typed-emitter": "^2.1.0",
|
||||
"typescript": "^5.0.4",
|
||||
"zip-local": "^0.3.5",
|
||||
"zustand": "^3.7.2"
|
||||
|
|
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
|
@ -1,9 +1,5 @@
|
|||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
patchedDependencies:
|
||||
'@types/less@3.0.6':
|
||||
hash: krcufrsfhsuxuoj7hocqugs6zi
|
||||
|
@ -132,6 +128,9 @@ devDependencies:
|
|||
type-fest:
|
||||
specifier: ^3.9.0
|
||||
version: 3.9.0
|
||||
typed-emitter:
|
||||
specifier: ^2.1.0
|
||||
version: 2.1.0
|
||||
typescript:
|
||||
specifier: ^5.0.4
|
||||
version: 5.0.4
|
||||
|
@ -2594,6 +2593,14 @@ packages:
|
|||
queue-microtask: 1.2.3
|
||||
dev: true
|
||||
|
||||
/rxjs@7.8.1:
|
||||
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
dev: true
|
||||
|
@ -2889,6 +2896,11 @@ packages:
|
|||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||
dev: true
|
||||
|
||||
/tslib@2.6.2:
|
||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/tsutils@3.21.0(typescript@5.0.4):
|
||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -2942,6 +2954,12 @@ packages:
|
|||
engines: {node: '>=14.16'}
|
||||
dev: true
|
||||
|
||||
/typed-emitter@2.1.0:
|
||||
resolution: {integrity: sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==}
|
||||
optionalDependencies:
|
||||
rxjs: 7.8.1
|
||||
dev: true
|
||||
|
||||
/typescript@5.0.4:
|
||||
resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
|
||||
engines: {node: '>=12.20'}
|
||||
|
@ -3123,3 +3141,7 @@ packages:
|
|||
name: gifenc
|
||||
version: 1.0.3
|
||||
dev: false
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Switch } from "@components/Switch";
|
||||
import { ModalSize } from "@utils/modal";
|
||||
import { Card, Forms, Select, Slider, TextInput, useEffect, useState } from "@webpack/common";
|
||||
import { SelectOption } from "@webpack/types";
|
||||
|
||||
import {
|
||||
ProfilableStore,
|
||||
SettingsModal,
|
||||
SettingsModalCard,
|
||||
SettingsModalCardItem,
|
||||
SettingsModalCardRow,
|
||||
SettingsModalProfilesCard,
|
||||
validateNumberInput,
|
||||
validateTextInputNumber
|
||||
} from "../../philsPluginLibrary";
|
||||
import { Styles } from "../../philsPluginLibrary/styles";
|
||||
import { MicrophoneProfile, MicrophoneStore } from "../stores";
|
||||
|
||||
const simpleVoiceBitrates: readonly SelectOption[] = [
|
||||
{
|
||||
label: "Normal",
|
||||
value: 96
|
||||
},
|
||||
{
|
||||
label: "Medium-High",
|
||||
value: 160
|
||||
},
|
||||
{
|
||||
label: "High",
|
||||
value: 320
|
||||
},
|
||||
{
|
||||
label: "Very-High",
|
||||
value: 512
|
||||
}
|
||||
] as const;
|
||||
|
||||
export interface MicrophoneSettingsModalProps extends React.ComponentProps<typeof SettingsModal> {
|
||||
microphoneStore: ProfilableStore<MicrophoneStore, MicrophoneProfile>;
|
||||
showInfo?: boolean;
|
||||
}
|
||||
|
||||
export const MicrophoneSettingsModal = (props: MicrophoneSettingsModalProps) => {
|
||||
const { microphoneStore, showInfo } = props;
|
||||
|
||||
const {
|
||||
currentProfile,
|
||||
simpleMode,
|
||||
setSimpleMode,
|
||||
deleteProfile,
|
||||
duplicateProfile,
|
||||
getCurrentProfile,
|
||||
getDefaultProfiles,
|
||||
getProfile,
|
||||
getProfiles,
|
||||
isCurrentProfileADefaultProfile,
|
||||
profiles,
|
||||
saveProfile,
|
||||
setChannels,
|
||||
setChannelsEnabled,
|
||||
setCurrentProfile,
|
||||
setFreq,
|
||||
setFreqEnabled,
|
||||
setPacsize,
|
||||
setPacsizeEnabled,
|
||||
setRate,
|
||||
setRateEnabled,
|
||||
setVoiceBitrate,
|
||||
setVoiceBitrateEnabled
|
||||
} = microphoneStore.use();
|
||||
|
||||
const {
|
||||
name,
|
||||
channels,
|
||||
channelsEnabled,
|
||||
freq,
|
||||
freqEnabled,
|
||||
pacsize,
|
||||
pacsizeEnabled,
|
||||
rate,
|
||||
rateEnabled,
|
||||
voiceBitrate,
|
||||
voiceBitrateEnabled
|
||||
} = currentProfile;
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const [rateInput, setRateInput] = useState<string>(rate ? rate.toString() : "");
|
||||
const [freqInput, setFreqInput] = useState<string>(freq ? freq.toString() : "");
|
||||
const [pacsizeInput, setPacsizeInput] = useState<string>(pacsize ? pacsize.toString() : "");
|
||||
const [channelsInput, setChannelsInput] = useState<string>(channels ? channels.toString() : "");
|
||||
|
||||
useEffect(() => {
|
||||
setRateInput(rate ? rate.toString() : "");
|
||||
setFreqInput(freq ? freq.toString() : "");
|
||||
setPacsizeInput(pacsize ? pacsize.toString() : "");
|
||||
setChannelsInput(channels ? channels.toString() : "");
|
||||
}, [rate, freq, pacsize, channels]);
|
||||
|
||||
const simpleToggle =
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", gap: "0.6em" }}>
|
||||
<Forms.FormTitle style={{ margin: 0 }} tag="h5">Simple</Forms.FormTitle>
|
||||
<Switch checked={simpleMode ?? false} disabled={isSaving} onChange={checked => setSimpleMode(checked)} />
|
||||
</Flex>;
|
||||
|
||||
const settingsCardVoiceBitrateSimple =
|
||||
<SettingsModalCard
|
||||
title="Audio Bitrate"
|
||||
switchEnabled
|
||||
flex={0.8}
|
||||
switchProps={{
|
||||
checked: voiceBitrateEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setVoiceBitrateEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<Select
|
||||
isDisabled={!voiceBitrateEnabled || isSaving}
|
||||
options={simpleVoiceBitrates}
|
||||
select={(value: number) => setVoiceBitrate(value)}
|
||||
isSelected={(value: number) => value === voiceBitrate}
|
||||
serialize={() => ""} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardChannelsSimple =
|
||||
<SettingsModalCard
|
||||
title="Stereo"
|
||||
flex={0.2}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: (channelsEnabled && channels === 2) ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => void setChannelsEnabled(status) ?? setChannels(2)
|
||||
}}>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardVoiceBitrate =
|
||||
<SettingsModalCard
|
||||
title="Audio Bitrate"
|
||||
switchEnabled
|
||||
flex={0.4}
|
||||
switchProps={{
|
||||
checked: voiceBitrateEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setVoiceBitrateEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem title="Kb/s">
|
||||
<div style={{ paddingTop: "0.3em", paddingRight: "0.4em", paddingLeft: "0.4em", boxSizing: "border-box" }}>
|
||||
<Slider
|
||||
disabled={!voiceBitrateEnabled || isSaving}
|
||||
onValueChange={value => setVoiceBitrate(value)}
|
||||
initialValue={voiceBitrate || 8}
|
||||
minValue={8}
|
||||
maxValue={512}
|
||||
markers={[8, 96, 320, 512]}
|
||||
onValueRender={value => `${value.toFixed(0)}kb/s`} />
|
||||
</div>
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardRate =
|
||||
<SettingsModalCard
|
||||
title="Sample Rate"
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: rateEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setRateEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<TextInput
|
||||
disabled={!rateEnabled || isSaving}
|
||||
value={rateInput}
|
||||
onChange={value => validateTextInputNumber(value) && setRateInput(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setRate(result);
|
||||
setRateInput(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardFreq =
|
||||
<SettingsModalCard
|
||||
title="Sample Frequency"
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: freqEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setFreqEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<TextInput
|
||||
disabled={!freqEnabled || isSaving}
|
||||
value={freqInput}
|
||||
onChange={value => validateTextInputNumber(value) && setFreqInput(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setFreq(result);
|
||||
setFreqInput(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardPacsize =
|
||||
<SettingsModalCard
|
||||
title="Pac Size"
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: pacsizeEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setPacsizeEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<TextInput
|
||||
disabled={!pacsizeEnabled || isSaving}
|
||||
value={pacsizeInput}
|
||||
onChange={value => validateTextInputNumber(value) && setPacsizeInput(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setPacsize(result);
|
||||
setPacsizeInput(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardChannels =
|
||||
<SettingsModalCard
|
||||
title="Channels"
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: channelsEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setChannelsEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<TextInput
|
||||
disabled={!channelsEnabled || isSaving}
|
||||
value={channelsInput}
|
||||
onChange={value => validateTextInputNumber(value) && setChannelsInput(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setChannels(result);
|
||||
setChannelsInput(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardProfiles =
|
||||
<SettingsModalProfilesCard
|
||||
flex={0.6}
|
||||
onSaveStateChanged={state => setIsSaving(state)}
|
||||
profileableStore={microphoneStore} />;
|
||||
|
||||
const infoCard =
|
||||
<Card style={{ ...Styles.infoCard }}>
|
||||
<Forms.FormTitle tag="h5">Important</Forms.FormTitle>
|
||||
<Forms.FormText>
|
||||
To take full advantage of this plugin, please disable <span style={{ fontWeight: "bold" }}>Krisp</span> and <span style={{ fontWeight: "bold" }}>Echo Cancellation</span>, otherwise features like Stereo (Channels) will not work.
|
||||
</Forms.FormText>
|
||||
</Card>;
|
||||
|
||||
return (
|
||||
<SettingsModal
|
||||
size={simpleMode ? ModalSize.DYNAMIC : ModalSize.DYNAMIC}
|
||||
title="Microphone Settings"
|
||||
closeButtonName="Apply"
|
||||
footerContent={
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", marginLeft: "auto" }}>
|
||||
{simpleToggle}
|
||||
</Flex>
|
||||
}
|
||||
{...props}
|
||||
onDone={() => {
|
||||
props.onClose();
|
||||
props.onDone && props.onDone();
|
||||
}}
|
||||
>
|
||||
{simpleMode
|
||||
? <div style={{ width: "30em", display: "flex", flexDirection: "column", gap: "1em" }}>
|
||||
<SettingsModalCardRow>
|
||||
{settingsCardVoiceBitrateSimple}
|
||||
{settingsCardChannelsSimple}
|
||||
</SettingsModalCardRow>
|
||||
{showInfo &&
|
||||
<SettingsModalCardRow>
|
||||
{infoCard}
|
||||
</SettingsModalCardRow>
|
||||
}
|
||||
</div>
|
||||
: <div style={{ display: "flex", flexDirection: "column", width: "50em", gap: "1em", maxHeight: "30em" }}>
|
||||
<SettingsModalCardRow>
|
||||
{settingsCardFreq}
|
||||
{settingsCardRate}
|
||||
{settingsCardPacsize}
|
||||
{settingsCardChannels}
|
||||
</SettingsModalCardRow>
|
||||
<SettingsModalCardRow>
|
||||
{settingsCardVoiceBitrate}
|
||||
{settingsCardProfiles}
|
||||
</SettingsModalCardRow>
|
||||
{showInfo &&
|
||||
<SettingsModalCardRow>
|
||||
{infoCard}
|
||||
</SettingsModalCardRow>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</SettingsModal>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./MicrophoneSettingsModal";
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
|
||||
import { types } from "../../philsPluginLibrary";
|
||||
|
||||
export const PluginInfo = {
|
||||
PLUGIN_NAME: "BetterMicrophone",
|
||||
DESCRIPTION: "This plugin allows you to further customize your microphone.",
|
||||
AUTHOR: {
|
||||
...Devs.philhk,
|
||||
github: "https://github.com/philhk"
|
||||
},
|
||||
CONTRIBUTORS: {}
|
||||
} as const satisfies types.PluginInfo;
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./constants";
|
57
src/equicordplugins/betterMicrophone.desktop/index.tsx
Normal file
57
src/equicordplugins/betterMicrophone.desktop/index.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { PluginAuthor, PluginDef } from "@utils/types";
|
||||
|
||||
import { addSettingsPanelButton, Emitter, MicrophoneSettingsIcon, removeSettingsPanelButton } from "../philsPluginLibrary";
|
||||
import { PluginInfo } from "./constants";
|
||||
import { openMicrophoneSettingsModal } from "./modals";
|
||||
import { MicrophonePatcher } from "./patchers";
|
||||
import { initMicrophoneStore } from "./stores";
|
||||
|
||||
export default new class Plugin implements PluginDef {
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly authors: PluginAuthor[];
|
||||
readonly dependencies: string[];
|
||||
|
||||
public microphonePatcher?: MicrophonePatcher;
|
||||
|
||||
constructor() {
|
||||
this.name = PluginInfo.PLUGIN_NAME;
|
||||
this.description = PluginInfo.DESCRIPTION;
|
||||
this.authors = [PluginInfo.AUTHOR, ...Object.values(PluginInfo.CONTRIBUTORS)] as PluginAuthor[];
|
||||
this.dependencies = ["PhilsPluginLibrary"];
|
||||
}
|
||||
|
||||
start(): void {
|
||||
initMicrophoneStore();
|
||||
|
||||
this.microphonePatcher = new MicrophonePatcher().patch();
|
||||
|
||||
addSettingsPanelButton({ name: PluginInfo.PLUGIN_NAME, icon: MicrophoneSettingsIcon, tooltipText: "Microphone Settings", onClick: openMicrophoneSettingsModal });
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
this.microphonePatcher?.unpatch();
|
||||
|
||||
Emitter.removeAllListeners(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
removeSettingsPanelButton(PluginInfo.PLUGIN_NAME);
|
||||
}
|
||||
};
|
23
src/equicordplugins/betterMicrophone.desktop/logger/index.ts
Normal file
23
src/equicordplugins/betterMicrophone.desktop/logger/index.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
||||
import { PluginInfo } from "../constants";
|
||||
|
||||
export const logger = new Logger(PluginInfo.PLUGIN_NAME);
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { openModalLazy } from "@utils/modal";
|
||||
|
||||
import { MicrophoneSettingsModal } from "../components";
|
||||
import { PluginInfo } from "../constants";
|
||||
import Plugin from "../index";
|
||||
import { microphoneStore } from "../stores";
|
||||
|
||||
const onMicrophoneModalDone = () => {
|
||||
const { microphonePatcher } = Plugin;
|
||||
|
||||
if (microphonePatcher)
|
||||
microphonePatcher.forceUpdateTransportationOptions();
|
||||
};
|
||||
|
||||
export const openMicrophoneSettingsModal =
|
||||
() => openModalLazy(async () => {
|
||||
return props =>
|
||||
<MicrophoneSettingsModal
|
||||
onDone={onMicrophoneModalDone}
|
||||
showInfo
|
||||
microphoneStore={microphoneStore}
|
||||
author={PluginInfo.AUTHOR}
|
||||
contributors={Object.values(PluginInfo.CONTRIBUTORS)}
|
||||
{...props} />;
|
||||
});
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./microphone";
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Emitter, MediaEngineStore, Patcher, types } from "../../philsPluginLibrary";
|
||||
import { patchConnectionAudioTransportOptions } from "../../philsPluginLibrary/patches/audio";
|
||||
import { PluginInfo } from "../constants";
|
||||
import { logger } from "../logger";
|
||||
import { microphoneStore } from "../stores";
|
||||
|
||||
export class MicrophonePatcher extends Patcher {
|
||||
private mediaEngineStore: types.MediaEngineStore;
|
||||
private mediaEngine: types.MediaEngine;
|
||||
public connection?: types.Connection;
|
||||
public oldSetTransportOptions: (...args: any[]) => void;
|
||||
public forceUpdateTransportationOptions: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.mediaEngineStore = MediaEngineStore;
|
||||
this.mediaEngine = this.mediaEngineStore.getMediaEngine();
|
||||
this.oldSetTransportOptions = () => void 0;
|
||||
this.forceUpdateTransportationOptions = () => void 0;
|
||||
}
|
||||
|
||||
public patch(): this {
|
||||
this.unpatch();
|
||||
|
||||
const { get } = microphoneStore;
|
||||
|
||||
const connectionEventFunction =
|
||||
(connection: types.Connection) => {
|
||||
if (connection.context !== "default") return;
|
||||
|
||||
this.connection = connection;
|
||||
|
||||
const { oldSetTransportOptions, forceUpdateTransportationOptions } = patchConnectionAudioTransportOptions(connection, get, logger);
|
||||
|
||||
this.oldSetTransportOptions = oldSetTransportOptions;
|
||||
this.forceUpdateTransportationOptions = forceUpdateTransportationOptions;
|
||||
};
|
||||
|
||||
Emitter.addListener(
|
||||
this.mediaEngine.emitter,
|
||||
"on",
|
||||
"connection",
|
||||
connectionEventFunction,
|
||||
PluginInfo.PLUGIN_NAME
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unpatch(): this {
|
||||
return this._unpatch();
|
||||
}
|
||||
}
|
19
src/equicordplugins/betterMicrophone.desktop/stores/index.ts
Normal file
19
src/equicordplugins/betterMicrophone.desktop/stores/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./microphoneStore";
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { createPluginStore, ProfilableInitializer, ProfilableStore, profileable, ProfileableProfile } from "../../philsPluginLibrary";
|
||||
import { PluginInfo } from "../constants";
|
||||
|
||||
|
||||
export interface MicrophoneProfile {
|
||||
freq?: number,
|
||||
pacsize?: number,
|
||||
channels?: number,
|
||||
rate?: number,
|
||||
voiceBitrate?: number;
|
||||
freqEnabled?: boolean,
|
||||
pacsizeEnabled?: boolean;
|
||||
channelsEnabled?: boolean;
|
||||
rateEnabled?: boolean;
|
||||
voiceBitrateEnabled?: boolean;
|
||||
}
|
||||
|
||||
export interface MicrophoneStore {
|
||||
simpleMode?: boolean;
|
||||
setSimpleMode: (enabled?: boolean) => void;
|
||||
setFreq: (freq?: number) => void;
|
||||
setPacsize: (pacsize?: number) => void;
|
||||
setChannels: (channels?: number) => void;
|
||||
setRate: (rate?: number) => void;
|
||||
setVoiceBitrate: (voiceBitrate?: number) => void;
|
||||
setFreqEnabled: (enabled?: boolean) => void;
|
||||
setPacsizeEnabled: (enabled?: boolean) => void;
|
||||
setChannelsEnabled: (enabled?: boolean) => void;
|
||||
setRateEnabled: (enabled?: boolean) => void;
|
||||
setVoiceBitrateEnabled: (enabled?: boolean) => void;
|
||||
}
|
||||
|
||||
export const defaultMicrophoneProfiles = {
|
||||
normal: {
|
||||
name: "Normal",
|
||||
channels: 2,
|
||||
channelsEnabled: true,
|
||||
voiceBitrate: 96,
|
||||
voiceBitrateEnabled: true
|
||||
},
|
||||
high: {
|
||||
name: "High",
|
||||
channels: 2,
|
||||
channelsEnabled: true,
|
||||
voiceBitrate: 320,
|
||||
voiceBitrateEnabled: true
|
||||
},
|
||||
} as const satisfies Record<string, MicrophoneProfile & ProfileableProfile>;
|
||||
|
||||
export const microphoneStoreDefault: ProfilableInitializer<MicrophoneStore, MicrophoneProfile> = (set, get) => ({
|
||||
simpleMode: true,
|
||||
setSimpleMode: enabled => get().simpleMode = enabled,
|
||||
setChannels: channels => get().currentProfile.channels = channels,
|
||||
setRate: rate => get().currentProfile.rate = rate,
|
||||
setVoiceBitrate: voiceBitrate => get().currentProfile.voiceBitrate = voiceBitrate,
|
||||
setPacsize: pacsize => get().currentProfile.pacsize = pacsize,
|
||||
setFreq: freq => get().currentProfile.freq = freq,
|
||||
setChannelsEnabled: enabled => get().currentProfile.channelsEnabled = enabled,
|
||||
setFreqEnabled: enabled => get().currentProfile.freqEnabled = enabled,
|
||||
setPacsizeEnabled: enabled => get().currentProfile.pacsizeEnabled = enabled,
|
||||
setRateEnabled: enabled => get().currentProfile.rateEnabled = enabled,
|
||||
setVoiceBitrateEnabled: enabled => get().currentProfile.voiceBitrateEnabled = enabled,
|
||||
});
|
||||
|
||||
export let microphoneStore: ProfilableStore<MicrophoneStore, MicrophoneProfile>;
|
||||
|
||||
export const initMicrophoneStore = () =>
|
||||
microphoneStore = createPluginStore(
|
||||
PluginInfo.PLUGIN_NAME,
|
||||
"MicrophoneStore",
|
||||
profileable(
|
||||
microphoneStoreDefault,
|
||||
{ name: "" },
|
||||
Object.values(defaultMicrophoneProfiles)
|
||||
)
|
||||
);
|
30
src/equicordplugins/betterScreenshare.desktop/README.md
Normal file
30
src/equicordplugins/betterScreenshare.desktop/README.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Better Screenshare Plugin
|
||||
|
||||
## How to use each Setting?
|
||||
|
||||
- **Audio Source** - Choose a window from the drop-down list and the audio will be shared whether you're streaming a window or a screen.
|
||||
- **Resolution** - Here you can set the width and the height (both are required). The ideal resolution is the resolution of the monitor you are streaming. An example would be `1080p` (height: `1920` width: `1080`).
|
||||
- **Framerate** - Here you can set the frame rate. The most common frame rate is `60`, but you can set it higher or lower if you like.
|
||||
- **Keyframe Interval** - Here you can set the keyframe interval in milliseconds. If you don't know anything about it, just leave it disabled, but if you want to understand it better, read through this [article](https://filmora.wondershare.com/video-editing/keyframe-interval-obs.html).
|
||||
- **Video Bitrate** - This is one of the most important settings as it affects the quality the most. Discord uses a low bitrate by default, so it's important to set it if you want good quality. If you want to find out your optimal bitrate, go to the video bitrate [section](https://github.com/Vendicated/Vencord/tree/main/src/plugins/betterScreenshare#video-bitrate).
|
||||
- **Audio Bitrate** - This is almost the same as video bitrate, but it works a little differently for audio. If you want to learn more about it, you can read through this [article](https://www.adobe.com/creativecloud/video/discover/audio-bitrate.html). But I would recommend setting it between `96kb/s` and `320kb/s` (higher means better).
|
||||
- **Video Codec** - Here you can set your video codec. Discord currently supports 4 codecs. Each codec offers different quality and performance. The most popular codec is **H264**, which I recommend. However, if you have a 40 series card, use the **AV1** codec.
|
||||
- **AV1** - Only supported on 40-series cards.
|
||||
- **VP8**
|
||||
- **VP9**
|
||||
- **H264**
|
||||
- **HDR** - Allows streaming in HDR.
|
||||
|
||||
## Bitrate
|
||||
|
||||
To find your optimal bitrate, you must first find your upload speed. You can do this by running a speed test on this [website](https://www.speedtest.net/). When you're done, you'll see a number in the upload field that represents your maximum upload speed in (`Mbps`) `Mb/s`. To use the upload you need to convert it from `Mb/s` to `Kb/s` by multiplying it by `1000`. I'd recommend going a bit lower as you probably won't always hit your max upload speed and it will affect your ping. Heres is a example `5000 Kb/s` -> `4000 Kb/s`.
|
||||
|
||||
**IMPORTANT**: Discord added a cap of `10000 Kb/s`, if you went higher everyone would experience packet loss. It is not known if there is a bypass for this.
|
||||
|
||||
## Presets
|
||||
|
||||
If you don't want to do any of the above, you can just try the presets in the Profile Options tab and see what works best for you. And if you want to change a setting in the preset, you can simply copy it and save it as a new one.
|
||||
|
||||
## Known Issues
|
||||
|
||||
~~When sharing a window directly it can sometimes happen that no changes are applied, the reason for this is currently unknown, but to avoid this you can simply share your whole screen and set the audio source if required.~~
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Select, useEffect, useState } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { MediaEngineStore, types } from "../../philsPluginLibrary";
|
||||
import { screenshareStore } from "../stores";
|
||||
|
||||
export const AudioSourceSelect = (props?: typeof Select["defaultProps"]) => {
|
||||
const { use } = screenshareStore;
|
||||
|
||||
const { audioSource, setAudioSource } = use();
|
||||
|
||||
const [windowPreviews, setWindowPreviews] = useState<types.WindowPreview[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const intervalFn = async () => {
|
||||
const newPreviews = await MediaEngineStore.getMediaEngine().getWindowPreviews(1, 1);
|
||||
setWindowPreviews(oldPreviews => [...oldPreviews, ...newPreviews].filter((preview, index, array) => array.findIndex(t => t.id === preview.id) === index));
|
||||
};
|
||||
intervalFn();
|
||||
|
||||
const intervals = [
|
||||
setInterval(async () => {
|
||||
intervalFn();
|
||||
}, 4000), setInterval(async () => {
|
||||
setWindowPreviews(await MediaEngineStore.getMediaEngine().getWindowPreviews(1, 1));
|
||||
}, 30000)
|
||||
];
|
||||
|
||||
return () => intervals.forEach(interval => clearInterval(interval));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Select
|
||||
options={windowPreviews.map(({ name, id }) => ({
|
||||
label: name,
|
||||
value: id
|
||||
}))}
|
||||
isSelected={value => audioSource === value}
|
||||
select={value => setAudioSource(value)}
|
||||
serialize={() => ""}
|
||||
{...props}
|
||||
></Select>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Button } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { openScreenshareModal } from "../modals";
|
||||
|
||||
export interface OpenScreenshareSettingsButtonProps {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const OpenScreenshareSettingsButton = (props: OpenScreenshareSettingsButtonProps) => {
|
||||
return (
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
color={Button.Colors.PRIMARY}
|
||||
onClick={openScreenshareModal}
|
||||
>
|
||||
{props.title ? props.title : "Screenshare Settings"}
|
||||
</Button>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Switch } from "@components/Switch";
|
||||
import { ModalSize, openModalLazy } from "@utils/modal";
|
||||
import { Button, Card, Forms, React, Select, Slider, TextInput, useEffect, useState } from "@webpack/common";
|
||||
import { SelectOption } from "@webpack/types";
|
||||
|
||||
import { MicrophoneSettingsModal } from "../../betterMicrophone.desktop/components";
|
||||
import {
|
||||
MediaEngineStore,
|
||||
openURL,
|
||||
ProfilableStore,
|
||||
SettingsModal,
|
||||
SettingsModalCard,
|
||||
SettingsModalCardItem,
|
||||
SettingsModalCardRow,
|
||||
SettingsModalProfilesCard,
|
||||
types,
|
||||
validateNumberInput,
|
||||
validateTextInputNumber
|
||||
} from "../../philsPluginLibrary";
|
||||
import { Styles } from "../../philsPluginLibrary/styles";
|
||||
import { PluginInfo } from "../constants";
|
||||
import { ScreenshareAudioProfile, ScreenshareAudioStore, ScreenshareProfile, ScreenshareStore } from "../stores";
|
||||
|
||||
const simpleResolutions: readonly (SelectOption & { value: types.Resolution; })[] = [
|
||||
{
|
||||
label: "480p",
|
||||
value: {
|
||||
height: 480,
|
||||
width: 720
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "720p",
|
||||
value: {
|
||||
height: 720,
|
||||
width: 1280
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "1080p",
|
||||
value: {
|
||||
height: 1080,
|
||||
width: 1920
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "1440p",
|
||||
value: {
|
||||
height: 1440,
|
||||
width: 2560
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "2160p",
|
||||
value: {
|
||||
height: 2160,
|
||||
width: 3840
|
||||
}
|
||||
}
|
||||
] as const;
|
||||
|
||||
const simpleVideoBitrates: readonly SelectOption[] = [
|
||||
{
|
||||
label: "Low",
|
||||
value: 2500
|
||||
},
|
||||
{
|
||||
label: "Medium",
|
||||
value: 5000
|
||||
},
|
||||
{
|
||||
label: "Medium-High",
|
||||
value: 7500
|
||||
},
|
||||
{
|
||||
label: "High",
|
||||
value: 10000
|
||||
}
|
||||
] as const;
|
||||
|
||||
export interface ScreenshareSettingsModalProps extends React.ComponentProps<typeof SettingsModal> {
|
||||
screenshareStore: ProfilableStore<ScreenshareStore, ScreenshareProfile>;
|
||||
screenshareAudioStore?: ProfilableStore<ScreenshareAudioStore, ScreenshareAudioProfile>;
|
||||
onAudioDone?: () => void;
|
||||
}
|
||||
|
||||
export const ScreenshareSettingsModal = (props: ScreenshareSettingsModalProps) => {
|
||||
const { screenshareStore, screenshareAudioStore, onAudioDone } = props;
|
||||
|
||||
const {
|
||||
currentProfile,
|
||||
profiles,
|
||||
simpleMode,
|
||||
setVideoBitrateEnabled,
|
||||
setVideoCodec,
|
||||
setVideoCodecEnabled,
|
||||
setFramerate,
|
||||
setFramerateEnabled,
|
||||
setHeight,
|
||||
setKeyframeInterval,
|
||||
setKeyframeIntervalEnabled,
|
||||
setResolutionEnabled,
|
||||
setVideoBitrate,
|
||||
setWidth,
|
||||
setCurrentProfile,
|
||||
getProfile,
|
||||
saveProfile,
|
||||
setHdrEnabled,
|
||||
setSimpleMode,
|
||||
deleteProfile,
|
||||
duplicateProfile,
|
||||
getCurrentProfile,
|
||||
getProfiles
|
||||
} = screenshareStore.use();
|
||||
|
||||
|
||||
const {
|
||||
name,
|
||||
framerate,
|
||||
framerateEnabled,
|
||||
height,
|
||||
keyframeInterval,
|
||||
keyframeIntervalEnabled,
|
||||
resolutionEnabled,
|
||||
videoBitrate,
|
||||
videoBitrateEnabled,
|
||||
videoCodec,
|
||||
videoCodecEnabled,
|
||||
width,
|
||||
hdrEnabled
|
||||
} = currentProfile;
|
||||
|
||||
const [videoCodecs, setVideoCodecs] = useState<types.CodecCapabilities[]>([]);
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const [textinputWidth, setTextinputWidth] = useState<string>(width ? width.toString() : "");
|
||||
const [textinputHeight, setTextinputHeight] = useState<string>(height ? height.toString() : "");
|
||||
const [textinputFramerate, setTextinputFramerate] = useState<string>(framerate ? framerate.toString() : "");
|
||||
const [textinputKeyframeInterval, setTextinputKeyframeInterval] = useState<string>(keyframeInterval ? keyframeInterval.toString() : "");
|
||||
|
||||
useEffect(() => {
|
||||
setTextinputWidth(width ? width.toString() : "");
|
||||
setTextinputHeight(height ? height.toString() : "");
|
||||
setTextinputFramerate(framerate ? framerate.toString() : "");
|
||||
setTextinputKeyframeInterval(keyframeInterval ? keyframeInterval.toString() : "");
|
||||
}, [width, height, framerate, keyframeInterval]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const mediaEngine = MediaEngineStore.getMediaEngine();
|
||||
|
||||
const stringifiedCodecs: types.CodecCapabilities[] = JSON.parse(
|
||||
await new Promise(res => mediaEngine.getCodecCapabilities(res))
|
||||
);
|
||||
|
||||
setVideoCodecs(stringifiedCodecs);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const settingsCardResolutionSimple =
|
||||
<SettingsModalCard
|
||||
title="Resolution"
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: resolutionEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setResolutionEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<Select
|
||||
isDisabled={!resolutionEnabled || isSaving}
|
||||
options={simpleResolutions}
|
||||
select={(value: types.Resolution) => void setWidth(value.width) ?? setHeight(value.height)}
|
||||
isSelected={(value: types.Resolution) => width === value.width && height === value.height}
|
||||
serialize={() => ""} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardVideoBitrateSimple =
|
||||
<SettingsModalCard
|
||||
title="Video Bitrate"
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: videoBitrateEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setVideoBitrateEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<Select
|
||||
isDisabled={!videoBitrateEnabled || isSaving}
|
||||
options={simpleVideoBitrates}
|
||||
select={(value: number) => void setVideoBitrate(value)}
|
||||
isSelected={(value: number) => videoBitrate === value}
|
||||
serialize={() => ""} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardResolution =
|
||||
<SettingsModalCard
|
||||
title="Resolution"
|
||||
flex={0.5}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: resolutionEnabled ?? false,
|
||||
onChange: status => setResolutionEnabled(status),
|
||||
disabled: isSaving
|
||||
}}>
|
||||
<SettingsModalCardItem title="Width">
|
||||
<TextInput
|
||||
disabled={!resolutionEnabled || isSaving}
|
||||
value={textinputWidth}
|
||||
onChange={value => validateTextInputNumber(value) && setTextinputWidth(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setWidth(result);
|
||||
setTextinputWidth(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
<SettingsModalCardItem title="Height">
|
||||
<TextInput
|
||||
disabled={!resolutionEnabled || isSaving}
|
||||
value={textinputHeight}
|
||||
onChange={value => validateTextInputNumber(value) && setTextinputHeight(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setHeight(result);
|
||||
setTextinputHeight(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardItemFramerate =
|
||||
<SettingsModalCardItem>
|
||||
<TextInput
|
||||
disabled={!framerateEnabled || isSaving}
|
||||
value={textinputFramerate}
|
||||
onChange={value => validateTextInputNumber(value) && setTextinputFramerate(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setFramerate(result);
|
||||
setTextinputFramerate(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>;
|
||||
|
||||
const settingsCardFramerateProps: React.ComponentProps<typeof SettingsModalCard> = {
|
||||
title: "Framerate",
|
||||
switchEnabled: true,
|
||||
switchProps: {
|
||||
checked: framerateEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setFramerateEnabled(status)
|
||||
}
|
||||
};
|
||||
|
||||
const settingsCardFramerate =
|
||||
<SettingsModalCard
|
||||
{...settingsCardFramerateProps}
|
||||
flex={0.25}
|
||||
>
|
||||
{settingsCardItemFramerate}
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardFramerateSimple =
|
||||
<SettingsModalCard
|
||||
{...settingsCardFramerateProps}
|
||||
>
|
||||
{settingsCardItemFramerate}
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardKeyframeInterval =
|
||||
<SettingsModalCard
|
||||
title="Keyframe Interval (ms)"
|
||||
flex={0.25}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: keyframeIntervalEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setKeyframeIntervalEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<TextInput
|
||||
disabled={!keyframeIntervalEnabled || isSaving}
|
||||
value={textinputKeyframeInterval}
|
||||
onChange={value => validateTextInputNumber(value) && setTextinputKeyframeInterval(value)}
|
||||
onBlur={e => {
|
||||
const result = validateNumberInput(e.target.value);
|
||||
setKeyframeInterval(result);
|
||||
setTextinputKeyframeInterval(result ? result.toString() : "");
|
||||
}} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardVideoBitrate =
|
||||
<SettingsModalCard
|
||||
title="Video Bitrate"
|
||||
flex={0.4}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: videoBitrateEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setVideoBitrateEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem title="Kb/s">
|
||||
<div style={{ paddingTop: "0.3em", paddingRight: "0.4em", paddingLeft: "0.4em", boxSizing: "border-box" }}>
|
||||
<Slider
|
||||
disabled={!videoBitrateEnabled || isSaving}
|
||||
onValueChange={value => setVideoBitrate(value)}
|
||||
initialValue={videoBitrate || 500}
|
||||
minValue={500}
|
||||
maxValue={10000}
|
||||
markers={[500, 10000]}
|
||||
onValueRender={value => `${value.toFixed(0)}kb/s`} />
|
||||
</div>
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardAudioProps: React.ComponentProps<typeof SettingsModalCard> = {
|
||||
title: "Audio Settings"
|
||||
};
|
||||
|
||||
const settingsCardItemAudio =
|
||||
<SettingsModalCardItem >
|
||||
<Button
|
||||
color={Button.Colors.PRIMARY}
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={() => {
|
||||
if (screenshareAudioStore)
|
||||
openModalLazy(async () => {
|
||||
return props_ =>
|
||||
<MicrophoneSettingsModal
|
||||
author={props.author}
|
||||
contributors={props.contributors}
|
||||
title="Screenshare Audio Settings"
|
||||
onDone={onAudioDone}
|
||||
microphoneStore={screenshareAudioStore}
|
||||
{...props_} />;
|
||||
});
|
||||
}}
|
||||
children={"Open"} />
|
||||
</SettingsModalCardItem>;
|
||||
|
||||
const settingsCardAudio =
|
||||
<SettingsModalCard
|
||||
{...settingsCardAudioProps}
|
||||
flex={0.2}>
|
||||
{settingsCardItemAudio}
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardAudioSimple =
|
||||
<SettingsModalCard
|
||||
{...settingsCardAudioProps}>
|
||||
{settingsCardItemAudio}
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardVideoCodec =
|
||||
<SettingsModalCard
|
||||
title="Video Codec"
|
||||
flex={0.4}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: videoCodecEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setVideoCodecEnabled(status)
|
||||
}}>
|
||||
<SettingsModalCardItem>
|
||||
<Select
|
||||
isDisabled={!videoCodecEnabled || isSaving}
|
||||
isSelected={value => value === videoCodec}
|
||||
options={videoCodecs.map(codecCapabilities => ({ label: codecCapabilities.codec, value: codecCapabilities.codec }))}
|
||||
select={value => setVideoCodec(value)}
|
||||
serialize={() => ""} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>;
|
||||
|
||||
const settingsCardHdr =
|
||||
<SettingsModalCard
|
||||
title="Hdr"
|
||||
flex={0.1}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: hdrEnabled ?? false,
|
||||
disabled: isSaving,
|
||||
onChange: status => setHdrEnabled(status)
|
||||
}} />;
|
||||
|
||||
const guideCard =
|
||||
<Card style={{ ...Styles.infoCard, flex: 0.4 }}>
|
||||
<Forms.FormTitle tag="h5">How to use?</Forms.FormTitle>
|
||||
<Forms.FormText>If you want to know more about the settings or possible issues, please read <a onClick={() => openURL(PluginInfo.README + "#better-screenshare-plugin")}>this</a>.</Forms.FormText>
|
||||
</Card>;
|
||||
|
||||
const settingsCardProfiles =
|
||||
<SettingsModalProfilesCard flex={0.5} onSaveStateChanged={state => setIsSaving(state)} profileableStore={screenshareStore} />;
|
||||
|
||||
const simpleToggle =
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", gap: "0.6em" }}>
|
||||
<Forms.FormTitle style={{ margin: 0 }} tag="h5">Simple</Forms.FormTitle>
|
||||
<Switch checked={simpleMode ?? false} disabled={isSaving} onChange={checked => setSimpleMode(checked)} />
|
||||
</Flex>;
|
||||
|
||||
|
||||
return (
|
||||
<SettingsModal
|
||||
size={simpleMode ? ModalSize.DYNAMIC : ModalSize.LARGE}
|
||||
title="Screenshare Settings"
|
||||
closeButtonName="Apply"
|
||||
footerContent={
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", marginLeft: "auto" }}>
|
||||
{simpleToggle}
|
||||
</Flex>
|
||||
}
|
||||
{...props}
|
||||
onDone={() => {
|
||||
props.onClose();
|
||||
props.onDone && props.onDone();
|
||||
}}
|
||||
>
|
||||
{simpleMode
|
||||
? <div style={{ width: "55em" }}>
|
||||
<SettingsModalCardRow>
|
||||
{settingsCardResolutionSimple}
|
||||
{settingsCardFramerateSimple}
|
||||
{settingsCardVideoBitrateSimple}
|
||||
{screenshareAudioStore && settingsCardAudioSimple}
|
||||
</SettingsModalCardRow>
|
||||
</div>
|
||||
: <>
|
||||
<SettingsModalCardRow>
|
||||
{settingsCardResolution}
|
||||
{settingsCardFramerate}
|
||||
{settingsCardKeyframeInterval}
|
||||
</SettingsModalCardRow>
|
||||
<SettingsModalCardRow>
|
||||
{settingsCardVideoBitrate}
|
||||
{settingsCardVideoCodec}
|
||||
{screenshareAudioStore && settingsCardAudio}
|
||||
</SettingsModalCardRow>
|
||||
<SettingsModalCardRow>
|
||||
{guideCard}
|
||||
{settingsCardHdr}
|
||||
{settingsCardProfiles}
|
||||
</SettingsModalCardRow>
|
||||
</>
|
||||
}
|
||||
</SettingsModal>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./AudioSourceSelect";
|
||||
export * from "./OpenScreenshareSettingsButton";
|
||||
export * from "./ScreenshareSettingsModal";
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
|
||||
import { types } from "../../philsPluginLibrary";
|
||||
|
||||
export const PluginInfo = {
|
||||
PLUGIN_NAME: "BetterScreenshare",
|
||||
DESCRIPTION: "This plugin allows you to further customize your screen sharing.",
|
||||
AUTHOR: {
|
||||
...Devs.philhk,
|
||||
github: "https://github.com/philhk"
|
||||
},
|
||||
CONTRIBUTORS: {
|
||||
walrus: {
|
||||
github: "https://github.com/philhk",
|
||||
id: 305317288775778306n,
|
||||
name: "walrus"
|
||||
},
|
||||
},
|
||||
README: "https://github.com/Vendicated/Vencord/tree/main/src/plugins/betterScreenshare"
|
||||
} as const satisfies types.PluginInfo;
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./constants";
|
86
src/equicordplugins/betterScreenshare.desktop/index.tsx
Normal file
86
src/equicordplugins/betterScreenshare.desktop/index.tsx
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { DefinedSettings, OptionType, Patch, PluginAuthor, PluginDef, SettingsDefinition } from "@utils/types";
|
||||
|
||||
import { addSettingsPanelButton, Emitter, removeSettingsPanelButton, ScreenshareSettingsIcon } from "../philsPluginLibrary";
|
||||
import { PluginInfo } from "./constants";
|
||||
import { openScreenshareModal } from "./modals";
|
||||
import { ScreenshareAudioPatcher, ScreensharePatcher } from "./patchers";
|
||||
import { replacedScreenshareModalComponent } from "./patches";
|
||||
import { initScreenshareAudioStore, initScreenshareStore } from "./stores";
|
||||
|
||||
export default new class Plugin implements PluginDef {
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly authors: PluginAuthor[];
|
||||
readonly patches: Omit<Patch, "plugin">[];
|
||||
readonly settings: DefinedSettings<SettingsDefinition, {}>;
|
||||
readonly dependencies: string[];
|
||||
|
||||
private readonly replacedScreenshareModalComponent: typeof replacedScreenshareModalComponent;
|
||||
public screensharePatcher?: ScreensharePatcher;
|
||||
public screenshareAudioPatcher?: ScreenshareAudioPatcher;
|
||||
|
||||
constructor() {
|
||||
this.name = PluginInfo.PLUGIN_NAME;
|
||||
this.description = PluginInfo.DESCRIPTION;
|
||||
this.authors = [PluginInfo.AUTHOR, ...Object.values(PluginInfo.CONTRIBUTORS)] as PluginAuthor[];
|
||||
this.patches = [
|
||||
{
|
||||
find: "Messages.SCREENSHARE_RELAUNCH",
|
||||
replacement: {
|
||||
match: /(function .{1,2}\(.{1,2}\){)(.{1,40}(?=selectGuild).+?(?:]}\)}\)))(})/,
|
||||
replace: "$1return $self.replacedScreenshareModalComponent(function(){$2}, this, arguments)$3"
|
||||
}
|
||||
}
|
||||
];
|
||||
this.settings = definePluginSettings({
|
||||
hideDefaultSettings: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Hide Discord screen sharing settings",
|
||||
default: true,
|
||||
}
|
||||
});
|
||||
this.dependencies = ["PhilsPluginLibrary"];
|
||||
this.replacedScreenshareModalComponent = replacedScreenshareModalComponent;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
initScreenshareStore();
|
||||
initScreenshareAudioStore();
|
||||
this.screensharePatcher = new ScreensharePatcher().patch();
|
||||
this.screenshareAudioPatcher = new ScreenshareAudioPatcher().patch();
|
||||
|
||||
addSettingsPanelButton({
|
||||
name: PluginInfo.PLUGIN_NAME,
|
||||
icon: ScreenshareSettingsIcon,
|
||||
tooltipText: "Screenshare Settings",
|
||||
onClick: openScreenshareModal
|
||||
});
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
this.screensharePatcher?.unpatch();
|
||||
this.screenshareAudioPatcher?.unpatch();
|
||||
Emitter.removeAllListeners(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
removeSettingsPanelButton(PluginInfo.PLUGIN_NAME);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
||||
import { PluginInfo } from "../constants";
|
||||
|
||||
export const logger = new Logger(PluginInfo.PLUGIN_NAME);
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { openModalLazy } from "@utils/modal";
|
||||
|
||||
import Plugin from "..";
|
||||
import { ScreenshareSettingsModal } from "../components";
|
||||
import { PluginInfo } from "../constants";
|
||||
import { screenshareAudioStore, screenshareStore } from "../stores";
|
||||
|
||||
const onScreenshareModalDone = () => {
|
||||
const { screenshareAudioPatcher, screensharePatcher } = Plugin;
|
||||
|
||||
if (screensharePatcher) {
|
||||
screensharePatcher.forceUpdateTransportationOptions();
|
||||
screensharePatcher.forceUpdateDesktopSourceOptions();
|
||||
}
|
||||
if (screenshareAudioPatcher)
|
||||
screenshareAudioPatcher.forceUpdateTransportationOptions();
|
||||
};
|
||||
|
||||
const onScreenshareAudioModalDone = () => {
|
||||
const { screenshareAudioPatcher } = Plugin;
|
||||
|
||||
if (screenshareAudioPatcher)
|
||||
screenshareAudioPatcher.forceUpdateTransportationOptions();
|
||||
};
|
||||
|
||||
export const openScreenshareModal =
|
||||
() => openModalLazy(async () => {
|
||||
return props =>
|
||||
<ScreenshareSettingsModal
|
||||
onAudioDone={onScreenshareAudioModalDone}
|
||||
onDone={onScreenshareModalDone}
|
||||
screenshareStore={screenshareStore}
|
||||
screenshareAudioStore={screenshareAudioStore}
|
||||
author={PluginInfo.AUTHOR}
|
||||
contributors={Object.values(PluginInfo.CONTRIBUTORS)}
|
||||
{...props} />;
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./screenshare";
|
||||
export * from "./screenshareAudio";
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
import { Emitter, MediaEngineStore, Patcher, types } from "../../philsPluginLibrary";
|
||||
import { patchConnectionVideoSetDesktopSourceWithOptions, patchConnectionVideoTransportOptions } from "../../philsPluginLibrary/patches/video";
|
||||
import { PluginInfo } from "../constants";
|
||||
import { logger } from "../logger";
|
||||
import { screenshareStore } from "../stores";
|
||||
|
||||
export class ScreensharePatcher extends Patcher {
|
||||
private mediaEngineStore: types.MediaEngineStore;
|
||||
private mediaEngine: types.MediaEngine;
|
||||
public connection?: types.Connection;
|
||||
public oldSetDesktopSourceWithOptions: (...args: any[]) => void;
|
||||
public oldSetTransportOptions: (...args: any[]) => void;
|
||||
public forceUpdateTransportationOptions: () => void;
|
||||
public forceUpdateDesktopSourceOptions: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.mediaEngineStore = MediaEngineStore;
|
||||
this.mediaEngine = this.mediaEngineStore.getMediaEngine();
|
||||
this.forceUpdateTransportationOptions = () => void 0;
|
||||
this.forceUpdateDesktopSourceOptions = () => void 0;
|
||||
this.oldSetDesktopSourceWithOptions = () => void 0;
|
||||
this.oldSetTransportOptions = () => void 0;
|
||||
}
|
||||
|
||||
public patch(): this {
|
||||
this.unpatch();
|
||||
|
||||
const { get } = screenshareStore;
|
||||
|
||||
const connectionEventFunction =
|
||||
(connection: types.Connection) => {
|
||||
if (!(connection.context === "stream" && connection.streamUserId === UserStore.getCurrentUser().id)) return;
|
||||
|
||||
this.connection = connection;
|
||||
|
||||
const {
|
||||
oldSetDesktopSourceWithOptions,
|
||||
oldSetTransportOptions,
|
||||
forceUpdateDesktopSourceOptions,
|
||||
forceUpdateTransportationOptions
|
||||
} = {
|
||||
...patchConnectionVideoTransportOptions(connection, get, logger),
|
||||
...patchConnectionVideoSetDesktopSourceWithOptions(connection, get, logger)
|
||||
};
|
||||
|
||||
this.oldSetDesktopSourceWithOptions = oldSetDesktopSourceWithOptions;
|
||||
this.oldSetTransportOptions = oldSetTransportOptions;
|
||||
this.forceUpdateDesktopSourceOptions = forceUpdateDesktopSourceOptions;
|
||||
this.forceUpdateTransportationOptions = forceUpdateTransportationOptions;
|
||||
|
||||
Emitter.addListener(connection.emitter, "on", "connected", () => {
|
||||
this.forceUpdateTransportationOptions();
|
||||
this.forceUpdateDesktopSourceOptions();
|
||||
});
|
||||
|
||||
Emitter.addListener(connection.emitter, "on", "destroy", () => {
|
||||
this.forceUpdateTransportationOptions = () => void 0;
|
||||
this.forceUpdateDesktopSourceOptions = () => void 0;
|
||||
this.oldSetTransportOptions = () => void 0;
|
||||
this.oldSetDesktopSourceWithOptions = () => void 0;
|
||||
});
|
||||
};
|
||||
|
||||
Emitter.addListener(
|
||||
this.mediaEngine.emitter,
|
||||
"on",
|
||||
"connection",
|
||||
connectionEventFunction,
|
||||
PluginInfo.PLUGIN_NAME
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unpatch(): this {
|
||||
return this._unpatch();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { UserStore } from "@webpack/common";
|
||||
|
||||
import { Emitter, MediaEngineStore, patchConnectionAudioTransportOptions, Patcher, types } from "../../philsPluginLibrary";
|
||||
import { PluginInfo } from "../constants";
|
||||
import { logger } from "../logger";
|
||||
import { screenshareAudioStore } from "../stores/screenshareAudioStore";
|
||||
|
||||
export class ScreenshareAudioPatcher extends Patcher {
|
||||
private mediaEngineStore: types.MediaEngineStore;
|
||||
private mediaEngine: types.MediaEngine;
|
||||
public connection?: types.Connection;
|
||||
|
||||
public oldSetTransportOptions: (...args: any[]) => void;
|
||||
public forceUpdateTransportationOptions: () => void;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.mediaEngineStore = MediaEngineStore;
|
||||
this.mediaEngine = this.mediaEngineStore.getMediaEngine();
|
||||
|
||||
this.forceUpdateTransportationOptions = () => void 0;
|
||||
this.oldSetTransportOptions = () => void 0;
|
||||
}
|
||||
|
||||
public patch(): this {
|
||||
this.unpatch();
|
||||
|
||||
const { get } = screenshareAudioStore;
|
||||
|
||||
const connectionEventFunction =
|
||||
(connection: types.Connection) => {
|
||||
if (connection.context !== "stream" || connection.streamUserId !== UserStore.getCurrentUser().id) return;
|
||||
|
||||
this.connection = connection;
|
||||
|
||||
const {
|
||||
forceUpdateTransportationOptions: forceUpdateTransportationOptionsAudio,
|
||||
oldSetTransportOptions: oldSetTransportOptionsAudio
|
||||
} = patchConnectionAudioTransportOptions(connection, get, logger);
|
||||
|
||||
this.forceUpdateTransportationOptions = forceUpdateTransportationOptionsAudio;
|
||||
this.oldSetTransportOptions = oldSetTransportOptionsAudio;
|
||||
|
||||
Emitter.addListener(connection.emitter, "on", "connected", () => {
|
||||
this.forceUpdateTransportationOptions();
|
||||
});
|
||||
|
||||
Emitter.addListener(connection.emitter, "on", "destroy", () => {
|
||||
this.forceUpdateTransportationOptions = () => void 0;
|
||||
});
|
||||
};
|
||||
|
||||
Emitter.addListener(
|
||||
this.mediaEngine.emitter,
|
||||
"on",
|
||||
"connection",
|
||||
connectionEventFunction,
|
||||
PluginInfo.PLUGIN_NAME
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unpatch(): this {
|
||||
return this._unpatch();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./screenshareModal";
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { React } from "@webpack/common";
|
||||
import { Settings } from "Vencord";
|
||||
|
||||
import { SettingsModalCard, SettingsModalCardItem } from "../../philsPluginLibrary";
|
||||
import Plugin from "..";
|
||||
import { AudioSourceSelect, OpenScreenshareSettingsButton } from "../components";
|
||||
import { PluginInfo } from "../constants";
|
||||
import { screenshareStore } from "../stores";
|
||||
|
||||
const ReplacedStreamSettings = () => {
|
||||
const { use } = screenshareStore;
|
||||
|
||||
const { audioSourceEnabled, setAudioSourceEnabled } = use();
|
||||
|
||||
const cardProps = { style: { border: "1px solid var(--primary-800)" } };
|
||||
|
||||
return (
|
||||
<div style={{ margin: "1em", display: "flex", flexDirection: "column", gap: "1em" }}>
|
||||
<SettingsModalCard cardProps={cardProps} title="Stream Settings">
|
||||
<SettingsModalCardItem>
|
||||
<Flex flexDirection="column">
|
||||
<OpenScreenshareSettingsButton title="Advanced Settings" />
|
||||
</Flex>
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>
|
||||
<SettingsModalCard
|
||||
cardProps={cardProps}
|
||||
switchEnabled
|
||||
switchProps={{
|
||||
checked: audioSourceEnabled ?? false,
|
||||
onChange: status => setAudioSourceEnabled(status)
|
||||
}}
|
||||
title="Audio Source">
|
||||
<SettingsModalCardItem>
|
||||
<AudioSourceSelect isDisabled={!audioSourceEnabled} />
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export function replacedScreenshareModalSettingsContentType(oldType: (...args: any[]) => any, thisContext: any, functionArguments: any) {
|
||||
const { hideDefaultSettings } = Settings.plugins[PluginInfo.PLUGIN_NAME];
|
||||
const oldTypeResult = Reflect.apply(oldType, thisContext, functionArguments);
|
||||
|
||||
if (hideDefaultSettings)
|
||||
oldTypeResult.props.children = oldTypeResult.props.children.filter(c => !c?.props?.selectedFPS);
|
||||
oldTypeResult.props.children.push(<ReplacedStreamSettings />);
|
||||
|
||||
return oldTypeResult;
|
||||
}
|
||||
|
||||
export function replacedScreenshareModalComponent(oldComponent: (...args: any[]) => any, thisContext: any, functionArguments: any) {
|
||||
const oldComponentResult = Reflect.apply(oldComponent, thisContext, functionArguments);
|
||||
|
||||
const content = oldComponentResult.props.children.props.children[2].props.children[1].props.children[2].props.children.props.children;
|
||||
const oldContentType = content.type;
|
||||
|
||||
content.type = function () {
|
||||
return replacedScreenshareModalSettingsContentType(oldContentType, this, arguments);
|
||||
};
|
||||
|
||||
const [submitBtn, cancelBtn] = oldComponentResult.props.children.props.children[2].props.children[2].props.children;
|
||||
|
||||
submitBtn.props.onClick = () => {
|
||||
const { screensharePatcher, screenshareAudioPatcher } = Plugin;
|
||||
|
||||
if (screensharePatcher) {
|
||||
screensharePatcher.forceUpdateTransportationOptions();
|
||||
if (screensharePatcher.connection?.connectionState === "CONNECTED")
|
||||
screensharePatcher.forceUpdateDesktopSourceOptions();
|
||||
}
|
||||
|
||||
if (screenshareAudioPatcher)
|
||||
screenshareAudioPatcher.forceUpdateTransportationOptions();
|
||||
};
|
||||
|
||||
return oldComponentResult;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./screenshareAudioStore";
|
||||
export * from "./screenshareStore";
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
defaultMicrophoneProfiles as defaultScreenshareAudioProfiles,
|
||||
MicrophoneProfile as ScreenshareAudioProfile,
|
||||
MicrophoneStore as ScreenshareAudioStore,
|
||||
microphoneStoreDefault as screenshareAudioStoreDefault
|
||||
} from "../../betterMicrophone.desktop/stores";
|
||||
import { createPluginStore, ProfilableStore, profileable } from "../../philsPluginLibrary";
|
||||
import { PluginInfo } from "../constants";
|
||||
|
||||
export let screenshareAudioStore: ProfilableStore<ScreenshareAudioStore, ScreenshareAudioProfile>;
|
||||
|
||||
export const initScreenshareAudioStore = () =>
|
||||
screenshareAudioStore = createPluginStore(
|
||||
PluginInfo.PLUGIN_NAME,
|
||||
"ScreenshareAudioStore",
|
||||
profileable(
|
||||
screenshareAudioStoreDefault,
|
||||
{ name: "" },
|
||||
Object.values(defaultScreenshareAudioProfiles)
|
||||
)
|
||||
);
|
||||
|
||||
export { defaultScreenshareAudioProfiles, ScreenshareAudioProfile, ScreenshareAudioStore, screenshareAudioStoreDefault };
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { createPluginStore, ProfilableInitializer, ProfilableStore, profileable, ProfileableProfile } from "../../philsPluginLibrary";
|
||||
import { PluginInfo } from "../constants";
|
||||
|
||||
|
||||
export interface ScreenshareProfile {
|
||||
width?: number,
|
||||
height?: number,
|
||||
framerate?: number,
|
||||
videoCodec?: string,
|
||||
keyframeInterval?: number,
|
||||
videoBitrate?: number;
|
||||
videoBitrateEnabled?: boolean;
|
||||
resolutionEnabled?: boolean,
|
||||
framerateEnabled?: boolean,
|
||||
videoCodecEnabled?: boolean;
|
||||
keyframeIntervalEnabled?: boolean;
|
||||
hdrEnabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ScreenshareStore {
|
||||
audioSource?: string;
|
||||
audioSourceEnabled?: boolean;
|
||||
simpleMode?: boolean;
|
||||
setWidth: (width?: number) => void;
|
||||
setHeight: (height?: number) => void;
|
||||
setFramerate: (framerate?: number) => void;
|
||||
setVideoCodec: (codec?: string) => void;
|
||||
setKeyframeInterval: (keyframeInterval?: number) => void;
|
||||
setVideoBitrate: (bitrate?: number) => void;
|
||||
setKeyframeIntervalEnabled: (enabled?: boolean) => void;
|
||||
setResolutionEnabled: (enabled?: boolean) => void;
|
||||
setFramerateEnabled: (enabled?: boolean) => void;
|
||||
setVideoCodecEnabled: (enabled?: boolean) => void;
|
||||
setVideoBitrateEnabled: (enabled?: boolean) => void;
|
||||
setHdrEnabled: (enabled?: boolean) => void;
|
||||
setAudioSource: (audioSource?: string) => void;
|
||||
setAudioSourceEnabled: (enabled?: boolean) => void;
|
||||
setSimpleMode: (enabled?: boolean) => void;
|
||||
}
|
||||
|
||||
export const defaultScreenshareProfiles = {
|
||||
low: {
|
||||
name: "Low Quality",
|
||||
width: 1280,
|
||||
height: 720,
|
||||
framerate: 60,
|
||||
videoBitrate: 2500,
|
||||
resolutionEnabled: true,
|
||||
framerateEnabled: true,
|
||||
videoBitrateEnabled: true,
|
||||
},
|
||||
medium: {
|
||||
name: "Medium Quality",
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
framerate: 60,
|
||||
videoBitrate: 5000,
|
||||
resolutionEnabled: true,
|
||||
framerateEnabled: true,
|
||||
videoBitrateEnabled: true,
|
||||
},
|
||||
high: {
|
||||
name: "High Quality",
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
framerate: 60,
|
||||
videoBitrate: 10000,
|
||||
resolutionEnabled: true,
|
||||
framerateEnabled: true,
|
||||
videoBitrateEnabled: true,
|
||||
}
|
||||
} as const satisfies Record<string, ScreenshareProfile & ProfileableProfile>;
|
||||
|
||||
export const screenshareStoreDefault: ProfilableInitializer<ScreenshareStore, ScreenshareProfile> = (set, get) => ({
|
||||
setVideoBitrate: bitrate => get().currentProfile.videoBitrate = bitrate,
|
||||
setVideoBitrateEnabled: enabled => get().currentProfile.videoBitrateEnabled = enabled,
|
||||
setVideoCodec: codec => get().currentProfile.videoCodec = codec,
|
||||
setVideoCodecEnabled: enabled => get().currentProfile.videoCodecEnabled = enabled,
|
||||
setFramerate: framerate => get().currentProfile.framerate = framerate,
|
||||
setFramerateEnabled: enabled => get().currentProfile.framerateEnabled = enabled,
|
||||
setHeight: height => get().currentProfile.height = height,
|
||||
setWidth: width => get().currentProfile.width = width,
|
||||
setResolutionEnabled: enabled => get().currentProfile.resolutionEnabled = enabled,
|
||||
setKeyframeInterval: keyframeInterval => get().currentProfile.keyframeInterval = keyframeInterval,
|
||||
setKeyframeIntervalEnabled: enabled => get().currentProfile.keyframeIntervalEnabled = enabled,
|
||||
setHdrEnabled: enabled => get().currentProfile.hdrEnabled = enabled,
|
||||
setAudioSource: audioSource => get().audioSource = audioSource,
|
||||
setAudioSourceEnabled: enabled => get().audioSourceEnabled = enabled,
|
||||
setSimpleMode: enabled => get().simpleMode = enabled,
|
||||
simpleMode: true
|
||||
});
|
||||
|
||||
export let screenshareStore: ProfilableStore<ScreenshareStore, ScreenshareProfile>;
|
||||
|
||||
export const initScreenshareStore = () =>
|
||||
screenshareStore = createPluginStore(
|
||||
PluginInfo.PLUGIN_NAME,
|
||||
"ScreenshareStore",
|
||||
profileable(
|
||||
screenshareStoreDefault,
|
||||
{ name: "" },
|
||||
Object.values(defaultScreenshareProfiles)
|
||||
)
|
||||
);
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { PluginAuthor } from "@utils/types";
|
||||
import { useEffect, UserUtils, useState } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
import React from "react";
|
||||
|
||||
import { createDummyUser, types, UserSummaryItem } from "../../philsPluginLibrary";
|
||||
|
||||
export interface AuthorUserSummaryItemProps extends Partial<React.ComponentProps<types.UserSummaryItem>> {
|
||||
authors: PluginAuthor[];
|
||||
}
|
||||
|
||||
export const AuthorUserSummaryItem = (props: AuthorUserSummaryItemProps) => {
|
||||
const [users, setUsers] = useState<Partial<User>[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
props.authors.forEach(author =>
|
||||
UserUtils.getUser(`${author.id}`)
|
||||
.then(user => setUsers(users => [...users, user]))
|
||||
.catch(() => setUsers(users => [...users, createDummyUser({
|
||||
username: author.name,
|
||||
id: `${author.id}`,
|
||||
bot: true,
|
||||
})]))
|
||||
);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<UserSummaryItem
|
||||
users={users as User[]}
|
||||
guildId={undefined}
|
||||
renderIcon={false}
|
||||
showDefaultAvatarsForNullUsers
|
||||
showUserPopout
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Text } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { Author, Contributor } from "../types";
|
||||
import { openURL } from "../utils";
|
||||
import { AuthorUserSummaryItem } from "./AuthorSummaryItem";
|
||||
|
||||
export interface ContributorAuthorSummaryProps {
|
||||
author?: Author;
|
||||
contributors?: Contributor[];
|
||||
}
|
||||
|
||||
export const ContributorAuthorSummary = ({ author, contributors }: ContributorAuthorSummaryProps) => {
|
||||
return (
|
||||
<Flex style={{ gap: "0.7em" }}>
|
||||
{author &&
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", gap: "0.5em" }}>
|
||||
<Text variant="text-sm/normal" style={{ color: "var(--text-muted)" }}>
|
||||
Author: <a onClick={() => author.github && openURL(author.github)}>{`${author.name}`}</a>
|
||||
</Text>
|
||||
<AuthorUserSummaryItem authors={[author]} />
|
||||
</Flex>
|
||||
}
|
||||
{(contributors && contributors.length > 0) &&
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", gap: "0.5em" }}>
|
||||
<Text variant="text-sm/normal" style={{ color: "var(--text-muted)" }}>
|
||||
Contributors:
|
||||
</Text>
|
||||
<AuthorUserSummaryItem authors={contributors} />
|
||||
</Flex>
|
||||
}
|
||||
</Flex>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Button } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { IconTooltipButton } from ".";
|
||||
|
||||
export const CopyButton = (props: typeof Button["defaultProps"]) => {
|
||||
return (
|
||||
<IconTooltipButton
|
||||
color={Button.Colors.PRIMARY}
|
||||
tooltipText="Copy Profile"
|
||||
icon={
|
||||
<svg width="18" height="18" viewBox="0 0 24 24">
|
||||
<path d="M7.024 3.75c0-.966.784-1.75 1.75-1.75H20.25c.966 0 1.75.784 1.75 1.75v11.498a1.75 1.75 0 0 1-1.75 1.75H8.774a1.75 1.75 0 0 1-1.75-1.75Zm1.75-.25a.25.25 0 0 0-.25.25v11.498c0 .139.112.25.25.25H20.25a.25.25 0 0 0 .25-.25V3.75a.25.25 0 0 0-.25-.25Z" fill="currentColor"></path>
|
||||
<path d="M1.995 10.749a1.75 1.75 0 0 1 1.75-1.751H5.25a.75.75 0 1 1 0 1.5H3.745a.25.25 0 0 0-.25.25L3.5 20.25c0 .138.111.25.25.25h9.5a.25.25 0 0 0 .25-.25v-1.51a.75.75 0 1 1 1.5 0v1.51A1.75 1.75 0 0 1 13.25 22h-9.5A1.75 1.75 0 0 1 2 20.25l-.005-9.501Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
}
|
||||
{...props} />
|
||||
);
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Button } from "@webpack/common";
|
||||
import * as types from "@webpack/types";
|
||||
import React from "react";
|
||||
|
||||
import { IconTooltipButton } from ".";
|
||||
|
||||
export const DeleteButton = (props: types.Button["defaultProps"]) => {
|
||||
return (
|
||||
<IconTooltipButton
|
||||
color={Button.Colors.RED}
|
||||
tooltipText="Delete Profile"
|
||||
icon={
|
||||
<svg width="18" height="18" viewBox="0 0 24 24">
|
||||
<path d="M16 1.75V3h5.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H8V1.75C8 .784 8.784 0 9.75 0h4.5C15.216 0 16 .784 16 1.75Zm-6.5 0V3h5V1.75a.25.25 0 0 0-.25-.25h-4.5a.25.25 0 0 0-.25.25ZM4.997 6.178a.75.75 0 1 0-1.493.144L4.916 20.92a1.75 1.75 0 0 0 1.742 1.58h10.684a1.75 1.75 0 0 0 1.742-1.581l1.413-14.597a.75.75 0 0 0-1.494-.144l-1.412 14.596a.25.25 0 0 1-.249.226H6.658a.25.25 0 0 1-.249-.226L4.997 6.178Z" fill="currentColor"></path>
|
||||
<path d="M9.206 7.501a.75.75 0 0 1 .793.705l.5 8.5A.75.75 0 1 1 9 16.794l-.5-8.5a.75.75 0 0 1 .705-.793Zm6.293.793A.75.75 0 1 0 14 8.206l-.5 8.5a.75.75 0 0 0 1.498.088l.5-8.5Z" fill="currentColor"></path>
|
||||
</svg>
|
||||
}
|
||||
{...props} />
|
||||
);
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Button, Tooltip } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
|
||||
export interface IconTooltipButtonProps {
|
||||
tooltipText?: string;
|
||||
icon?: JSX.Element;
|
||||
}
|
||||
|
||||
export const IconTooltipButton = (props: typeof Button["defaultProps"] & IconTooltipButtonProps) => {
|
||||
return (
|
||||
<Tooltip text={props.tooltipText}>
|
||||
{tooltipProps => <Button
|
||||
size={Button.Sizes.ICON}
|
||||
{...props as any}
|
||||
style={{ aspectRatio: 1, maxHeight: "32px", boxSizing: "border-box", ...props.style }}
|
||||
>
|
||||
<Flex style={{ justifyContent: "center", alignItems: "center", width: 24, height: 24 }}>
|
||||
{props.icon}
|
||||
</Flex>
|
||||
<span {...tooltipProps} style={{ position: "absolute", top: 0, right: 0, bottom: 0, left: 0 }} />
|
||||
</Button>}
|
||||
</Tooltip >
|
||||
);
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Button } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { IconTooltipButton } from ".";
|
||||
|
||||
export const NewButton = (props: typeof Button["defaultProps"]) => {
|
||||
return (
|
||||
<IconTooltipButton
|
||||
color={Button.Colors.PRIMARY}
|
||||
tooltipText="New Profile"
|
||||
icon={
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="12" y1="5" x2="12" y2="19"></line>
|
||||
<line x1="5" y1="12" x2="19" y2="12"></line>
|
||||
</svg>
|
||||
}
|
||||
{...props} />
|
||||
);
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Button } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { IconTooltipButton } from ".";
|
||||
|
||||
export const SaveButton = (props: typeof Button["defaultProps"]) => {
|
||||
return (
|
||||
<IconTooltipButton
|
||||
color={Button.Colors.GREEN}
|
||||
tooltipText="Save Profile"
|
||||
icon={
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" >
|
||||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path>
|
||||
<polyline points="17 21 17 13 7 13 7 21"></polyline>
|
||||
<polyline points="7 3 7 8 15 8"></polyline>
|
||||
</svg>
|
||||
}
|
||||
{...props} />
|
||||
);
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./CopyButton";
|
||||
export * from "./DeleteButton";
|
||||
export * from "./IconTooltipButton";
|
||||
export * from "./NewButton";
|
||||
export * from "./SaveButton";
|
23
src/equicordplugins/philsPluginLibrary/components/index.tsx
Normal file
23
src/equicordplugins/philsPluginLibrary/components/index.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./AuthorSummaryItem";
|
||||
export * from "./buttons";
|
||||
export * from "./ContributorAuthorSummary";
|
||||
export * from "./settingsModal";
|
||||
export * from "./settingsPanel";
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot } from "@utils/modal";
|
||||
import { Button, Text } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { Author, Contributor } from "../../types";
|
||||
import { ContributorAuthorSummary } from "../ContributorAuthorSummary";
|
||||
|
||||
|
||||
export interface SettingsModalProps extends React.ComponentProps<typeof ModalRoot> {
|
||||
title?: string;
|
||||
onClose: () => void;
|
||||
onDone?: () => void;
|
||||
footerContent?: JSX.Element;
|
||||
closeButtonName?: string;
|
||||
author?: Author,
|
||||
contributors?: Contributor[];
|
||||
}
|
||||
|
||||
export const SettingsModal = (props: SettingsModalProps) => {
|
||||
const doneButton =
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
color={Button.Colors.BRAND}
|
||||
onClick={props.onDone}
|
||||
>
|
||||
{props.closeButtonName ?? "Done"}
|
||||
</Button>;
|
||||
|
||||
return (
|
||||
<ModalRoot {...props}>
|
||||
<ModalHeader separator={false}>
|
||||
{props.title && <Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>{props.title}</Text>}
|
||||
<div style={{ marginLeft: "auto" }}>
|
||||
<ModalCloseButton onClick={props.onClose} />
|
||||
</div>
|
||||
</ModalHeader>
|
||||
<ModalContent style={{ marginBottom: "1em", display: "flex", flexDirection: "column", gap: "1em" }}>
|
||||
{props.children}
|
||||
</ModalContent>
|
||||
<ModalFooter>
|
||||
<Flex style={{ width: "100%" }}>
|
||||
<div style={{ flex: 1, display: "flex" }}>
|
||||
{(props.author || props.contributors && props.contributors.length > 0) &&
|
||||
|
||||
<Flex style={{ justifyContent: "flex-start", alignItems: "center", flex: 1 }}>
|
||||
<ContributorAuthorSummary
|
||||
author={props.author}
|
||||
contributors={props.contributors} />
|
||||
</Flex>
|
||||
}
|
||||
{props.footerContent}
|
||||
</div>
|
||||
<div style={{ marginLeft: "auto" }}>{doneButton}</div>
|
||||
</Flex>
|
||||
</ModalFooter>
|
||||
</ModalRoot >
|
||||
);
|
||||
};
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Switch } from "@components/Switch";
|
||||
import { Card, Forms } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
export interface SettingsModalItemProps extends Pick<React.ComponentProps<"div">,
|
||||
| "children"> {
|
||||
title?: string;
|
||||
switchEnabled?: boolean;
|
||||
switchProps?: React.ComponentProps<typeof Switch>;
|
||||
flex?: number;
|
||||
cardProps?: React.ComponentProps<typeof Card>;
|
||||
}
|
||||
|
||||
export const SettingsModalCard = ({ children, title, switchProps, switchEnabled, flex, cardProps }: SettingsModalItemProps) => {
|
||||
return (
|
||||
<Card
|
||||
{...cardProps}
|
||||
style={{
|
||||
padding: "1em",
|
||||
boxSizing: "border-box",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
flex: flex ?? 1,
|
||||
...(cardProps?.style ? cardProps.style : {})
|
||||
}}>
|
||||
{title && <Forms.FormTitle tag="h5" style={{ margin: 0 }}>{title}</Forms.FormTitle>}
|
||||
<div style={{
|
||||
display: "flex",
|
||||
gap: "1em",
|
||||
height: "100%",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingTop: "0.6em",
|
||||
}}>
|
||||
{children &&
|
||||
<div style={{
|
||||
display: "flex",
|
||||
alignItems: "flex-end",
|
||||
gap: "1em",
|
||||
flex: 1
|
||||
}}>
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
{switchEnabled &&
|
||||
<div style={{
|
||||
display: "flex",
|
||||
height: "100%",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}>
|
||||
<Forms.FormTitle tag="h5">Status</Forms.FormTitle>
|
||||
<Switch
|
||||
checked={false}
|
||||
onChange={() => void 0}
|
||||
disabled={false}
|
||||
{...switchProps}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Card >
|
||||
);
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Forms } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
export interface SettingsModalCardItemProps extends Pick<React.ComponentProps<"div">,
|
||||
| "children"> {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const SettingsModalCardItem = ({ children, title }: SettingsModalCardItemProps) => {
|
||||
return (
|
||||
<div style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "0.4em",
|
||||
width: "100%"
|
||||
}}>
|
||||
{title && <Forms.FormTitle tag="h5" style={{ margin: 0 }}>{title}</Forms.FormTitle>}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
export interface SettingsModalRowProps extends Pick<React.ComponentProps<"div">,
|
||||
| "children"
|
||||
| "style"> {
|
||||
gap?: string;
|
||||
}
|
||||
|
||||
export const SettingsModalCardRow = ({ children, style, gap }: SettingsModalRowProps) => {
|
||||
return (
|
||||
<div style={{ display: "flex", gap: gap ?? "1em", ...style }}>{children}</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { Select, TextInput, useEffect, useState } from "@webpack/common";
|
||||
|
||||
import { PluginSettings, ProfilableStore } from "../../../philsPluginLibrary";
|
||||
import { CopyButton, DeleteButton, NewButton, SaveButton } from "../buttons";
|
||||
import { SettingsModalCard } from "./SettingsModalCard";
|
||||
import { SettingsModalCardItem } from "./SettingsModalCardItem";
|
||||
|
||||
export interface SettingsModalProfilesCardProps<T extends PluginSettings = {}> extends React.ComponentProps<typeof SettingsModalCard> {
|
||||
profileableStore: ProfilableStore<T, any>;
|
||||
onSaveStateChanged: (isSaving: boolean) => void;
|
||||
}
|
||||
|
||||
export const SettingsModalProfilesCard = <T extends PluginSettings = {},>(props: SettingsModalProfilesCardProps<T>) => {
|
||||
const { profileableStore: { use } } = props;
|
||||
|
||||
const {
|
||||
currentProfile,
|
||||
setCurrentProfile,
|
||||
deleteProfile,
|
||||
getCurrentProfile,
|
||||
getDefaultProfiles,
|
||||
getProfile,
|
||||
getProfiles,
|
||||
saveProfile,
|
||||
isCurrentProfileADefaultProfile
|
||||
} = use();
|
||||
|
||||
const { name } = currentProfile;
|
||||
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [profileNameInput, setProfileNameInput] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
props.onSaveStateChanged(isSaving);
|
||||
}, [isSaving]);
|
||||
|
||||
const onSaveProfile = () => {
|
||||
if (!isSaving) {
|
||||
setIsSaving(true);
|
||||
|
||||
} else {
|
||||
if (profileNameInput.length && !getDefaultProfiles().some(value => value.name === profileNameInput)) {
|
||||
saveProfile({ ...getCurrentProfile(), name: profileNameInput });
|
||||
setCurrentProfile(getProfile(profileNameInput) || { name: "" });
|
||||
setIsSaving(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onCopyProfile = () => {
|
||||
setCurrentProfile({ ...getCurrentProfile(), name: "" });
|
||||
};
|
||||
|
||||
const onNewProfile = () => {
|
||||
setCurrentProfile({ name: "" });
|
||||
};
|
||||
|
||||
const onDeleteProfile = () => {
|
||||
deleteProfile(currentProfile);
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsModalCard
|
||||
title="Profile"
|
||||
{...props}>
|
||||
<SettingsModalCardItem>
|
||||
<Flex style={{ alignItems: "center" }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
{isSaving
|
||||
? <TextInput
|
||||
style={{ width: "100%" }}
|
||||
placeholder="Insert name"
|
||||
value={profileNameInput}
|
||||
onChange={setProfileNameInput} />
|
||||
: <Select
|
||||
isSelected={value => name === value}
|
||||
options={getProfiles(true).map(profile => ({
|
||||
label: profile.name,
|
||||
value: profile.name
|
||||
}))}
|
||||
select={value => setCurrentProfile(getProfile(value) || { name: "" })}
|
||||
serialize={() => ""} />}
|
||||
</div>
|
||||
<Flex style={{ gap: "0.8em" }}>
|
||||
<SaveButton onClick={onSaveProfile} />
|
||||
<NewButton onClick={onNewProfile} disabled={isSaving} />
|
||||
<CopyButton onClick={onCopyProfile} disabled={isSaving} />
|
||||
<DeleteButton onClick={onDeleteProfile} disabled={isSaving || isCurrentProfileADefaultProfile() || !currentProfile.name.length} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
</SettingsModalCardItem>
|
||||
</SettingsModalCard>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./SettingsModal";
|
||||
export * from "./SettingsModalCard";
|
||||
export * from "./SettingsModalCardItem";
|
||||
export * from "./SettingsModalCardRow";
|
||||
export * from "./SettingsModalProfilesCard";
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { React } from "@webpack/common";
|
||||
|
||||
import { panelClasses } from "../../discordModules";
|
||||
|
||||
|
||||
export interface SettingsPanelProps {
|
||||
children: React.ComponentProps<"div">["children"];
|
||||
}
|
||||
|
||||
export const SettingsPanel = ({ children }: SettingsPanelProps) => {
|
||||
return (
|
||||
<div
|
||||
className={panelClasses.container}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { classes } from "@utils/misc";
|
||||
import { Button } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { panelClasses } from "../../../philsPluginLibrary";
|
||||
|
||||
export type IconComponent = <T extends { className: string; }>(props: T) => JSX.Element;
|
||||
export interface SettingsPanelButtonProps extends Partial<React.ComponentProps<typeof Button>> {
|
||||
icon?: IconComponent;
|
||||
}
|
||||
|
||||
export const SettingsPanelButton = (props: SettingsPanelButtonProps) => {
|
||||
return (
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
className={classes(panelClasses.button, panelClasses.buttonColor)}
|
||||
innerClassName={classes(panelClasses.buttonContents)}
|
||||
wrapperClassName={classes(panelClasses.button)}
|
||||
children={props.icon && <props.icon className={classes(panelClasses.buttonIcon)} />}
|
||||
{...props} />
|
||||
);
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { classes } from "@utils/misc";
|
||||
import React from "react";
|
||||
|
||||
import { panelClasses } from "../../discordModules";
|
||||
|
||||
export interface SettingsPanelRowProps {
|
||||
children: React.ComponentProps<"div">["children"];
|
||||
}
|
||||
|
||||
export const SettingsPanelRow = ({ children }: SettingsPanelRowProps) => {
|
||||
return (
|
||||
<div
|
||||
className={classes(panelClasses.actionButtons)}
|
||||
style={{ padding: 0 }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Tooltip } from "@webpack/common";
|
||||
import React from "react";
|
||||
|
||||
import { SettingsPanelButton, SettingsPanelButtonProps } from "./SettingsPanelButton";
|
||||
|
||||
export interface SettingsPanelTooltipButtonProps extends SettingsPanelButtonProps {
|
||||
tooltipProps: Omit<React.ComponentProps<typeof Tooltip>, "children">;
|
||||
}
|
||||
|
||||
export const SettingsPanelTooltipButton = (props: SettingsPanelTooltipButtonProps) => {
|
||||
return (
|
||||
<Tooltip {...props.tooltipProps}>
|
||||
{tooltipProps => <SettingsPanelButton {...tooltipProps} {...props} />}
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./SettingsPanel";
|
||||
export * from "./SettingsPanelButton";
|
||||
export * from "./SettingsPanelRow";
|
||||
export * from "./SettingsPanelTooltipButton";
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Devs } from "@utils/constants";
|
||||
|
||||
import * as types from "../types/constants";
|
||||
|
||||
export const PluginInfo: types.PluginInfo = {
|
||||
PLUGIN_NAME: "PhilsPluginLibrary",
|
||||
DESCRIPTION: "A library for phil's plugins",
|
||||
AUTHOR: {
|
||||
...Devs.philhk,
|
||||
github: "https://github.com/philhk"
|
||||
},
|
||||
} as const;
|
19
src/equicordplugins/philsPluginLibrary/constants/index.ts
Normal file
19
src/equicordplugins/philsPluginLibrary/constants/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./constants";
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
|
||||
import * as types from "../types";
|
||||
|
||||
export const panelClasses: types.PanelClasses = findByPropsLazy("button", "buttonContents", "buttonColor");
|
||||
|
||||
// waitFor(filters.byProps("button", "buttonContents", "buttonColor"), result => panelClasses = result);
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { findByCode } from "@webpack";
|
||||
|
||||
import { types } from "../";
|
||||
|
||||
export const UserSummaryItem = LazyComponent<React.ComponentProps<types.UserSummaryItem>>(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers"));
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./classes";
|
||||
export * from "./components";
|
||||
export * from "./modules";
|
||||
export * from "./stores";
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { filters, waitFor } from "@webpack";
|
||||
|
||||
import * as types from "../types";
|
||||
|
||||
export let utils: types.Utils;
|
||||
|
||||
waitFor(filters.byProps("getPidFromDesktopSource"), result => utils = result);
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { waitForStore } from "webpack/common/internal";
|
||||
|
||||
import * as types from "../types";
|
||||
|
||||
export let MediaEngineStore: types.MediaEngineStore;
|
||||
|
||||
waitForStore("MediaEngineStore", store => MediaEngineStore = store);
|
86
src/equicordplugins/philsPluginLibrary/emitter/emitter.ts
Normal file
86
src/equicordplugins/philsPluginLibrary/emitter/emitter.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import EventEmitter from "events";
|
||||
import TypedEmitter from "typed-emitter";
|
||||
|
||||
export type TypedEmitterEvents<J extends TypedEmitter<any>> = J extends TypedEmitter<
|
||||
infer N
|
||||
>
|
||||
? N
|
||||
: never;
|
||||
|
||||
export interface EmitterEvent {
|
||||
emitter: TypedEmitter<any> | EventEmitter;
|
||||
event: any;
|
||||
fn: (...args: any[]) => any;
|
||||
plugin?: string;
|
||||
}
|
||||
|
||||
export class Emitter {
|
||||
private static events: EmitterEvent[] = [];
|
||||
|
||||
public static addListener<
|
||||
T extends TypedEmitter<any>,
|
||||
U extends keyof TypedEmitterEvents<T>,
|
||||
V extends TypedEmitterEvents<T>[U]
|
||||
>(
|
||||
emitter: T,
|
||||
type: keyof Pick<EventEmitter, "on" | "once">,
|
||||
event: U,
|
||||
fn: V,
|
||||
plugin?: string
|
||||
): () => void;
|
||||
|
||||
public static addListener(
|
||||
emitter: EventEmitter,
|
||||
type: keyof Pick<EventEmitter, "on" | "once">,
|
||||
event: string,
|
||||
fn: (...args: any[]) => void,
|
||||
plugin?: string
|
||||
): () => void {
|
||||
emitter[type](event, fn);
|
||||
const emitterEvenet: EmitterEvent = {
|
||||
emitter,
|
||||
event,
|
||||
fn,
|
||||
plugin: plugin
|
||||
};
|
||||
this.events.push(emitterEvenet);
|
||||
|
||||
return () => this.removeListener(emitterEvenet);
|
||||
}
|
||||
|
||||
public static removeListener(emitterEvent: EmitterEvent) {
|
||||
emitterEvent.emitter.removeListener(emitterEvent.event, emitterEvent.fn);
|
||||
this.events = this.events.filter(
|
||||
emitterEvent_ => emitterEvent_ !== emitterEvent
|
||||
);
|
||||
}
|
||||
|
||||
public static removeAllListeners(plugin?: string) {
|
||||
if (!plugin) {
|
||||
this.events.forEach(emitterEvent =>
|
||||
this.removeListener(emitterEvent)
|
||||
);
|
||||
} else
|
||||
this.events.forEach(emitterEvent =>
|
||||
plugin === emitterEvent.plugin && this.removeListener(emitterEvent)
|
||||
);
|
||||
}
|
||||
}
|
19
src/equicordplugins/philsPluginLibrary/emitter/index.ts
Normal file
19
src/equicordplugins/philsPluginLibrary/emitter/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./emitter";
|
142
src/equicordplugins/philsPluginLibrary/icons/index.tsx
Normal file
142
src/equicordplugins/philsPluginLibrary/icons/index.tsx
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const ScreenshareSettingsIcon =
|
||||
(props: React.ComponentProps<"svg">) =>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 1000 1000"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<mask id="screenshareSettingsIconMask">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M2 4.5c0-1.103.897-2 2-2h16c1.103 0 2 .897 2 2v11c0 1.104-.897 2-2 2h-7v2h4v2H7v-2h4v-2H4c-1.103 0-2-.896-2-2v-11zm11.2 9.838V11.6c-3.336 0-5.532 1.063-7.2 3.4.672-3.338 2.532-6.662 7.2-7.338V5L18 9.662l-4.8 4.675z"
|
||||
transform="matrix(43.2813 0 0 43.3063 567.187 588.59) translate(-12 -12)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
strokeWidth="0"
|
||||
// Circle
|
||||
d="M132.5 67.5c0 35.899-29.101 65-65 65-35.898 0-65-29.101-65-65 0-35.898 29.102-65 65-65 35.899 0 65 29.102 65 65z"
|
||||
transform="translate(229.14 230.807) scale(4.9157) translate(-67.5 -67.5)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
</mask>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#fff" mask="url(#screenshareSettingsIconMask)"></rect>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
strokeWidth="0"
|
||||
// Settings Icon
|
||||
d="M19.738 10H22v4h-2.261a7.952 7.952 0 01-1.174 2.564L20 18l-2 2-1.435-1.436A7.946 7.946 0 0114 19.738V22h-4v-2.262a7.94 7.94 0 01-2.564-1.174L6 20l-2-2 1.436-1.436A7.911 7.911 0 014.262 14H2v-4h2.262a7.9 7.9 0 011.174-2.564L4 6l2-2 1.436 1.436A7.9 7.9 0 0110 4.262V2h4v2.261a7.967 7.967 0 012.565 1.174L18 3.999l2 2-1.436 1.437A7.93 7.93 0 0119.738 10zM12 16a4 4 0 100-8 4 4 0 000 8z"
|
||||
transform="translate(229.812 230.81) scale(23.0217) translate(-12 -12)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
</svg>;
|
||||
|
||||
export const CameraSettingsIcon =
|
||||
(props: React.ComponentProps<"svg">) =>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 1000 1000"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<mask id="m">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M21.526 8.149a1 1 0 00-.973-.044L18 9.382V7c0-1.103-.897-2-2-2H4c-1.103 0-2 .897-2 2v10c0 1.104.897 2 2 2h12c1.103 0 2-.896 2-2v-2.382l2.553 1.276a.992.992 0 00.973-.043c.294-.183.474-.504.474-.851V9c0-.347-.18-.668-.474-.851z"
|
||||
transform="translate(586.527 617.666) scale(41.3472) translate(-12 -12)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
strokeWidth="0"
|
||||
// Circle
|
||||
d="M132.5 67.5c0 35.899-29.101 65-65 65-35.898 0-65-29.101-65-65 0-35.898 29.102-65 65-65 35.899 0 65 29.102 65 65z"
|
||||
transform="translate(229.14 230.807) scale(4.9157) translate(-67.5 -67.5)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
</mask>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#fff" mask="url(#m)"></rect>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
strokeWidth="0"
|
||||
// Settings Icon
|
||||
d="M19.738 10H22v4h-2.261a7.952 7.952 0 01-1.174 2.564L20 18l-2 2-1.435-1.436A7.946 7.946 0 0114 19.738V22h-4v-2.262a7.94 7.94 0 01-2.564-1.174L6 20l-2-2 1.436-1.436A7.911 7.911 0 014.262 14H2v-4h2.262a7.9 7.9 0 011.174-2.564L4 6l2-2 1.436 1.436A7.9 7.9 0 0110 4.262V2h4v2.261a7.967 7.967 0 012.565 1.174L18 3.999l2 2-1.436 1.437A7.93 7.93 0 0119.738 10zM12 16a4 4 0 100-8 4 4 0 000 8z"
|
||||
transform="translate(229.812 230.81) scale(23.0217) translate(-12 -12)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
</svg>;
|
||||
|
||||
export const MicrophoneSettingsIcon =
|
||||
(props: React.ComponentProps<"svg">) =>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="1000"
|
||||
height="1000"
|
||||
viewBox="0 0 1000 1000"
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<mask id="microphoneSettingsIcon">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M14.99 11c0 1.66-1.33 3-2.99 3-1.66 0-3-1.34-3-3V5c0-1.66 1.34-3 3-3s3 1.34 3 3l-.01 6zM12 16.1c2.76 0 5.3-2.1 5.3-5.1H19c0 3.42-2.72 6.24-6 6.72V21h-2v-3.28c-3.28-.49-6-3.31-6-6.72h1.7c0 3 2.54 5.1 5.3 5.1zM12 4c-.8 0-1 .667-1 1v6c0 .333.2 1 1 1s1-.667 1-1V5c0-.333-.2-1-1-1z"
|
||||
transform="translate(689.616 574.556) scale(48.6222) translate(0 -.417) scale(.8333) translate(-12 -11.5)"
|
||||
></path>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
d="M14.99 11c0 1.66-1.33 3-2.99 3-1.66 0-3-1.34-3-3V5c0-1.66 1.34-3 3-3s3 1.34 3 3l-.01 6zM12 16.1c2.76 0 5.3-2.1 5.3-5.1H19c0 3.42-2.72 6.24-6 6.72V22h-2v-4.28c-3.28-.49-6-3.31-6-6.72h1.7c0 3 2.54 5.1 5.3 5.1z"
|
||||
transform="translate(689.616 574.556) scale(48.6222) scale(.8333) translate(-12 -12)"
|
||||
></path>
|
||||
<path
|
||||
fill="#000"
|
||||
strokeWidth="0"
|
||||
// Circle
|
||||
d="M132.5 67.5c0 35.899-29.101 65-65 65-35.898 0-65-29.101-65-65 0-35.898 29.102-65 65-65 35.899 0 65 29.102 65 65z"
|
||||
transform="translate(229.14 230.807) scale(4.9157) translate(-67.5 -67.5)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
</mask>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#fff" mask="url(#microphoneSettingsIcon)"></rect>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
strokeWidth="0"
|
||||
// Settings Icon
|
||||
d="M19.738 10H22v4h-2.261a7.952 7.952 0 01-1.174 2.564L20 18l-2 2-1.435-1.436A7.946 7.946 0 0114 19.738V22h-4v-2.262a7.94 7.94 0 01-2.564-1.174L6 20l-2-2 1.436-1.436A7.911 7.911 0 014.262 14H2v-4h2.262a7.9 7.9 0 011.174-2.564L4 6l2-2 1.436 1.436A7.9 7.9 0 0110 4.262V2h4v2.261a7.967 7.967 0 012.565 1.174L18 3.999l2 2-1.436 1.437A7.93 7.93 0 0119.738 10zM12 16a4 4 0 100-8 4 4 0 000 8z"
|
||||
transform="translate(229.812 230.81) scale(23.0217) translate(-12 -12)"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
></path>
|
||||
</svg>;
|
55
src/equicordplugins/philsPluginLibrary/index.tsx
Normal file
55
src/equicordplugins/philsPluginLibrary/index.tsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Patch, PluginAuthor, PluginDef } from "@utils/types";
|
||||
|
||||
import { PluginInfo } from "./constants";
|
||||
import { replacedUserPanelComponent } from "./patches";
|
||||
|
||||
export default new class Plugin implements PluginDef {
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly authors: PluginAuthor[];
|
||||
readonly patches: Omit<Patch, "plugin">[];
|
||||
|
||||
readonly replacedUserPanelComponent: typeof replacedUserPanelComponent;
|
||||
|
||||
constructor() {
|
||||
this.name = PluginInfo.PLUGIN_NAME;
|
||||
this.description = PluginInfo.DESCRIPTION;
|
||||
this.authors = PluginInfo.AUTHORS as PluginAuthor[];
|
||||
this.patches = [{
|
||||
find: "Messages.ACCOUNT_A11Y_LABEL",
|
||||
replacement: {
|
||||
match: /(?<=function)( .{0,8}(?={).)(.{0,1000}isFullscreenInContext\(\).+?\)]}\))(})/,
|
||||
replace: "$1return $self.replacedUserPanelComponent(function(){$2}, this, arguments)$3"
|
||||
}
|
||||
}];
|
||||
this.replacedUserPanelComponent = replacedUserPanelComponent;
|
||||
}
|
||||
};
|
||||
|
||||
export * from "./components";
|
||||
export * from "./discordModules";
|
||||
export * from "./emitter";
|
||||
export * from "./icons";
|
||||
export * from "./patchers";
|
||||
export * from "./patches";
|
||||
export * from "./store";
|
||||
export * as types from "./types";
|
||||
export * from "./utils";
|
19
src/equicordplugins/philsPluginLibrary/patchers/index.ts
Normal file
19
src/equicordplugins/philsPluginLibrary/patchers/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./patcher";
|
29
src/equicordplugins/philsPluginLibrary/patchers/patcher.ts
Normal file
29
src/equicordplugins/philsPluginLibrary/patchers/patcher.ts
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export abstract class Patcher {
|
||||
protected unpatchFunctions: (() => any)[] = [];
|
||||
public abstract patch(): this;
|
||||
public abstract unpatch(): this;
|
||||
protected _unpatch(): this {
|
||||
this.unpatchFunctions.forEach(fn => fn());
|
||||
this.unpatchFunctions = [];
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
88
src/equicordplugins/philsPluginLibrary/patches/audio.ts
Normal file
88
src/equicordplugins/philsPluginLibrary/patches/audio.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { lodash } from "@webpack/common";
|
||||
|
||||
import { MicrophoneProfile, MicrophoneStore } from "../../betterMicrophone.desktop/stores";
|
||||
import { ProfilableStore, replaceObjectValuesIfExist, types } from "../../philsPluginLibrary";
|
||||
|
||||
export function getDefaultAudioTransportationOptions(connection: types.Connection) {
|
||||
return {
|
||||
audioEncoder: {
|
||||
...connection.getCodecOptions("opus").audioEncoder,
|
||||
},
|
||||
encodingVoiceBitRate: 64000
|
||||
};
|
||||
}
|
||||
|
||||
export function getReplaceableAudioTransportationOptions(connection: types.Connection, get: ProfilableStore<MicrophoneStore, MicrophoneProfile>["get"]) {
|
||||
const { currentProfile } = get();
|
||||
const {
|
||||
channels,
|
||||
channelsEnabled,
|
||||
freq,
|
||||
freqEnabled,
|
||||
pacsize,
|
||||
pacsizeEnabled,
|
||||
rate,
|
||||
rateEnabled,
|
||||
voiceBitrate,
|
||||
voiceBitrateEnabled
|
||||
} = currentProfile;
|
||||
|
||||
return {
|
||||
...(voiceBitrateEnabled && voiceBitrate
|
||||
? {
|
||||
encodingVoiceBitRate: voiceBitrate * 1000
|
||||
}
|
||||
: {}
|
||||
),
|
||||
audioEncoder: {
|
||||
...connection.getCodecOptions("opus").audioEncoder,
|
||||
...(rateEnabled && rate ? { rate } : {}),
|
||||
...(pacsizeEnabled && pacsize ? { pacsize } : {}),
|
||||
...(freqEnabled && freq ? { freq } : {}),
|
||||
...(channelsEnabled && channels ? { channels } : {})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function patchConnectionAudioTransportOptions(
|
||||
connection: types.Connection,
|
||||
get: ProfilableStore<MicrophoneStore, MicrophoneProfile>["get"],
|
||||
logger?: Logger
|
||||
) {
|
||||
const oldSetTransportOptions = connection.conn.setTransportOptions;
|
||||
|
||||
connection.conn.setTransportOptions = function (this: any, options: Record<string, any>) {
|
||||
replaceObjectValuesIfExist(options, getReplaceableAudioTransportationOptions(connection, get));
|
||||
|
||||
return Reflect.apply(oldSetTransportOptions, this, [options]);
|
||||
};
|
||||
|
||||
const forceUpdateTransportationOptions = () => {
|
||||
const transportOptions = lodash.merge({ ...getDefaultAudioTransportationOptions(connection) }, getReplaceableAudioTransportationOptions(connection, get));
|
||||
|
||||
logger?.info("Overridden Transport Options", transportOptions);
|
||||
|
||||
oldSetTransportOptions(transportOptions);
|
||||
};
|
||||
|
||||
return { oldSetTransportOptions, forceUpdateTransportationOptions };
|
||||
}
|
21
src/equicordplugins/philsPluginLibrary/patches/index.ts
Normal file
21
src/equicordplugins/philsPluginLibrary/patches/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./audio";
|
||||
export * from "./userPanel";
|
||||
export * from "./video";
|
107
src/equicordplugins/philsPluginLibrary/patches/userPanel.tsx
Normal file
107
src/equicordplugins/philsPluginLibrary/patches/userPanel.tsx
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { React } from "@webpack/common";
|
||||
|
||||
import { SettingsPanel } from "../components";
|
||||
import { IconComponent, SettingsPanelButton } from "../components/settingsPanel/SettingsPanelButton";
|
||||
import { SettingsPanelRow } from "../components/settingsPanel/SettingsPanelRow";
|
||||
import { SettingsPanelTooltipButton } from "../components/settingsPanel/SettingsPanelTooltipButton";
|
||||
|
||||
export interface PanelButton {
|
||||
name: string,
|
||||
tooltipText?: string,
|
||||
icon?: IconComponent;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const settingsPanelButtonsSubscriptions = new Set<React.DispatchWithoutAction>();
|
||||
export const settingsPanelButtons: PanelButton[] = new Proxy<PanelButton[]>([], {
|
||||
set: (target, p, newValue) => {
|
||||
target[p] = newValue;
|
||||
settingsPanelButtonsSubscriptions.forEach(fn => fn());
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
export const useButtons = () => {
|
||||
const [, forceUpdate] = React.useReducer(() => ({}), {});
|
||||
|
||||
React.useEffect(() => {
|
||||
settingsPanelButtonsSubscriptions.add(forceUpdate);
|
||||
return () => void settingsPanelButtonsSubscriptions.delete(() => forceUpdate);
|
||||
}, []);
|
||||
|
||||
return settingsPanelButtons;
|
||||
};
|
||||
|
||||
export const ButtonsSettingsPanel = () => {
|
||||
const rawPanelButtons = useButtons();
|
||||
|
||||
const convertRawPanelButtons = (buttons: PanelButton[]) => {
|
||||
const settingsPanelButtonsClone = [...buttons].sort();
|
||||
const groupedButtons: JSX.Element[][] = [];
|
||||
|
||||
while (settingsPanelButtonsClone.length) {
|
||||
const splicedButtons =
|
||||
settingsPanelButtonsClone
|
||||
.splice(0, 3)
|
||||
.map(({ icon, tooltipText, onClick }) =>
|
||||
tooltipText
|
||||
? <SettingsPanelTooltipButton tooltipProps={{ text: tooltipText }} icon={icon} onClick={onClick} />
|
||||
: <SettingsPanelButton icon={icon} onClick={onClick} />
|
||||
);
|
||||
|
||||
groupedButtons.push(splicedButtons);
|
||||
}
|
||||
|
||||
return groupedButtons;
|
||||
};
|
||||
|
||||
return rawPanelButtons.length > 0
|
||||
? <SettingsPanel>
|
||||
{...convertRawPanelButtons(rawPanelButtons).map(value => <SettingsPanelRow children={value} />)}
|
||||
</SettingsPanel>
|
||||
: <>
|
||||
</>;
|
||||
};
|
||||
|
||||
export function replacedUserPanelComponent(oldComponent: (...args: any[]) => any, thisContext: any, functionArguments: any) {
|
||||
const componentResult: JSX.Element = Reflect.apply(oldComponent, thisContext, functionArguments);
|
||||
|
||||
if (!componentResult?.props) return componentResult;
|
||||
|
||||
const { children } = componentResult.props;
|
||||
|
||||
const userPanel = children.at(-2);
|
||||
const userPanelChildren = userPanel.props.children;
|
||||
|
||||
userPanelChildren.splice(userPanelChildren.length - 1, 0,
|
||||
<ButtonsSettingsPanel />
|
||||
);
|
||||
|
||||
return componentResult;
|
||||
}
|
||||
|
||||
export function addSettingsPanelButton(settings: PanelButton) {
|
||||
settingsPanelButtons.push(settings);
|
||||
}
|
||||
|
||||
export function removeSettingsPanelButton(name: string) {
|
||||
settingsPanelButtons.splice(0, settingsPanelButtons.length, ...settingsPanelButtons.filter(value => value.name !== name));
|
||||
}
|
253
src/equicordplugins/philsPluginLibrary/patches/video.ts
Normal file
253
src/equicordplugins/philsPluginLibrary/patches/video.ts
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { lodash } from "@webpack/common";
|
||||
|
||||
import { ScreenshareProfile, ScreenshareStore } from "../../betterScreenshare.desktop/stores";
|
||||
import { ProfilableStore, replaceObjectValuesIfExist, types, utils } from "../../philsPluginLibrary";
|
||||
|
||||
|
||||
export function getDefaultVideoTransportationOptions(connection: types.Connection) {
|
||||
return {
|
||||
...connection.videoQualityManager.applyQualityConstraints({}).constraints,
|
||||
videoEncoder: {
|
||||
...connection.getCodecOptions("", "H264", "stream").videoEncoder
|
||||
},
|
||||
streamParameters: connection.videoStreamParameters[0],
|
||||
keyframeInterval: 0,
|
||||
};
|
||||
}
|
||||
|
||||
export function getDefaultVideoDesktopSourceOptions(connection: types.Connection) {
|
||||
const [type, sourceId] = connection.goLiveSourceIdentifier?.split(":") ?? ["screen", 0];
|
||||
|
||||
return {
|
||||
hdrCaptureMode: "never",
|
||||
allowScreenCaptureKit: true,
|
||||
useQuartzCapturer: true,
|
||||
useGraphicsCapture: true,
|
||||
useVideoHook: true,
|
||||
sourceId: sourceId,
|
||||
type: type
|
||||
};
|
||||
}
|
||||
|
||||
export function getStreamParameters(connection: types.Connection, get: ProfilableStore<ScreenshareStore, ScreenshareProfile>["get"]) {
|
||||
const { currentProfile } = get();
|
||||
const {
|
||||
framerate,
|
||||
framerateEnabled,
|
||||
height,
|
||||
resolutionEnabled,
|
||||
videoBitrate,
|
||||
videoBitrateEnabled,
|
||||
width,
|
||||
} = currentProfile;
|
||||
|
||||
const { bitrateMax, capture } = connection.applyQualityConstraints({}).quality;
|
||||
|
||||
return {
|
||||
...connection.videoStreamParameters[0],
|
||||
...(videoBitrateEnabled && videoBitrate
|
||||
? {
|
||||
maxBitrate: videoBitrate * 1000,
|
||||
}
|
||||
: {
|
||||
maxBitrate: bitrateMax
|
||||
}
|
||||
),
|
||||
...((resolutionEnabled && width && height)
|
||||
? {
|
||||
maxResolution: {
|
||||
height: height,
|
||||
width: width,
|
||||
type: "fixed"
|
||||
},
|
||||
maxPixelCount: width * height
|
||||
}
|
||||
: {
|
||||
maxResolution: !capture.height || !capture.width ? {
|
||||
height: capture.height,
|
||||
width: capture.width,
|
||||
type: "source"
|
||||
} : {
|
||||
height: capture.height,
|
||||
width: capture.width,
|
||||
type: "fixed"
|
||||
}
|
||||
}
|
||||
),
|
||||
...(framerateEnabled && framerate
|
||||
? {
|
||||
maxFrameRate: framerate,
|
||||
}
|
||||
: {
|
||||
maxFrameRate: capture.framerate
|
||||
}
|
||||
),
|
||||
active: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function getReplaceableVideoTransportationOptions(connection: types.Connection, get: ProfilableStore<ScreenshareStore, ScreenshareProfile>["get"]) {
|
||||
const { currentProfile, audioSource, audioSourceEnabled } = get();
|
||||
const {
|
||||
framerate,
|
||||
framerateEnabled,
|
||||
height,
|
||||
keyframeInterval,
|
||||
keyframeIntervalEnabled,
|
||||
resolutionEnabled,
|
||||
videoBitrate,
|
||||
videoBitrateEnabled,
|
||||
videoCodec,
|
||||
videoCodecEnabled,
|
||||
width,
|
||||
} = currentProfile;
|
||||
|
||||
return {
|
||||
...(videoBitrateEnabled && videoBitrate
|
||||
? {
|
||||
encodingVideoBitRate: videoBitrate * 1000,
|
||||
encodingVideoMinBitRate: videoBitrate * 1000,
|
||||
encodingVideoMaxBitRate: videoBitrate * 1000,
|
||||
callBitRate: videoBitrate * 1000,
|
||||
callMinBitRate: videoBitrate * 1000,
|
||||
callMaxBitRate: videoBitrate * 1000
|
||||
}
|
||||
: {}
|
||||
),
|
||||
...((resolutionEnabled && width && height)
|
||||
? {
|
||||
encodingVideoHeight: height,
|
||||
encodingVideoWidth: width,
|
||||
remoteSinkWantsPixelCount: height * width
|
||||
}
|
||||
: {}
|
||||
),
|
||||
...(framerateEnabled && framerate
|
||||
? {
|
||||
encodingVideoFrameRate: framerate,
|
||||
remoteSinkWantsMaxFramerate: framerate
|
||||
}
|
||||
: {}
|
||||
),
|
||||
...(keyframeIntervalEnabled && keyframeInterval
|
||||
? {
|
||||
keyframeInterval: keyframeInterval
|
||||
}
|
||||
: {}
|
||||
),
|
||||
...(videoCodecEnabled && videoCodec
|
||||
? {
|
||||
videoEncoder: connection.getCodecOptions("", videoCodec, "stream").videoEncoder
|
||||
}
|
||||
: {}
|
||||
),
|
||||
...(audioSourceEnabled && audioSource && utils.getPidFromDesktopSource(audioSource)
|
||||
? {
|
||||
soundsharePid: utils.getPidFromDesktopSource(audioSource),
|
||||
soundshareEventDriven: true,
|
||||
soundshareLoopback: true
|
||||
}
|
||||
: {}
|
||||
),
|
||||
streamParameters: getStreamParameters(connection, get)
|
||||
};
|
||||
}
|
||||
|
||||
export function getReplaceableVideoDesktopSourceOptions(get: ProfilableStore<ScreenshareStore, ScreenshareProfile>["get"]) {
|
||||
const { currentProfile } = get();
|
||||
const {
|
||||
hdrEnabled,
|
||||
} = currentProfile;
|
||||
|
||||
return {
|
||||
...(hdrEnabled
|
||||
? {
|
||||
hdrCaptureMode: "always"
|
||||
}
|
||||
: {}
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
export function patchConnectionVideoSetDesktopSourceWithOptions(
|
||||
connection: types.Connection,
|
||||
get: ProfilableStore<ScreenshareStore, ScreenshareProfile>["get"],
|
||||
logger?: Logger
|
||||
) {
|
||||
const oldSetDesktopSourceWithOptions = connection.conn.setDesktopSourceWithOptions;
|
||||
|
||||
connection.conn.setDesktopSourceWithOptions = function (this: any, options: Record<string, any>) {
|
||||
const replaceableDesktopSourceOptions = getReplaceableVideoDesktopSourceOptions(get);
|
||||
replaceObjectValuesIfExist(options, replaceableDesktopSourceOptions);
|
||||
|
||||
logger?.info("Overridden Desktop Source Options", options);
|
||||
|
||||
return Reflect.apply(oldSetDesktopSourceWithOptions, this, [options]);
|
||||
};
|
||||
|
||||
const forceUpdateDesktopSourceOptions = () => {
|
||||
const desktopSourceOptions = lodash.merge({ ...getDefaultVideoDesktopSourceOptions(connection) }, getReplaceableVideoDesktopSourceOptions(get));
|
||||
|
||||
logger?.info("Force Updated Desktop Source Options", desktopSourceOptions);
|
||||
|
||||
oldSetDesktopSourceWithOptions(desktopSourceOptions);
|
||||
};
|
||||
|
||||
return {
|
||||
oldSetDesktopSourceWithOptions,
|
||||
forceUpdateDesktopSourceOptions
|
||||
};
|
||||
}
|
||||
|
||||
export function patchConnectionVideoTransportOptions(
|
||||
connection: types.Connection,
|
||||
get: ProfilableStore<ScreenshareStore, ScreenshareProfile>["get"],
|
||||
logger?: Logger
|
||||
) {
|
||||
const oldSetTransportOptions = connection.conn.setTransportOptions;
|
||||
|
||||
connection.conn.setTransportOptions = function (this: any, options: Record<string, any>) {
|
||||
const replaceableTransportOptions = getReplaceableVideoTransportationOptions(connection, get);
|
||||
|
||||
if (options.streamParameters)
|
||||
connection.videoStreamParameters = Array.isArray(options.streamParameters) ? options.streamParameters : [options.streamParameters];
|
||||
|
||||
replaceObjectValuesIfExist(options, replaceableTransportOptions);
|
||||
|
||||
logger?.info("Overridden Transport Options", options);
|
||||
|
||||
return Reflect.apply(oldSetTransportOptions, this, [options]);
|
||||
};
|
||||
|
||||
const forceUpdateTransportationOptions = () => {
|
||||
const transportOptions = lodash.merge({ ...getDefaultVideoTransportationOptions(connection) }, getReplaceableVideoTransportationOptions(connection, get));
|
||||
|
||||
logger?.info("Force Updated Transport Options", transportOptions);
|
||||
|
||||
oldSetTransportOptions(transportOptions);
|
||||
};
|
||||
|
||||
return {
|
||||
oldSetTransportOptions,
|
||||
forceUpdateTransportationOptions,
|
||||
};
|
||||
}
|
20
src/equicordplugins/philsPluginLibrary/store/index.ts
Normal file
20
src/equicordplugins/philsPluginLibrary/store/index.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./profileable";
|
||||
export * from "./store";
|
85
src/equicordplugins/philsPluginLibrary/store/profileable.ts
Normal file
85
src/equicordplugins/philsPluginLibrary/store/profileable.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { PluginInitializer, PluginSettings, PluginStore } from "./store";
|
||||
|
||||
export interface ProfileableProfile {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ProfileableSettings<T extends PluginSettings = {}, B extends ProfileableProfile & T = T & ProfileableProfile> {
|
||||
currentProfile: B;
|
||||
profiles: B[];
|
||||
setCurrentProfile: (f: ((currentProfile: B) => B | undefined) | B | undefined) => void;
|
||||
getCurrentProfile: () => B;
|
||||
duplicateProfile: (profile: string | B, name: string) => void;
|
||||
deleteProfile: (profile: string | B) => void;
|
||||
saveProfile: (profile: B) => void;
|
||||
getProfile: (profile: string) => B | undefined;
|
||||
getProfiles: (defaultProfiles: boolean) => B[],
|
||||
isCurrentProfileADefaultProfile: () => boolean;
|
||||
getDefaultProfiles: () => B[];
|
||||
}
|
||||
|
||||
export type ProfilableStore<
|
||||
T extends PluginSettings = {},
|
||||
S extends PluginSettings = {}
|
||||
> = PluginStore<T & ProfileableSettings<S>>;
|
||||
|
||||
export type ProfilableMiddleware<
|
||||
T extends PluginSettings = {},
|
||||
S extends PluginSettings = {},
|
||||
B = T & ProfileableSettings<S>
|
||||
> = PluginInitializer<T & ProfileableSettings<S>, B>;
|
||||
|
||||
export type ProfilableInitializer<
|
||||
T extends PluginSettings = {},
|
||||
S extends PluginSettings = {}
|
||||
> = ProfilableMiddleware<T, S, T & Partial<ProfileableSettings<S>>>;
|
||||
|
||||
export function profileable<
|
||||
T extends PluginSettings = {},
|
||||
S extends PluginSettings = {}
|
||||
>(f: ProfilableInitializer<T, S>, defaultProfile: ProfileableProfile & S, defaultProfiles: (ProfileableProfile & S)[] = []): ProfilableMiddleware<T, S> {
|
||||
return (set, get) => ({
|
||||
currentProfile: defaultProfile,
|
||||
profiles: [],
|
||||
getCurrentProfile: () => get().currentProfile,
|
||||
getProfile: profile => [...get().profiles, ...(defaultProfiles ?? [])].find(p => p.name === profile),
|
||||
deleteProfile: profile => get().profiles = get().profiles.filter(p => typeof profile === "string" ? p.name !== profile : p.name !== profile.name),
|
||||
duplicateProfile: (profile, name) => {
|
||||
const foundProfile = get().profiles.find(p => typeof profile === "string" ? p.name === profile : p.name === profile.name);
|
||||
if (foundProfile) {
|
||||
foundProfile.name = name;
|
||||
get().profiles.push(foundProfile);
|
||||
}
|
||||
},
|
||||
setCurrentProfile: f => {
|
||||
const currProfile = get().currentProfile;
|
||||
get().currentProfile = (typeof f === "function" ? f(currProfile) ?? currProfile : f ?? currProfile);
|
||||
},
|
||||
saveProfile: profile => {
|
||||
get().deleteProfile(profile.name);
|
||||
get().profiles.push(profile);
|
||||
},
|
||||
isCurrentProfileADefaultProfile: () => defaultProfiles.some(profile => get().currentProfile.name === profile.name),
|
||||
getDefaultProfiles: () => defaultProfiles,
|
||||
getProfiles: defaultProfiles => [...get().profiles, ...(defaultProfiles ? get().getDefaultProfiles() : [])],
|
||||
...f(set as any, get as any)
|
||||
});
|
||||
}
|
102
src/equicordplugins/philsPluginLibrary/store/store.ts
Normal file
102
src/equicordplugins/philsPluginLibrary/store/store.ts
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
|
||||
export type PluginSettings = {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export type PluginUse<Z extends PluginSettings> = () => Z;
|
||||
export type PluginGet<Z extends PluginSettings> = () => Z;
|
||||
export type PluginSet<Z extends PluginSettings> = (s: Z | ((settings: Z) => Z | undefined)) => Z;
|
||||
export type PluginInitializer<Z extends PluginSettings, T = Z> = (set: PluginSet<Z>, get: PluginGet<Z>) => T;
|
||||
export interface PluginStore<Z extends PluginSettings> {
|
||||
use: PluginUse<Z>,
|
||||
get: PluginGet<Z>,
|
||||
set: PluginSet<Z>;
|
||||
}
|
||||
|
||||
function createObjectProxy<T extends object>(obj1: T, onUpdate: (updatedObject: T) => void): T {
|
||||
const handler: ProxyHandler<T> = {
|
||||
set(target, property, value, receiver) {
|
||||
const success = Reflect.set(target, property, value, receiver);
|
||||
const nestedObj = target[property];
|
||||
|
||||
if (typeof nestedObj === "object") {
|
||||
target[property] = createObjectProxy(nestedObj, () => { onUpdate(obj1); }); // On update will call itself until the top level object
|
||||
}
|
||||
|
||||
onUpdate(obj1); // This will recursively call on nested objects
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
return new Proxy(obj1, handler);
|
||||
}
|
||||
|
||||
|
||||
const startupStates = {};
|
||||
const settingStorage = new Map();
|
||||
export function createPluginStore<Z extends PluginSettings = {}>(pluginName: string, storeName: string, f: PluginInitializer<Z>): PluginStore<Z> {
|
||||
if (!Settings.plugins[pluginName])
|
||||
throw new Error("The specified plugin does not exist");
|
||||
|
||||
if (!Settings.plugins[pluginName].stores)
|
||||
Settings.plugins[pluginName].stores = {};
|
||||
|
||||
if (!Settings.plugins[pluginName].stores[storeName]) // Just incase the store doesn't exist we create it here (otherwise we crash)
|
||||
Settings.plugins[pluginName].stores[storeName] = {};
|
||||
|
||||
const get: PluginGet<Z> = () => {
|
||||
const storeSettings = settingStorage.get(storeName);
|
||||
|
||||
if (!startupStates[storeName]) { // We do this so that we can load all the saved data without the proxy attempting to overwrite it
|
||||
const startupInfo = Settings.plugins[pluginName].stores[storeName];
|
||||
Object.keys(startupInfo).forEach(prop => storeSettings[prop] = startupInfo[prop]);
|
||||
|
||||
startupStates[storeName] = true;
|
||||
}
|
||||
|
||||
return storeSettings;
|
||||
};
|
||||
|
||||
const set: PluginSet<Z> = (s: ((settings: Z) => Z | undefined) | Z) =>
|
||||
(typeof s === "function" ? s(get()) : s) || get();
|
||||
|
||||
const use: PluginUse<Z> = () => { useSettings().plugins[pluginName].stores[storeName]; return get(); }; // useSettings is called to update renderer (after settings change)
|
||||
|
||||
const initialSettings: Z = f(set, get);
|
||||
const proxiedSettings = createObjectProxy(initialSettings as unknown, updateCallback); // Setup our proxy that allows us connections to the datastore
|
||||
|
||||
function updateCallback(updatedObject: any) {
|
||||
if (!startupStates[storeName]) return; // Wait for the startup information to overwrite the blank proxy
|
||||
Settings.plugins[pluginName].stores[storeName] = JSON.parse(JSON.stringify(updatedObject));
|
||||
}
|
||||
|
||||
for (const key of Object.keys(initialSettings)) { proxiedSettings[key] = initialSettings[key]; } // Set them so the nested objects also become proxies
|
||||
settingStorage.set(storeName, proxiedSettings);
|
||||
|
||||
updateCallback(initialSettings);
|
||||
|
||||
return {
|
||||
use,
|
||||
get,
|
||||
set
|
||||
};
|
||||
}
|
19
src/equicordplugins/philsPluginLibrary/styles/index.ts
Normal file
19
src/equicordplugins/philsPluginLibrary/styles/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./styles";
|
25
src/equicordplugins/philsPluginLibrary/styles/styles.ts
Normal file
25
src/equicordplugins/philsPluginLibrary/styles/styles.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export const Styles = {
|
||||
infoCard: {
|
||||
padding: "1em",
|
||||
width: "100%",
|
||||
boxSizing: "border-box"
|
||||
},
|
||||
} as const satisfies Record<string, React.CSSProperties>;
|
46
src/equicordplugins/philsPluginLibrary/types/common/index.ts
Normal file
46
src/equicordplugins/philsPluginLibrary/types/common/index.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface Resolution {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface Framerate {
|
||||
framerate: number;
|
||||
}
|
||||
|
||||
export interface Bitrate {
|
||||
min: number;
|
||||
target: number;
|
||||
max: number;
|
||||
}
|
||||
|
||||
export type DeepPartial<T> = T extends Function
|
||||
? T
|
||||
: T extends Array<infer InferredArrayMember>
|
||||
? DeepPartialArray<InferredArrayMember>
|
||||
: T extends object
|
||||
? DeepPartialObject<T>
|
||||
: T | undefined;
|
||||
|
||||
interface DeepPartialArray<T> extends Array<DeepPartial<T>> { }
|
||||
|
||||
type DeepPartialObject<T> = {
|
||||
[key in keyof T]?: DeepPartial<T[key]>;
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { PluginAuthor } from "@utils/types";
|
||||
|
||||
export type Author = PluginAuthor & { github?: string; };
|
||||
export type Contributor = Author;
|
||||
|
||||
export interface PluginInfo {
|
||||
[key: string]: any;
|
||||
PLUGIN_NAME: string,
|
||||
DESCRIPTION: string,
|
||||
AUTHOR: PluginAuthor & { github?: string; },
|
||||
CONTRIBUTORS?: Record<string, PluginAuthor & { github?: string; }>,
|
||||
README?: string;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./panelClasses";
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface PanelClasses {
|
||||
container: string;
|
||||
inner: string;
|
||||
channel: string;
|
||||
statusWithPopout: string;
|
||||
hotspot: string;
|
||||
customStatusContainer: string;
|
||||
noiseCancellationPopout: string;
|
||||
noiseCancellationTooltip: string;
|
||||
krispLogo: string;
|
||||
krispLink: string;
|
||||
micTestButton: string;
|
||||
beta: string;
|
||||
connection: string;
|
||||
voiceUsers: string;
|
||||
actionButtons: string;
|
||||
button: string;
|
||||
buttonColor: string;
|
||||
buttonActive: string;
|
||||
fauxDisabled: string;
|
||||
buttonDeveloperActivityShelf: string;
|
||||
active: string;
|
||||
buttonContents: string;
|
||||
buttonIcon: string;
|
||||
withText: string;
|
||||
voicePanelIntroductionHeader: string;
|
||||
voicePanelIntroductionText: string;
|
||||
voicePanelIntroductionButton: string;
|
||||
voicePanelIntroductionWrapper: string;
|
||||
wrapper: string;
|
||||
viewAsRolesWarning: string;
|
||||
viewAsRolesWarningText: string;
|
||||
viewAsRolesWarningButton: string;
|
||||
disabled: string;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./userSummaryItem";
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { User } from "discord-types/general";
|
||||
import type { ComponentType } from "react";
|
||||
|
||||
export interface UserSummaryItemProps {
|
||||
guildId?: string;
|
||||
className?: string;
|
||||
users?: User[];
|
||||
renderUser?: (...props: any[]) => any;
|
||||
renderMoreUsers?: (...props: any[]) => any;
|
||||
max?: number;
|
||||
showUserPopout?: boolean;
|
||||
renderIcon?: boolean;
|
||||
showDefaultAvatarsForNullUsers?: boolean;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export type UserSummaryItem = ComponentType<UserSummaryItemProps>;
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./classes";
|
||||
export * from "./components";
|
||||
export * from "./modules";
|
||||
export * from "./stores";
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface Conn {
|
||||
destroy: (...args: any[]) => any;
|
||||
setTransportOptions: (options: Record<string, any>) => any;
|
||||
setSelfMute: (...args: any[]) => any;
|
||||
setSelfDeafen: (...args: any[]) => any;
|
||||
mergeUsers: (...args: any[]) => any;
|
||||
destroyUser: (...args: any[]) => any;
|
||||
setLocalVolume: (...args: any[]) => any;
|
||||
setLocalMute: (...args: any[]) => any;
|
||||
setLocalPan: (...args: any[]) => any;
|
||||
setDisableLocalVideo: (...args: any[]) => any;
|
||||
setMinimumOutputDelay: (...args: any[]) => any;
|
||||
getEncryptionModes: (...args: any[]) => any;
|
||||
configureConnectionRetries: (...args: any[]) => any;
|
||||
setOnSpeakingCallback: (...args: any[]) => any;
|
||||
setOnSpeakingWhileMutedCallback: (...args: any[]) => any;
|
||||
setPingInterval: (...args: any[]) => any;
|
||||
setPingCallback: (...args: any[]) => any;
|
||||
setPingTimeoutCallback: (...args: any[]) => any;
|
||||
setRemoteUserSpeakingStatus: (...args: any[]) => any;
|
||||
setRemoteUserCanHavePriority: (...args: any[]) => any;
|
||||
setOnVideoCallback: (...args: any[]) => any;
|
||||
setVideoBroadcast: (...args: any[]) => any;
|
||||
setDesktopSource: (...args: any[]) => any;
|
||||
setDesktopSourceWithOptions: (...args: any[]) => any;
|
||||
clearDesktopSource: (...args: any[]) => any;
|
||||
setDesktopSourceStatusCallback: (...args: any[]) => any;
|
||||
setOnDesktopSourceEnded: (...args: any[]) => any;
|
||||
setOnSoundshare: (...args: any[]) => any;
|
||||
setOnSoundshareEnded: (...args: any[]) => any;
|
||||
setOnSoundshareFailed: (...args: any[]) => any;
|
||||
setPTTActive: (...args: any[]) => any;
|
||||
getStats: (...args: any[]) => any;
|
||||
getFilteredStats: (...args: any[]) => any;
|
||||
startReplay: (...args: any[]) => any;
|
||||
startSamplesPlayback: (...args: any[]) => any;
|
||||
stopSamplesPlayback: (...args: any[]) => any;
|
||||
}
|
|
@ -0,0 +1,387 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import TypedEmitter from "typed-emitter";
|
||||
|
||||
import { Framerate, Resolution } from "../../../types";
|
||||
import { Conn, FramerateReducer, VideoQualityManager } from "./";
|
||||
|
||||
export const ConnectionEvent = {
|
||||
SPEAKING: "speaking",
|
||||
MUTE: "mute",
|
||||
NEW_LISTENER: "newListener",
|
||||
DESTORY: "destroy",
|
||||
CONNECTED: "connected",
|
||||
SILENCE: "silence",
|
||||
DESKTOP_SOURCE_END: "desktopsourceend",
|
||||
SOUNDSHARE_ATTACHED: "soundshareattached",
|
||||
SOUNDSHARE_FAILED: "soundsharefailed",
|
||||
SOUNDSHARE_SPEAKING: "soundsharespeaking",
|
||||
SOUNDSHARE_TRACE: "soundsharetrace",
|
||||
INTERACTION_REQUIRED: "interactionrequired",
|
||||
VIDEOHOOK_INITIALIZED: "videohook-initialize",
|
||||
SCREENSHARE_FAILED: "screenshare-finish",
|
||||
NOISE_CANCELLER_ERROR: "noisecancellererror",
|
||||
VOICE_ACTIVITY_DETECTOR_ERROR: "voiceactivitydetectorerror",
|
||||
VIDEO_STATE: "video-state",
|
||||
VIDEO: "video",
|
||||
FIRST_FRAME: "first-frame",
|
||||
ERROR: "error",
|
||||
CONNECTION_STATE_CHANGE: "connectionstatechange",
|
||||
PING: "ping",
|
||||
PING_TIMEOUT: "pingtimeout",
|
||||
OUTBOUND_LOSSRATE: "outboundlossrate",
|
||||
LOCAL_VIDEO_DISABLED: "local-video-disabled",
|
||||
STATS: "stats",
|
||||
} as const;
|
||||
|
||||
export type ConnectionEvent = typeof ConnectionEvent;
|
||||
|
||||
export type ConnectionEvents = {
|
||||
[ConnectionEvent.SPEAKING]: (...args: any[]) => any;
|
||||
[ConnectionEvent.MUTE]: (...args: any[]) => any;
|
||||
[ConnectionEvent.NEW_LISTENER]: (...args: any[]) => any;
|
||||
[ConnectionEvent.DESTORY]: (...args: any[]) => any;
|
||||
[ConnectionEvent.CONNECTED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.SILENCE]: (...args: any[]) => any;
|
||||
[ConnectionEvent.DESKTOP_SOURCE_END]: (...args: any[]) => any;
|
||||
[ConnectionEvent.SOUNDSHARE_ATTACHED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.SOUNDSHARE_FAILED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.SOUNDSHARE_SPEAKING]: (...args: any[]) => any;
|
||||
[ConnectionEvent.SOUNDSHARE_TRACE]: (...args: any[]) => any;
|
||||
[ConnectionEvent.INTERACTION_REQUIRED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.VIDEOHOOK_INITIALIZED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.SCREENSHARE_FAILED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.NOISE_CANCELLER_ERROR]: (...args: any[]) => any;
|
||||
[ConnectionEvent.VOICE_ACTIVITY_DETECTOR_ERROR]: (...args: any[]) => any;
|
||||
[ConnectionEvent.VIDEO_STATE]: (...args: any[]) => any;
|
||||
[ConnectionEvent.VIDEO]: (...args: any[]) => any;
|
||||
[ConnectionEvent.FIRST_FRAME]: (...args: any[]) => any;
|
||||
[ConnectionEvent.ERROR]: (...args: any[]) => any;
|
||||
[ConnectionEvent.CONNECTION_STATE_CHANGE]: (...args: any[]) => any;
|
||||
[ConnectionEvent.PING]: (...args: any[]) => any;
|
||||
[ConnectionEvent.PING_TIMEOUT]: (...args: any[]) => any;
|
||||
[ConnectionEvent.OUTBOUND_LOSSRATE]: (...args: any[]) => any;
|
||||
[ConnectionEvent.LOCAL_VIDEO_DISABLED]: (...args: any[]) => any;
|
||||
[ConnectionEvent.STATS]: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
export type Connection = TypedEmitter<ConnectionEvents> &
|
||||
Connection__ &
|
||||
Connection_ & {
|
||||
streamUserId: string,
|
||||
goLiveSourceIdentifier?: string;
|
||||
emitter: TypedEmitter<ConnectionEvents>;
|
||||
mediaEngineConnectionId: string;
|
||||
destroyed: boolean;
|
||||
audioSSRC: number;
|
||||
selfDeaf: boolean;
|
||||
localMutes: LocalMutes;
|
||||
disabledLocalVideos: LocalMutes;
|
||||
localVolumes: LocalVolumes;
|
||||
isActiveOutputSinksEnabled: boolean;
|
||||
activeOutputSinks: LocalMutes;
|
||||
videoSupported: boolean;
|
||||
useElectronVideo: boolean;
|
||||
voiceBitrate: number;
|
||||
remoteSinkWantsMaxFramerate: number;
|
||||
wantsPriority: Set<any>;
|
||||
localSpeakingFlags: LocalSpeakingFlags;
|
||||
videoReady: boolean;
|
||||
videoStreamParameters: VideoStreamParameter[];
|
||||
remoteVideoSinkWants: VideoSinkWants;
|
||||
localVideoSinkWants: VideoSinkWants;
|
||||
connectionState: string;
|
||||
experimentFlags: string[];
|
||||
context: string;
|
||||
ids: Ids;
|
||||
selfMute: boolean;
|
||||
selfVideo: boolean;
|
||||
forceAudioNormal: boolean;
|
||||
forceAudioPriority: boolean;
|
||||
codecs: Codec[];
|
||||
desktopDegradationPreference: number;
|
||||
sourceDesktopDegradationPreference: number;
|
||||
videoDegradationPreference: number;
|
||||
localPans: LocalMutes;
|
||||
remoteAudioSSRCs: LocalMutes;
|
||||
remoteVideoSSRCs: LocalMutes;
|
||||
inputMode: string;
|
||||
vadThreshold: number;
|
||||
vadAutoThreshold: boolean;
|
||||
vadUseKrisp: boolean;
|
||||
vadLeading: number;
|
||||
vadTrailing: number;
|
||||
pttReleaseDelay: number;
|
||||
soundshareActive: boolean;
|
||||
soundshareId?: any;
|
||||
soundshareSentSpeakingEvent: boolean;
|
||||
echoCancellation: boolean;
|
||||
noiseSuppression: boolean;
|
||||
automaticGainControl: boolean;
|
||||
noiseCancellation: boolean;
|
||||
experimentalEncoders: boolean;
|
||||
hardwareH264: boolean;
|
||||
attenuationFactor: number;
|
||||
attenuateWhileSpeakingSelf: boolean;
|
||||
attenuateWhileSpeakingOthers: boolean;
|
||||
qos: boolean;
|
||||
minimumJitterBufferLevel: number;
|
||||
postponeDecodeLevel: number;
|
||||
reconnectInterval: number;
|
||||
keyframeInterval: number;
|
||||
conn: Conn;
|
||||
stats: Stats;
|
||||
framerateReducer: FramerateReducer;
|
||||
videoQualityManager: VideoQualityManager;
|
||||
handleSpeakingNative: (...args: any[]) => any;
|
||||
handleSpeakingFlags: (...args: any[]) => any;
|
||||
handleSpeakingWhileMuted: (...args: any[]) => any;
|
||||
handlePing: (...args: any[]) => any;
|
||||
handlePingTimeout: (...args: any[]) => any;
|
||||
handleVideo: (...args: any[]) => any;
|
||||
handleFirstFrame: (...args: any[]) => any;
|
||||
handleNoInput: (...args: any[]) => any;
|
||||
handleDesktopSourceEnded: (...args: any[]) => any;
|
||||
handleSoundshare: (...args: any[]) => any;
|
||||
handleSoundshareFailed: (...args: any[]) => any;
|
||||
handleSoundshareEnded: (...args: any[]) => any;
|
||||
handleNewListenerNative: (...args: any[]) => any;
|
||||
handleStats: (...args: any[]) => any;
|
||||
__proto__: Connection_;
|
||||
};
|
||||
|
||||
interface Connection_ {
|
||||
initialize: (...args: any[]) => any;
|
||||
destroy: (...args: any[]) => any;
|
||||
setCodecs: (audioCodec: string, videoCodec: string, context: string) => any;
|
||||
getStats: (...args: any[]) => any;
|
||||
createUser: (...args: any[]) => any;
|
||||
destroyUser: (...args: any[]) => any;
|
||||
setSelfMute: (...args: any[]) => any;
|
||||
setSelfDeaf: (...args: any[]) => any;
|
||||
setSoundshareSource: (id: number, loopback: boolean) => void;
|
||||
setLocalMute: (...args: any[]) => any;
|
||||
setLocalVideoDisabled: (...args: any[]) => any;
|
||||
setMinimumJitterBufferLevel: (...args: any[]) => any;
|
||||
setPostponeDecodeLevel: (...args: any[]) => any;
|
||||
setClipRecordSsrc: (...args: any[]) => any;
|
||||
getLocalVolume: (...args: any[]) => any;
|
||||
setLocalVolume: (...args: any[]) => any;
|
||||
setLocalPan: (...args: any[]) => any;
|
||||
isAttenuating: (...args: any[]) => any;
|
||||
setAttenuation: (...args: any[]) => any;
|
||||
setCanHavePriority: (...args: any[]) => any;
|
||||
setBitRate: (...args: any[]) => any;
|
||||
setVoiceBitRate: (target: number) => void;
|
||||
setCameraBitRate: (target: number, min: number, max: number) => void;
|
||||
setEchoCancellation: (...args: any[]) => any;
|
||||
setNoiseSuppression: (...args: any[]) => any;
|
||||
setAutomaticGainControl: (...args: any[]) => any;
|
||||
setNoiseCancellation: (...args: any[]) => any;
|
||||
setExperimentalEncoders: (...args: any[]) => any;
|
||||
setHardwareH264: (...args: any[]) => any;
|
||||
setQoS: (...args: any[]) => any;
|
||||
setInputMode: (...args: any[]) => any;
|
||||
setSilenceThreshold: (...args: any[]) => any;
|
||||
setForceAudioInput: (...args: any[]) => any;
|
||||
setSpeakingFlags: (...args: any[]) => any;
|
||||
clearAllSpeaking: (...args: any[]) => any;
|
||||
setEncryption: (...args: any[]) => any;
|
||||
setReconnectInterval: (...args: any[]) => any;
|
||||
setKeyframeInterval: (keyframeInterval: number) => void;
|
||||
setVideoBroadcast: (...args: any[]) => any;
|
||||
setDesktopSource: (
|
||||
source: string | null,
|
||||
options?: DesktopSourceOptions
|
||||
) => void;
|
||||
clearDesktopSource: (...args: any[]) => any;
|
||||
setDesktopSourceStatusCallback: (...args: any[]) => any;
|
||||
hasDesktopSource: (...args: any[]) => any;
|
||||
setDesktopEncodingOptions: (
|
||||
width: number,
|
||||
height: number,
|
||||
framerate: number
|
||||
) => void;
|
||||
setSDP: (...args: any[]) => any;
|
||||
setRemoteVideoSinkWants: (...args: any[]) => any;
|
||||
setLocalVideoSinkWants: (...args: any[]) => any;
|
||||
startSamplesPlayback: (...args: any[]) => any;
|
||||
stopSamplesPlayback: (...args: any[]) => any;
|
||||
startSamplesLocalPlayback: (...args: any[]) => any;
|
||||
stopAllSamplesLocalPlayback: (...args: any[]) => any;
|
||||
stopSamplesLocalPlayback: (...args: any[]) => any;
|
||||
updateVideoQualityCore: (...args: any[]) => any;
|
||||
setStreamParameters: (...args: any[]) => any;
|
||||
applyVideoTransportOptions: (...args: any[]) => any;
|
||||
chooseEncryptionMode: (...args: any[]) => any;
|
||||
getUserOptions: (...args: any[]) => any;
|
||||
createInputModeOptions: (...args: any[]) => any;
|
||||
getAttenuationOptions: (...args: any[]) => any;
|
||||
getCodecParams: (...args: any[]) => any;
|
||||
getCodecOptions: (...args: any[]) => any;
|
||||
getConnectionTransportOptions: (...args: any[]) => any;
|
||||
setStream: (...args: any[]) => any;
|
||||
getUserIdBySsrc: (...args: any[]) => any;
|
||||
setRtcLogEphemeralKey: (...args: any[]) => any;
|
||||
setRtcLogMarker: (...args: any[]) => any;
|
||||
__proto__: Connection__;
|
||||
}
|
||||
|
||||
interface Connection__ {
|
||||
destroy: (...args: any[]) => any;
|
||||
getLocalMute: (...args: any[]) => any;
|
||||
getLocalVideoDisabled: (...args: any[]) => any;
|
||||
setLocalVideoDisabled: (...args: any[]) => any;
|
||||
getHasActiveVideoOutputSink: (...args: any[]) => any;
|
||||
setHasActiveVideoOutputSink: (...args: any[]) => any;
|
||||
getActiveOutputSinkTrackingEnabled: (...args: any[]) => any;
|
||||
setUseElectronVideo: (...args: any[]) => any;
|
||||
setClipRecordSsrc: (...args: any[]) => any;
|
||||
getStreamParameters: (...args: any[]) => any;
|
||||
setExperimentFlag: (...args: any[]) => any;
|
||||
setConnectionState: (...args: any[]) => any;
|
||||
updateVideoQuality: (...args: any[]) => any;
|
||||
applyVideoQualityMode: (...args: any[]) => any;
|
||||
overwriteQualityForTesting: (args: {
|
||||
encode: Resolution & Framerate;
|
||||
capture: Resolution & Framerate;
|
||||
bitrateMin: number;
|
||||
bitrateMax: number;
|
||||
bitrateTarget: number;
|
||||
}) => any;
|
||||
applyQualityConstraints: (...args: any[]) => any;
|
||||
pickProperties: (...args: any[]) => any;
|
||||
initializeStreamParameters: (...args: any[]) => any;
|
||||
getLocalWant: (...args: any[]) => any;
|
||||
emitStats: (...args: any[]) => any;
|
||||
__proto__: TypedEmitter<ConnectionEvents>;
|
||||
}
|
||||
|
||||
export interface Stats {
|
||||
mediaEngineConnectionId: string;
|
||||
transport: Transport;
|
||||
camera?: any;
|
||||
rtp: Rtp;
|
||||
}
|
||||
|
||||
export interface Rtp {
|
||||
inbound: LocalMutes;
|
||||
outbound: Outbound[];
|
||||
}
|
||||
|
||||
export interface Outbound {
|
||||
type: string;
|
||||
ssrc: number;
|
||||
sinkWant: string;
|
||||
codec: OutboundCodec;
|
||||
bytesSent: number;
|
||||
packetsSent: number;
|
||||
packetsLost: number;
|
||||
fractionLost: number;
|
||||
audioLevel: number;
|
||||
audioDetected: number;
|
||||
framesCaptured: number;
|
||||
framesRendered: number;
|
||||
noiseCancellerProcessTime: number;
|
||||
}
|
||||
|
||||
export interface OutboundCodec {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Transport {
|
||||
availableOutgoingBitrate: number;
|
||||
ping: number;
|
||||
decryptionFailures: number;
|
||||
routingFailures: number;
|
||||
localAddress: string;
|
||||
pacerDelay: number;
|
||||
receiverReports: any[];
|
||||
receiverBitrateEstimate: number;
|
||||
outboundBitrateEstimate: number;
|
||||
inboundBitrateEstimate: number;
|
||||
bytesSent: number;
|
||||
}
|
||||
|
||||
export interface Codec {
|
||||
type: string;
|
||||
name: string;
|
||||
priority: number;
|
||||
payloadType: number;
|
||||
rtxPayloadType?: number;
|
||||
encode?: boolean;
|
||||
decode?: boolean;
|
||||
}
|
||||
|
||||
export interface Ids {
|
||||
userId: string;
|
||||
channelId: string;
|
||||
guildId: string;
|
||||
}
|
||||
|
||||
export interface VideoSinkWants {
|
||||
any: number;
|
||||
}
|
||||
|
||||
export interface VideoStreamParameter {
|
||||
type: string;
|
||||
active: boolean;
|
||||
rid: string;
|
||||
ssrc: number;
|
||||
rtxSsrc: number;
|
||||
quality: number;
|
||||
maxBitrate: number;
|
||||
maxFrameRate: number;
|
||||
maxResolution: MaxResolution;
|
||||
maxPixelCount: number;
|
||||
}
|
||||
|
||||
export type MaxResolution = Partial<Resolution> & {
|
||||
type: "fixed" | "source";
|
||||
};
|
||||
|
||||
export interface LocalSpeakingFlags {
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
export interface LocalVolumes {
|
||||
[key: string]: number;
|
||||
}
|
||||
|
||||
export interface LocalMutes {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export const HdrCaptureMode = {
|
||||
NEVER: "never",
|
||||
ALWAYS: "always",
|
||||
PERMITTED_DEVICES_ONLY: "permittedDevicesOnly",
|
||||
} as const;
|
||||
|
||||
export type HdrCaptureMode = typeof HdrCaptureMode;
|
||||
|
||||
export interface DesktopSourceOptions extends Partial<Resolution> {
|
||||
fps?: number;
|
||||
useVideoHook?: boolean;
|
||||
useGraphicsCapture?: boolean;
|
||||
useQuartzCapturer?: boolean;
|
||||
allowScreenCaptureKit?: boolean;
|
||||
hdrCaptureMode?: HdrCaptureMode[keyof HdrCaptureMode];
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Connection, VideoQualityManager } from "./";
|
||||
|
||||
export type FramerateReducer = FramerateReducer_ & {
|
||||
connection: Connection;
|
||||
sinkWants: VideoQualityManager;
|
||||
framerateReductionTimeout?: number;
|
||||
handleSelfMute: (...args: any[]) => any;
|
||||
handleSpeaking: (...args: any[]) => any;
|
||||
__proto__: FramerateReducer_;
|
||||
};
|
||||
|
||||
export interface FramerateReducer_ {
|
||||
destroy: (...args: any[]) => any;
|
||||
destroyFramerateScaleFactorTimers: (...args: any[]) => any;
|
||||
initialize: (...args: any[]) => any;
|
||||
updateRemoteWantsFramerate: (...args: any[]) => any;
|
||||
userSpeakingChange: (...args: any[]) => any;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./conn";
|
||||
export * from "./connection";
|
||||
export * from "./framerateReducer";
|
||||
export * from "./mediaEngine";
|
||||
export * from "./utils";
|
||||
export * from "./videoQualityManager";
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import TypedEmitter from "typed-emitter";
|
||||
|
||||
import { Connection } from "./";
|
||||
|
||||
export const MediaEngineEvent = {
|
||||
REMOVE_LISTENER: "removeListener",
|
||||
NEW_LISTENER: "newListener",
|
||||
DESTORY: "destroy",
|
||||
CONNECTION: "connection",
|
||||
DEVICE_CHANGE: "devicechange",
|
||||
VOLUME_CHANGE: "volumechange",
|
||||
DESKTOP_SOURCE_END: "desktopsourceend",
|
||||
AUDIO_PERMISSION: "audio-permission",
|
||||
VIDEO_PERMISSION: "video-permission",
|
||||
WATCHDOG_TIMEOUT: "watchdogtimeout",
|
||||
VIDEO_INPUT_INITIALIZED: "video-input-initialized",
|
||||
CONNECTION_STATS: "connection-stats",
|
||||
} as const;
|
||||
|
||||
export type MediaEngineEvents = {
|
||||
[MediaEngineEvent.REMOVE_LISTENER]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.NEW_LISTENER]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.DESTORY]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.CONNECTION]: (connection: Connection) => void;
|
||||
[MediaEngineEvent.DEVICE_CHANGE]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.VOLUME_CHANGE]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.DESKTOP_SOURCE_END]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.AUDIO_PERMISSION]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.VIDEO_PERMISSION]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.WATCHDOG_TIMEOUT]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.VIDEO_INPUT_INITIALIZED]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.CONNECTION_STATS]: (...args: any[]) => any;
|
||||
[MediaEngineEvent.REMOVE_LISTENER]: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
export type MediaEngine = TypedEmitter<MediaEngineEvents> &
|
||||
MediaEngine_ & {
|
||||
Video: (...args: any[]) => any;
|
||||
Camera: (...args: any[]) => any;
|
||||
handleDeviceChange: (...args: any[]) => any;
|
||||
handleVolumeChange: (...args: any[]) => any;
|
||||
handleVoiceActivity: (...args: any[]) => any;
|
||||
handleActiveSinksChange: (...args: any[]) => any;
|
||||
handleNewListener: (...args: any[]) => any;
|
||||
handleRemoveListener: (...args: any[]) => any;
|
||||
handleVideoInputInitialization: (...args: any[]) => any;
|
||||
emitter: TypedEmitter<MediaEngineEvents>;
|
||||
videoInputDeviceId: string;
|
||||
lastVoiceActivity: number;
|
||||
audioSubsystem: string;
|
||||
audioLayer: string;
|
||||
loopback: boolean;
|
||||
deviceChangeGeneration: number;
|
||||
consecutiveWatchdogFailures: number;
|
||||
codecSurvey?: any;
|
||||
connections: Set<Connection>;
|
||||
__proto__: MediaEngine_;
|
||||
};
|
||||
|
||||
export interface MediaEngine_ {
|
||||
destroy: (...args: any[]) => any;
|
||||
interact: (...args: any[]) => any;
|
||||
supported: (...args: any[]) => any;
|
||||
supports: (...args: any[]) => any;
|
||||
connect: (...args: any[]) => any;
|
||||
shouldConnectionBroadcastVideo: (...args: any[]) => any;
|
||||
eachConnection: (callback: (connection: Connection) => void) => void;
|
||||
enable: (...args: any[]) => any;
|
||||
setInputVolume: (...args: any[]) => any;
|
||||
setOutputVolume: (...args: any[]) => any;
|
||||
getAudioInputDevices: (...args: any[]) => any;
|
||||
setAudioInputDevice: (...args: any[]) => any;
|
||||
getAudioOutputDevices: (...args: any[]) => any;
|
||||
setAudioOutputDevice: (...args: any[]) => any;
|
||||
getVideoInputDevices: (...args: any[]) => any;
|
||||
setVideoInputDevice: (...args: any[]) => any;
|
||||
getSupportedVideoCodecs: (...args: any[]) => any;
|
||||
getCodecCapabilities: (callback: (codecs: string) => void) => void;
|
||||
setDesktopSource: (...args: any[]) => any;
|
||||
setSoundshareSource: (...args: any[]) => any;
|
||||
getDesktopSource: (...args: any[]) => any;
|
||||
getDesktopSources: (...args: any[]) => any;
|
||||
getScreenPreviews: (...args: any[]) => any;
|
||||
setClipBufferLength: (...args: any[]) => any;
|
||||
saveClip: (...args: any[]) => any;
|
||||
updateClipMetadata: (...args: any[]) => any;
|
||||
exportClip: (...args: any[]) => any;
|
||||
getWindowPreviews: (
|
||||
width: number,
|
||||
height: number
|
||||
) => Promise<WindowPreview[]>;
|
||||
setAudioSubsystem: (...args: any[]) => any;
|
||||
getAudioSubsystem: (...args: any[]) => any;
|
||||
getAudioLayer: (...args: any[]) => any;
|
||||
getDebugLogging: (...args: any[]) => any;
|
||||
setDebugLogging: (...args: any[]) => any;
|
||||
setExperimentalAdm: (...args: any[]) => any;
|
||||
setLoopback: (...args: any[]) => any;
|
||||
getLoopback: (...args: any[]) => any;
|
||||
setH264Enabled: (...args: any[]) => any;
|
||||
setAv1Enabled: (...args: any[]) => any;
|
||||
getCodecSurvey: () => Promise<string>;
|
||||
writeAudioDebugState: (...args: any[]) => any;
|
||||
startAecDump: (...args: any[]) => any;
|
||||
stopAecDump: (...args: any[]) => any;
|
||||
setAecDump: (...args: any[]) => any;
|
||||
rankRtcRegions: (...args: any[]) => any;
|
||||
getSoundshareStatus: (...args: any[]) => any;
|
||||
enableSoundshare: (...args: any[]) => any;
|
||||
createReplayConnection: (...args: any[]) => any;
|
||||
setUseDirectVideo: (...args: any[]) => any;
|
||||
setMaxSyncDelayOverride: (...args: any[]) => any;
|
||||
applyMediaFilterSettings: (...args: any[]) => any;
|
||||
startLocalAudioRecording: (...args: any[]) => any;
|
||||
stopLocalAudioRecording: (...args: any[]) => any;
|
||||
watchdogTick: (...args: any[]) => any;
|
||||
__proto__: TypedEmitter<MediaEngineEvents>;
|
||||
}
|
||||
|
||||
export interface CodecCapabilities {
|
||||
codec: string;
|
||||
decode: boolean;
|
||||
encode: boolean;
|
||||
}
|
||||
|
||||
export interface WindowPreview {
|
||||
id: string;
|
||||
url: string;
|
||||
name: string;
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export interface Utils {
|
||||
requireModule: (...args: any[]) => any;
|
||||
ensureModule: (...args: any[]) => any;
|
||||
getCrashReporterMetadata: (...args: any[]) => any;
|
||||
getSetting: (...args: any[]) => any;
|
||||
beforeUnload: (...args: any[]) => any;
|
||||
inputEventRegister: (...args: any[]) => any;
|
||||
inputEventUnregister: (...args: any[]) => any;
|
||||
setOnInputEventCallback: (...args: any[]) => any;
|
||||
setFocused: (...args: any[]) => any;
|
||||
getIdleMilliseconds: (...args: any[]) => any;
|
||||
setObservedGamesCallback: (...args: any[]) => any;
|
||||
setCandidateGamesCallback: (...args: any[]) => any;
|
||||
clearCandidateGamesCallback: (...args: any[]) => any;
|
||||
setGameCandidateOverrides: (...args: any[]) => any;
|
||||
detectPid: (...args: any[]) => any;
|
||||
undetectPid: (...args: any[]) => any;
|
||||
shouldDisplayNotifications: (...args: any[]) => any;
|
||||
getVoiceEngine: (...args: any[]) => any;
|
||||
getDiscordUtils: (...args: any[]) => any;
|
||||
isSystemDarkMode: (...args: any[]) => any;
|
||||
getGameUtils: (...args: any[]) => any;
|
||||
getCloudSync: (...args: any[]) => any;
|
||||
getDispatch: (...args: any[]) => any;
|
||||
setBadge: (...args: any[]) => any;
|
||||
setSystemTrayIcon: (...args: any[]) => any;
|
||||
setThumbarButtons: (...args: any[]) => any;
|
||||
bounceDock: (...args: any[]) => any;
|
||||
setSystemTrayApplications: (...args: any[]) => any;
|
||||
architecture: (...args: any[]) => any;
|
||||
moduleVersions: (...args: any[]) => any;
|
||||
copy: (...args: any[]) => any;
|
||||
copyImage: (...args: any[]) => any;
|
||||
saveImage: (...args: any[]) => any;
|
||||
saveFile: (...args: any[]) => any;
|
||||
canCopyImage: (...args: any[]) => any;
|
||||
cut: (...args: any[]) => any;
|
||||
paste: (...args: any[]) => any;
|
||||
readClipboard: (...args: any[]) => any;
|
||||
on: (...args: any[]) => any;
|
||||
invoke: (...args: any[]) => any;
|
||||
send: (...args: any[]) => any;
|
||||
flashFrame: (...args: any[]) => any;
|
||||
minimize: (...args: any[]) => any;
|
||||
restore: (...args: any[]) => any;
|
||||
maximize: (...args: any[]) => any;
|
||||
focus: (...args: any[]) => any;
|
||||
blur: (...args: any[]) => any;
|
||||
fullscreen: (...args: any[]) => any;
|
||||
close: (...args: any[]) => any;
|
||||
setAlwaysOnTop: (...args: any[]) => any;
|
||||
isAlwaysOnTop: (...args: any[]) => any;
|
||||
purgeMemory: (...args: any[]) => any;
|
||||
updateCrashReporter: (...args: any[]) => any;
|
||||
flushDNSCache: (...args: any[]) => any;
|
||||
supportsFeature: (...args: any[]) => any;
|
||||
getEnableHardwareAcceleration: (...args: any[]) => any;
|
||||
setEnableHardwareAcceleration: (...args: any[]) => any;
|
||||
getGPUDriverVersions: (...args: any[]) => any;
|
||||
setZoomFactor: (...args: any[]) => any;
|
||||
setBackgroundThrottling: (...args: any[]) => any;
|
||||
getPidFromDesktopSource: (...args: any[]) => any;
|
||||
getDesktopSourceFromPid: (...args: any[]) => any;
|
||||
generateSessionFromPid: (...args: any[]) => any;
|
||||
getAudioPid: (...args: any[]) => any;
|
||||
setForegroundProcess: (...args: any[]) => any;
|
||||
getDiscordMemoryUsage: (...args: any[]) => any;
|
||||
showOpenDialog: (...args: any[]) => any;
|
||||
flushStorageData: (...args: any[]) => any;
|
||||
flushCookies: (...args: any[]) => any;
|
||||
setCrashInformation: (...args: any[]) => any;
|
||||
blockDisplaySleep: (...args: any[]) => any;
|
||||
unblockDisplaySleep: (...args: any[]) => any;
|
||||
cleanupDisplaySleep: (...args: any[]) => any;
|
||||
relaunch: (...args: any[]) => any;
|
||||
makeChunkedRequest: (...args: any[]) => any;
|
||||
submitLiveCrashReport: (...args: any[]) => any;
|
||||
crash: (...args: any[]) => any;
|
||||
setApplicationBackgroundColor: (...args: any[]) => any;
|
||||
asyncify: (...args: any[]) => any;
|
||||
releaseChannel: string,
|
||||
canBootstrapNewUpdater: boolean;
|
||||
buildNumber: number;
|
||||
version: number[];
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Bitrate, Framerate, Resolution } from "../../";
|
||||
import { Connection } from "./";
|
||||
|
||||
export type VideoQualityManager = VideoQualityManager_ & {
|
||||
connection: Connection;
|
||||
contextType: string;
|
||||
isMuted: boolean;
|
||||
isStreamContext: boolean;
|
||||
ladder: Ladder;
|
||||
options: Options;
|
||||
qualityOverwrite: QualityOverwrite;
|
||||
__proto__: VideoQualityManager_;
|
||||
};
|
||||
|
||||
export interface VideoQualityManager_ {
|
||||
applyQualityConstraints: (...args: any[]) => any;
|
||||
getDesktopQuality: (...args: any[]) => any;
|
||||
getQuality: (...args: any[]) => any;
|
||||
getVideoQuality: (...args: any[]) => any;
|
||||
setQuality: (...args: any[]) => any;
|
||||
}
|
||||
|
||||
export interface QualityOverwrite {
|
||||
bitrateMax?: number;
|
||||
bitrateMin?: number;
|
||||
bitrateTarget?: number;
|
||||
capture?: Resolution & Framerate;
|
||||
encode?: Resolution & Framerate;
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
videoBudget: VideoBudget;
|
||||
videoCapture: VideoBudget;
|
||||
videoBitrate: VideoBitrate;
|
||||
desktopBitrate: DesktopBitrate;
|
||||
videoBitrateFloor: number;
|
||||
}
|
||||
|
||||
export type DesktopBitrate = Bitrate;
|
||||
|
||||
export type VideoBitrate = Omit<Bitrate, "target">;
|
||||
|
||||
export type VideoBudget = Resolution & Framerate;
|
||||
|
||||
export interface Ladder {
|
||||
pixelBudget: number;
|
||||
ladder: {
|
||||
[key: number]: LadderValue;
|
||||
};
|
||||
orderedLadder: OrderedLadder[];
|
||||
}
|
||||
|
||||
export interface OrderedLadder extends Resolution, Framerate {
|
||||
pixelCount: number;
|
||||
wantValue: number;
|
||||
budgetPortion: number;
|
||||
mutedFramerate: Framerate;
|
||||
}
|
||||
|
||||
export interface LadderValue extends Resolution, Framerate {
|
||||
budgetPortion: number;
|
||||
mutedFramerate: Framerate;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./mediaEngineStore";
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { types } from "../../..";
|
||||
|
||||
export type MediaEngineStore = MediaEngineStore__ &
|
||||
MediaEngineStore_ & {
|
||||
__proto__: MediaEngineStore_;
|
||||
};
|
||||
|
||||
export interface MediaEngineStore_ {
|
||||
initialize: (...args: any[]) => any;
|
||||
supports: (...args: any[]) => any;
|
||||
supportsInApp: (...args: any[]) => any;
|
||||
isSupported: (...args: any[]) => any;
|
||||
isExperimentalEncodersSupported: (...args: any[]) => any;
|
||||
isNoiseSuppressionSupported: (...args: any[]) => any;
|
||||
isNoiseCancellationSupported: (...args: any[]) => any;
|
||||
isNoiseCancellationError: (...args: any[]) => any;
|
||||
isAutomaticGainControlSupported: (...args: any[]) => any;
|
||||
isAdvancedVoiceActivitySupported: (...args: any[]) => any;
|
||||
isAecDumpSupported: (...args: any[]) => any;
|
||||
isSimulcastSupported: (...args: any[]) => any;
|
||||
getAecDump: (...args: any[]) => any;
|
||||
getMediaEngine: () => types.MediaEngine;
|
||||
getVideoComponent: (...args: any[]) => any;
|
||||
getCameraComponent: (...args: any[]) => any;
|
||||
isEnabled: (...args: any[]) => any;
|
||||
isMute: (...args: any[]) => any;
|
||||
isDeaf: (...args: any[]) => any;
|
||||
hasContext: (...args: any[]) => any;
|
||||
isSelfMutedTemporarily: (...args: any[]) => any;
|
||||
isSelfMute: (...args: any[]) => any;
|
||||
isHardwareMute: (...args: any[]) => any;
|
||||
isSelfDeaf: (...args: any[]) => any;
|
||||
isVideoEnabled: (...args: any[]) => any;
|
||||
isVideoAvailable: (...args: any[]) => any;
|
||||
isScreenSharing: (...args: any[]) => any;
|
||||
isSoundSharing: (...args: any[]) => any;
|
||||
isLocalMute: (...args: any[]) => any;
|
||||
supportsDisableLocalVideo: (...args: any[]) => any;
|
||||
isLocalVideoDisabled: (...args: any[]) => any;
|
||||
isLocalVideoAutoDisabled: (...args: any[]) => any;
|
||||
isMediaFilterSettingLoading: (...args: any[]) => any;
|
||||
isNativeAudioPermissionReady: (...args: any[]) => any;
|
||||
getDesktopSource: (...args: any[]) => any;
|
||||
getDesktopSourceContext: (...args: any[]) => any;
|
||||
getLocalPan: (...args: any[]) => any;
|
||||
getLocalVolume: (...args: any[]) => any;
|
||||
getInputVolume: (...args: any[]) => any;
|
||||
getOutputVolume: (...args: any[]) => any;
|
||||
getMode: (...args: any[]) => any;
|
||||
getModeOptions: (...args: any[]) => any;
|
||||
getShortcuts: (...args: any[]) => any;
|
||||
getInputDeviceId: (...args: any[]) => any;
|
||||
getOutputDeviceId: (...args: any[]) => any;
|
||||
getVideoDeviceId: (...args: any[]) => any;
|
||||
getInputDevices: (...args: any[]) => any;
|
||||
getOutputDevices: (...args: any[]) => any;
|
||||
getVideoDevices: (...args: any[]) => any;
|
||||
getEchoCancellation: (...args: any[]) => any;
|
||||
getLoopback: (...args: any[]) => any;
|
||||
getNoiseSuppression: (...args: any[]) => any;
|
||||
getAutomaticGainControl: (...args: any[]) => any;
|
||||
getNoiseCancellation: (...args: any[]) => any;
|
||||
getExperimentalEncoders: (...args: any[]) => any;
|
||||
getHardwareH264: (...args: any[]) => any;
|
||||
getEnableSilenceWarning: (...args: any[]) => any;
|
||||
getDebugLogging: (...args: any[]) => any;
|
||||
getQoS: (...args: any[]) => any;
|
||||
getAttenuation: (...args: any[]) => any;
|
||||
getAttenuateWhileSpeakingSelf: (...args: any[]) => any;
|
||||
getAttenuateWhileSpeakingOthers: (...args: any[]) => any;
|
||||
getAudioSubsystem: (...args: any[]) => any;
|
||||
getSettings: (...args: any[]) => any;
|
||||
getState: (...args: any[]) => any;
|
||||
getInputDetected: (...args: any[]) => any;
|
||||
getNoInputDetectedNotice: (...args: any[]) => any;
|
||||
getPacketDelay: (...args: any[]) => any;
|
||||
setCanHavePriority: (...args: any[]) => any;
|
||||
isInteractionRequired: (...args: any[]) => any;
|
||||
getVideoHook: (...args: any[]) => any;
|
||||
getExperimentalSoundshare: (...args: any[]) => any;
|
||||
supportsExperimentalSoundshare: (...args: any[]) => any;
|
||||
getOpenH264: (...args: any[]) => any;
|
||||
getAv1Enabled: (...args: any[]) => any;
|
||||
getEverSpeakingWhileMuted: (...args: any[]) => any;
|
||||
getSoundshareEnabled: (...args: any[]) => any;
|
||||
supportsEnableSoundshare: (...args: any[]) => any;
|
||||
getVideoStreamParameters: (...args: any[]) => any;
|
||||
__proto__: MediaEngineStore__;
|
||||
}
|
||||
|
||||
export interface MediaEngineStore__ {
|
||||
registerActionHandlers: (...args: any[]) => any;
|
||||
getName: (...args: any[]) => any;
|
||||
initializeIfNeeded: (...args: any[]) => any;
|
||||
initialize: (...args: any[]) => any;
|
||||
syncWith: (...args: any[]) => any;
|
||||
waitFor: (...args: any[]) => any;
|
||||
emitChange: (...args: any[]) => any;
|
||||
getDispatchToken: (...args: any[]) => any;
|
||||
mustEmitChanges: (...args: any[]) => any;
|
||||
}
|
21
src/equicordplugins/philsPluginLibrary/types/index.ts
Normal file
21
src/equicordplugins/philsPluginLibrary/types/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./common";
|
||||
export * from "./constants";
|
||||
export * from "./discordModules";
|
19
src/equicordplugins/philsPluginLibrary/utils/index.ts
Normal file
19
src/equicordplugins/philsPluginLibrary/utils/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
export * from "./utils";
|
27
src/equicordplugins/philsPluginLibrary/utils/utils.ts
Normal file
27
src/equicordplugins/philsPluginLibrary/utils/utils.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Vencord, a modification for Discord's desktop app
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { UserStore } from "@webpack/common";
|
||||
import { User } from "discord-types/general";
|
||||
|
||||
export const createDummyUser = (props: Partial<User>) => new (UserStore.getCurrentUser().constructor as any)(props);
|
||||
export const openURL = (url: string) => VencordNative.native.openExternal(url);
|
||||
export const validateNumberInput = (value: string) => parseInt(value) ? parseInt(value) : undefined;
|
||||
export const validateTextInputNumber = (value: string) => /^[0-9\b]+$/.test(value) || value === "";
|
||||
export const replaceObjectValuesIfExist =
|
||||
(target: Object, replace: Object) => Object.entries(target).forEach(([key, value]) => replace[key] && (target[key] = replace[key]));
|
|
@ -88,7 +88,7 @@ export const userContextPatch: NavContextMenuPatchCallback = (children, { user }
|
|||
export default definePlugin({
|
||||
name: "BiggerStreamPreview",
|
||||
description: "This plugin allows you to enlarge stream previews",
|
||||
authors: [Devs.phil],
|
||||
authors: [Devs.philhk],
|
||||
contextMenus: {
|
||||
"user-context": userContextPatch,
|
||||
"stream-context": streamContextPatch
|
||||
|
|
|
@ -320,8 +320,8 @@ export const Devs = /* #__PURE__*/ Object.freeze({
|
|||
name: "amia",
|
||||
id: 142007603549962240n
|
||||
},
|
||||
phil: {
|
||||
name: "phil",
|
||||
philhk: {
|
||||
name: "philhk",
|
||||
id: 305288513941667851n
|
||||
},
|
||||
ImLvna: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue