Update BetterScreenshare & PhilsPluginLibrary

This commit is contained in:
RobinRMC 2025-02-24 16:22:13 +01:00 committed by GitHub
parent 7193b82bd6
commit 337c1a05af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 115 additions and 65 deletions

View file

@ -12,7 +12,7 @@ import { addSettingsPanelButton, Emitter, removeSettingsPanelButton, Screenshare
import { PluginInfo } from "./constants";
import { openScreenshareModal } from "./modals";
import { ScreenshareAudioPatcher, ScreensharePatcher } from "./patchers";
import { replacedScreenshareModalComponent } from "./patches";
import { GoLivePanelWrapper, replacedSubmitFunction } from "./patches";
import { initScreenshareAudioStore, initScreenshareStore } from "./stores";
export default definePlugin({
@ -22,10 +22,17 @@ export default definePlugin({
dependencies: ["PhilsPluginLibrary"],
patches: [
{
find: "Messages.SCREENSHARE_RELAUNCH",
find: "GoLiveModal: user cannot be undefined", // Module: 60594; canaryRelease: 364525; L431
replacement: {
match: /(function .{1,2}\(.{1,2}\){)(.{1,40}(?=selectGuild).+?(?:]}\)}\)))(})/,
replace: "$1return $self.replacedScreenshareModalComponent(function(){$2}, this, arguments)$3"
match: /onSubmit:(\w+)/,
replace: "onSubmit:$self.replacedSubmitFunction($1)"
}
},
{
find: "StreamSettings: user cannot be undefined", // Module: 641115; canaryRelease: 364525; L254
replacement: {
match: /\(.{0,10}(,{.{0,100}modalContent)/,
replace: "($self.GoLivePanelWrapper$1"
}
}
],
@ -59,5 +66,6 @@ export default definePlugin({
toolboxActions: {
"Open Screenshare Settings": openScreenshareModal
},
replacedScreenshareModalComponent
replacedSubmitFunction,
GoLivePanelWrapper
});

View file

@ -1,6 +1,6 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@ -46,30 +46,8 @@ const ReplacedStreamSettings = () => {
);
};
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[3].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 = () => {
export function replacedSubmitFunction(fn) { // This is used to hook over the new OnSubmit function instead of implementing an OnClick function
return (...args) => {
const { screensharePatcher, screenshareAudioPatcher } = Plugin;
if (screensharePatcher) {
@ -80,6 +58,20 @@ export function replacedScreenshareModalComponent(oldComponent: (...args: any[])
if (screenshareAudioPatcher)
screenshareAudioPatcher.forceUpdateTransportationOptions();
return fn(...args);
};
return oldComponentResult;
}
export function GoLivePanelWrapper({ children }: { children: React.JSX.Element; }) {
if (!children)
return;
const { hideDefaultSettings } = Settings.plugins[PluginInfo.PLUGIN_NAME];
if (hideDefaultSettings)
return <ReplacedStreamSettings />;
children.props.children.push(<ReplacedStreamSettings />);
return children;
}

View file

@ -1,6 +1,6 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@ -18,8 +18,8 @@ const plugin = definePlugin({
{
find: "--custom-app-panels-height",
replacement: {
match: /(\w+\.\w+\(\w+,{\w+:function\(\){)return (\w)+}/,
replace: "$1 $self.storedComp = $2; return $self.replacedUserPanelComponent}"
match: /{}\)}\),/,
replace: "{})}),$self.replacedUserPanelComponent(),"
}
},
{
@ -37,7 +37,11 @@ const plugin = definePlugin({
}
]
});
plugin.replacedUserPanelComponent = replacedUserPanelComponent.bind(plugin);
export default plugin;
export const DeafenIcon = (props: React.ComponentProps<"svg">) => {

View file

@ -1,10 +1,11 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { React } from "@webpack/common";
import { JSX } from "react";
import { SettingsPanel } from "../components";
import { IconComponent, SettingsPanelButton } from "../components/settingsPanel/SettingsPanelButton";
@ -49,10 +50,19 @@ export const ButtonsSettingsPanel = () => {
const splicedButtons =
settingsPanelButtonsClone
.splice(0, 3)
.map(({ icon, tooltipText, onClick }) =>
.map(({ icon, tooltipText, onClick }, index) =>
tooltipText
? <SettingsPanelTooltipButton tooltipProps={{ text: tooltipText }} icon={icon} onClick={onClick} />
: <SettingsPanelButton icon={icon} onClick={onClick} />
? <SettingsPanelTooltipButton
key={`tooltip-button-${index}`} // Add a unique key here
tooltipProps={{ text: tooltipText }}
icon={icon}
onClick={onClick}
/>
: <SettingsPanelButton
key={`button-${index}`} // Add a unique key here
icon={icon}
onClick={onClick}
/>
);
groupedButtons.push(splicedButtons);
@ -63,24 +73,17 @@ export const ButtonsSettingsPanel = () => {
return rawPanelButtons.length > 0
? <SettingsPanel>
{...convertRawPanelButtons(rawPanelButtons).map(value => <SettingsPanelRow children={value} />)}
{convertRawPanelButtons(rawPanelButtons).map((value, index) => (
<SettingsPanelRow key={`panel-row-${index}`}>
{value}
</SettingsPanelRow>
))}
</SettingsPanel>
: <>
</>;
: null;
};
export function replacedUserPanelComponent() {
// @ts-ignore
const componentResult: JSX.Element = this.storedComp();
if (!componentResult?.props) return componentResult;
const { children } = componentResult.props;
children.splice(children.length - 1, 0,
<ButtonsSettingsPanel />
);
return componentResult;
export function replacedUserPanelComponent(oldComponent) {
return <ButtonsSettingsPanel />;
}
export function addSettingsPanelButton(settings: PanelButton) {

View file

@ -1,6 +1,6 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@ -52,6 +52,7 @@ export function getStreamParameters(connection: types.Connection, get: Profilabl
return {
...connection.videoStreamParameters[0],
quality: 100,
...(videoBitrateEnabled && videoBitrate
? {
maxBitrate: videoBitrate * 1000,
@ -112,12 +113,12 @@ export function getReplaceableVideoTransportationOptions(connection: types.Conne
return {
...(videoBitrateEnabled && videoBitrate
? {
encodingVideoBitRate: videoBitrate * 1000,
encodingVideoMinBitRate: videoBitrate * 1000,
encodingVideoMaxBitRate: videoBitrate * 1000,
callBitRate: videoBitrate * 1000,
callMinBitRate: videoBitrate * 1000,
callMaxBitRate: videoBitrate * 1000
encodingVideoBitRate: Math.round(videoBitrate * 1000),
encodingVideoMinBitRate: Math.round(videoBitrate * 1000),
encodingVideoMaxBitRate: Math.round(videoBitrate * 1000),
callBitRate: Math.round(videoBitrate * 1000),
callMinBitRate: Math.round(videoBitrate * 1000),
callMaxBitRate: Math.round(videoBitrate * 1000)
}
: {}
),
@ -213,6 +214,33 @@ export function patchConnectionVideoTransportOptions(
logger?: Logger
) {
const oldSetTransportOptions = connection.conn.setTransportOptions;
const oldGetQuality = connection.videoQualityManager.getQuality;
connection.videoQualityManager.getQuality = function (src) {
const { currentProfile } = get();
const { videoBitrateEnabled, videoBitrate, framerateEnabled, framerate, resolutionEnabled, width, height } = currentProfile;
const quality = oldGetQuality.call(this, src);
if (videoBitrateEnabled) {
quality.bitrateMax = Math.round(videoBitrate! * 1000);
quality.bitrateMin = Math.round(videoBitrate! * 1000);
quality.bitrateTarget = Math.round(videoBitrate! * 1000);
}
quality.localWant = 100;
quality.capture.framerate = framerateEnabled ? framerate : quality.capture.framerate;
quality.capture.width = resolutionEnabled ? width : quality.capture.width;
quality.capture.height = resolutionEnabled ? height : quality.capture.height;
quality.capture.pixelCount = quality.capture.width * quality.capture.height;
quality.encode = quality.capture;
logger?.info("Overridden getQuality", quality);
return quality;
};
connection.conn.setTransportOptions = function (this: any, options: Record<string, any>) {
const replaceableTransportOptions = getReplaceableVideoTransportationOptions(connection, get);

View file

@ -1,6 +1,6 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* Copyright (c) 2025 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@ -53,10 +53,12 @@ export function createPluginStore<Z extends PluginSettings = {}>(pluginName: str
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]);
storeSettings.simpleMode = startupInfo.simpleMode;
storeSettings.profiles = startupInfo.profiles || [];
storeSettings.currentProfile = startupInfo.currentProfile || { name: "" };
startupStates[storeName] = true;
}
@ -70,16 +72,29 @@ export function createPluginStore<Z extends PluginSettings = {}>(pluginName: str
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 any, updateCallback); // Setup our proxy that allows us connections to the datastore
const settingData = Settings.plugins[pluginName].stores[storeName];
const filteredInitialSettings: unknown = { // We make sure that everything we pass to the IPC is allowed
profiles: settingData.profiles || [],
currentProfile: settingData.currentProfile || { name: "" },
simpleMode: settingData.simpleMode ?? false
};
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));
Settings.plugins[pluginName].stores[storeName] = { // Whenever the proxy is updated we also update the datastore with data that we know can pass through the IPC
simpleMode: updatedObject.simpleMode ?? false,
profiles: updatedObject.profiles.map(profile => ({ ...profile })),
currentProfile: { ...updatedObject.currentProfile } // No clue if this has to be spread or not (disregard the inconsistency ig)
};
}
for (const key of Object.keys(initialSettings)) { proxiedSettings[key] = initialSettings[key]; } // Set them so the nested objects also become proxies
settingStorage.set(storeName, proxiedSettings);
set({ ...filteredInitialSettings as Z, ...Settings.plugins[pluginName].stores[storeName] });
updateCallback(initialSettings);
return {