Equibop supportHelper (#470)
* Add support for equibop git hashes, Equicord/Equibop/commit/154ad1095b358e92a1f57f77ffcc38d691d1075a * Add support for equibop arrpc-bun debugging * move to an actual plugin for equibop instead of webrichp * move plugin to core, move arrp debug out of support helper * fix devbuild detection for equibop * Tidy * ARRPCBUN CHAT * WOW --------- Co-authored-by: thororen1234 <78185467+thororen1234@users.noreply.github.com>
This commit is contained in:
parent
b503d49478
commit
57ebbe1fd4
7 changed files with 281 additions and 42 deletions
230
src/equicordplugins/arRPCBun.web/index.tsx
Normal file
230
src/equicordplugins/arRPCBun.web/index.tsx
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { popNotice, showNotice } from "@api/Notices";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { isAnyPluginDev, isEquicordGuild } from "@utils/misc";
|
||||
import definePlugin, { OptionType, ReporterTestable } from "@utils/types";
|
||||
import { findByCodeLazy } from "@webpack";
|
||||
import { ApplicationAssetUtils, FluxDispatcher, Toasts, UserStore } from "@webpack/common";
|
||||
|
||||
const fetchApplicationsRPC = findByCodeLazy('"Invalid Origin"', ".application");
|
||||
const logger = new Logger("arRPCBun");
|
||||
|
||||
async function lookupAsset(applicationId: string, key: string): Promise<string> {
|
||||
return (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0];
|
||||
}
|
||||
|
||||
const apps: any = {};
|
||||
async function lookupApp(applicationId: string): Promise<string> {
|
||||
const socket: any = {};
|
||||
await fetchApplicationsRPC(socket, applicationId);
|
||||
return socket.application;
|
||||
}
|
||||
|
||||
let ws: WebSocket;
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
oldVerNotice: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "old version notice for why arrpc bun doesnt work",
|
||||
default: false,
|
||||
hidden: true
|
||||
},
|
||||
oneTimeNotice: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "One time notice for showing arrpc disabled",
|
||||
default: false,
|
||||
hidden: true
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export default definePlugin({
|
||||
name: "arRPCBun",
|
||||
description: "arRPCBun integration",
|
||||
authors: [EquicordDevs.creations],
|
||||
reporterTestable: ReporterTestable.None,
|
||||
enabledByDefault: IS_EQUIBOP,
|
||||
settings,
|
||||
|
||||
commands: [
|
||||
{
|
||||
name: "arrpc-debug",
|
||||
description: "Show arRPCBun debug information",
|
||||
predicate: ctx => {
|
||||
const result = isAnyPluginDev(UserStore.getCurrentUser()?.id) || isEquicordGuild(ctx?.guild?.id, true);
|
||||
return result;
|
||||
},
|
||||
execute: () => {
|
||||
const arrpcStatus = IS_EQUIBOP ? VesktopNative.arrpc?.getStatus?.() : null;
|
||||
|
||||
let content = "";
|
||||
|
||||
if (IS_EQUIBOP) {
|
||||
const version = VesktopNative.app.getVersion();
|
||||
const gitHash = VesktopNative.app.getGitHash?.();
|
||||
const shortHash = gitHash?.slice(0, 7);
|
||||
|
||||
content += `Equibop: v${version}`;
|
||||
if (shortHash) {
|
||||
content += ` • [${shortHash}](<https://github.com/Equicord/Equibop/commit/${gitHash}>)`;
|
||||
}
|
||||
content += "\n";
|
||||
}
|
||||
|
||||
if (arrpcStatus) {
|
||||
content += `Running: ${arrpcStatus.running ? "Yes" : "No"}\n`;
|
||||
content += `Enabled: ${arrpcStatus.enabled ? "Yes" : "No"}\n`;
|
||||
|
||||
if (arrpcStatus.running) {
|
||||
content += `Port: ${arrpcStatus.port}\n`;
|
||||
content += `PID: ${arrpcStatus.pid}\n`;
|
||||
|
||||
if (arrpcStatus.uptime) {
|
||||
const seconds = Math.floor(arrpcStatus.uptime / 1000);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
|
||||
if (hours > 0) {
|
||||
content += `Uptime: ${hours}h ${minutes % 60}m ${seconds % 60}s\n`;
|
||||
} else if (minutes > 0) {
|
||||
content += `Uptime: ${minutes}m ${seconds % 60}s\n`;
|
||||
} else {
|
||||
content += `Uptime: ${seconds}s\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const info = [
|
||||
arrpcStatus.restartCount > 0 && ["Restarts", arrpcStatus.restartCount],
|
||||
arrpcStatus.bunPath && ["Bun", arrpcStatus.bunPath],
|
||||
arrpcStatus.warnings?.length && ["Warnings", arrpcStatus.warnings.join(", ")],
|
||||
arrpcStatus.lastError && ["Last Error", arrpcStatus.lastError],
|
||||
arrpcStatus.lastExitCode && arrpcStatus.lastExitCode !== 0 && ["Exit Code", arrpcStatus.lastExitCode]
|
||||
].filter(Boolean);
|
||||
|
||||
content += info.map(([type, value]) => `${type}: ${value}`).join("\n");
|
||||
} else {
|
||||
if (ws) {
|
||||
content += ws.readyState === WebSocket.OPEN
|
||||
? "WebSocket: Connected to external arRPCBun server\n"
|
||||
: `WebSocket: ${["Connecting", "Open", "Closing", "Closed"][ws.readyState]}\n`;
|
||||
} else {
|
||||
content += "WebSocket: Not connected\n";
|
||||
}
|
||||
}
|
||||
|
||||
return { content };
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
async handleEvent(e: MessageEvent<any>) {
|
||||
const data = JSON.parse(e.data);
|
||||
|
||||
const { activity } = data;
|
||||
const assets = activity?.assets;
|
||||
|
||||
if (assets?.large_image) assets.large_image = await lookupAsset(activity.application_id, assets.large_image);
|
||||
if (assets?.small_image) assets.small_image = await lookupAsset(activity.application_id, assets.small_image);
|
||||
|
||||
if (activity) {
|
||||
const appId = activity.application_id;
|
||||
apps[appId] ||= await lookupApp(appId);
|
||||
|
||||
const app = apps[appId];
|
||||
activity.name ||= app.name;
|
||||
}
|
||||
|
||||
FluxDispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", ...data });
|
||||
},
|
||||
|
||||
async start() {
|
||||
// only works on 3.0.8+
|
||||
if (IS_EQUIBOP) {
|
||||
const version = VesktopNative.app.getVersion();
|
||||
const [major, minor, patch] = version.split(".").map(Number);
|
||||
|
||||
if (major < 3 || (major === 3 && minor === 0 && patch < 8) && !settings.store.oldVerNotice) {
|
||||
logger.error(`Equibop ${version} is too old. Requires 3.0.8+ for arRPCBun fix.`);
|
||||
showNotice(`arRPCBun requires Equibop 3.0.8+. You have ${version}. Update Equibop to use this plugin.`, "OK", () => {
|
||||
settings.store.oldVerNotice = true;
|
||||
popNotice();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// disable WebRichPresence to avoid conflicts
|
||||
const webRPC = Vencord.Plugins.plugins.WebRichPresence;
|
||||
if (webRPC && Vencord.Plugins.isPluginEnabled("WebRichPresence")) {
|
||||
logger.info("Disabling WebRichPresence to avoid conflicts");
|
||||
Vencord.Plugins.stopPlugin(webRPC);
|
||||
}
|
||||
|
||||
// get arRPC status from Equibop if available, otherwise use defaults
|
||||
const arrpcStatus = IS_EQUIBOP ? VesktopNative.arrpc?.getStatus?.() : null;
|
||||
|
||||
// if on Equibop and arRPC is disabled AND not running, warn user
|
||||
if (IS_EQUIBOP && !arrpcStatus?.enabled && !arrpcStatus?.running && !settings.store.oneTimeNotice) {
|
||||
logger.warn("Equibop's built-in arRPC is disabled and not running");
|
||||
showNotice("arRPC is not running. Enable it in Equibop settings, or run your own arRPCBun server.", "OK", () => {
|
||||
settings.store.oneTimeNotice = true;
|
||||
popNotice();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const host = arrpcStatus?.host || "127.0.0.1";
|
||||
const port = arrpcStatus?.port || 1337;
|
||||
|
||||
const wsUrl = `ws://${host}:${port}`;
|
||||
logger.info(`Connecting to arRPCBun at ${wsUrl}${arrpcStatus?.host ? "" : " (using defaults)"}`);
|
||||
|
||||
if (ws) ws.close();
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onmessage = this.handleEvent;
|
||||
|
||||
ws.onerror = error => {
|
||||
logger.error("WebSocket error:", error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
logger.info("WebSocket closed");
|
||||
};
|
||||
|
||||
const connectionSuccessful = await new Promise(res => setTimeout(() => res(ws.readyState === WebSocket.OPEN), 5000));
|
||||
if (!connectionSuccessful) {
|
||||
logger.error("Failed to connect to arRPCBun");
|
||||
showNotice("Failed to connect to arRPCBun, is it running?", "Retry", () => {
|
||||
popNotice();
|
||||
this.start();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Successfully connected to arRPCBun");
|
||||
Toasts.show({
|
||||
message: "Connected to arRPCBun",
|
||||
type: Toasts.Type.SUCCESS,
|
||||
id: Toasts.genId(),
|
||||
options: {
|
||||
duration: 1000,
|
||||
position: Toasts.Position.BOTTOM
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
stop() {
|
||||
FluxDispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", activity: null });
|
||||
ws?.close();
|
||||
logger.info("Stopped arRPCBun connection");
|
||||
}
|
||||
});
|
||||
|
|
@ -75,7 +75,7 @@ async function readDirectoryEntry(entry: FileSystemDirectoryEntry): Promise<Reco
|
|||
|
||||
const readBatch = async (): Promise<void> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
reader.readEntries(async (entries) => {
|
||||
reader.readEntries(async entries => {
|
||||
if (entries.length === 0) {
|
||||
resolve();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -100,3 +100,31 @@ export async function toggleEnabled(name: string) {
|
|||
settings.enabled = !wasEnabled;
|
||||
return await beforeReturn(settings, wasEnabled);
|
||||
}
|
||||
|
||||
export function getWindowsName(release: string) {
|
||||
const build = parseInt(release.split(".")[2]);
|
||||
if (build >= 22000) return "Windows 11";
|
||||
if (build >= 10240) return "Windows 10";
|
||||
if (build >= 9200) return "Windows 8.1";
|
||||
if (build >= 7600) return "Windows 7";
|
||||
return `Windows (${release})`;
|
||||
}
|
||||
|
||||
export function getMacOSName(release: string) {
|
||||
const major = parseInt(release.split(".")[0]);
|
||||
if (major === 24) return "MacOS 15 (Sequoia)";
|
||||
if (major === 23) return "MacOS 14 (Sonoma)";
|
||||
if (major === 22) return "MacOS 13 (Ventura)";
|
||||
if (major === 21) return "MacOS 12 (Monterey)";
|
||||
if (major === 20) return "MacOS 11 (Big Sur)";
|
||||
if (major === 19) return "MacOS 10.15 (Catalina)";
|
||||
return `MacOS (${release})`;
|
||||
}
|
||||
|
||||
export function platformName() {
|
||||
if (typeof DiscordNative === "undefined") return navigator.platform;
|
||||
if (DiscordNative.process.platform === "win32") return `${getWindowsName(DiscordNative.os.release)}`;
|
||||
if (DiscordNative.process.platform === "darwin") return `${getMacOSName(DiscordNative.os.release)} (${DiscordNative.process.arch === "arm64" ? "Apple Silicon" : "Intel Silicon"})`;
|
||||
if (DiscordNative.process.platform === "linux") return `Linux (${DiscordNative.os.release})`;
|
||||
return DiscordNative.process.platform;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ interface PickerProps {
|
|||
const getDesktopSources = findByCodeLazy("desktop sources");
|
||||
const configModule = findByPropsLazy("getOutputVolume");
|
||||
const log = new Logger("InstantScreenShare");
|
||||
|
||||
export const settings = definePluginSettings({
|
||||
streamMedia: {
|
||||
type: OptionType.COMPONENT,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { Flex } from "@components/Flex";
|
|||
import { Link } from "@components/Link";
|
||||
import { Paragraph } from "@components/Paragraph";
|
||||
import { openUpdaterModal } from "@components/settings/tabs/updater";
|
||||
import { platformName } from "@equicordplugins/equicordHelper/utils";
|
||||
import { CONTRIB_ROLE_ID, Devs, DONOR_ROLE_ID, EQUIBOP_CONTRIB_ROLE_ID, EQUICORD_TEAM, GUILD_ID, SUPPORT_CHANNEL_ID, SUPPORT_CHANNEL_IDS, VC_CONTRIB_ROLE_ID, VC_DONOR_ROLE_ID, VC_GUILD_ID, VC_REGULAR_ROLE_ID, VC_SUPPORT_CHANNEL_IDS, VENCORD_CONTRIB_ROLE_ID } from "@utils/constants";
|
||||
import { sendMessage } from "@utils/discord";
|
||||
import { Logger } from "@utils/Logger";
|
||||
|
|
@ -71,41 +72,20 @@ async function forceUpdate() {
|
|||
return outdated;
|
||||
}
|
||||
|
||||
function getWindowsName(release: string) {
|
||||
const build = parseInt(release.split(".")[2]);
|
||||
if (build >= 22000) return "Windows 11";
|
||||
if (build >= 10240) return "Windows 10";
|
||||
if (build >= 9200) return "Windows 8.1";
|
||||
if (build >= 7600) return "Windows 7";
|
||||
return `Windows (${release})`;
|
||||
}
|
||||
|
||||
function getMacOSName(release: string) {
|
||||
const major = parseInt(release.split(".")[0]);
|
||||
if (major === 24) return "MacOS 15 (Sequoia)";
|
||||
if (major === 23) return "MacOS 14 (Sonoma)";
|
||||
if (major === 22) return "MacOS 13 (Ventura)";
|
||||
if (major === 21) return "MacOS 12 (Monterey)";
|
||||
if (major === 20) return "MacOS 11 (Big Sur)";
|
||||
if (major === 19) return "MacOS 10.15 (Catalina)";
|
||||
return `MacOS (${release})`;
|
||||
}
|
||||
|
||||
function platformName() {
|
||||
if (typeof DiscordNative === "undefined") return navigator.platform;
|
||||
if (DiscordNative.process.platform === "win32") return `${getWindowsName(DiscordNative.os.release)}`;
|
||||
if (DiscordNative.process.platform === "darwin") return `${getMacOSName(DiscordNative.os.release)} (${DiscordNative.process.arch === "arm64" ? "Apple Silicon" : "Intel Silicon"})`;
|
||||
if (DiscordNative.process.platform === "linux") return `Linux (${DiscordNative.os.release})`;
|
||||
return DiscordNative.process.platform;
|
||||
}
|
||||
|
||||
async function generateDebugInfoMessage() {
|
||||
const { RELEASE_CHANNEL } = window.GLOBAL_ENV;
|
||||
|
||||
const client = (() => {
|
||||
if (IS_DISCORD_DESKTOP) return `Discord Desktop v${DiscordNative.app.getVersion()}`;
|
||||
if (IS_VESKTOP) return `Vesktop v${VesktopNative.app.getVersion()}`;
|
||||
if (IS_EQUIBOP) return `Equibop v${VesktopNative.app.getVersion()}`;
|
||||
if (IS_EQUIBOP) {
|
||||
const equibopGitHash = tryOrElse(() => VesktopNative.app.getGitHash?.(), null);
|
||||
if (equibopGitHash) {
|
||||
const shortHash = equibopGitHash.slice(0, 7);
|
||||
return `Equibop v${VesktopNative.app.getVersion()} • [${shortHash}](<https://github.com/Equicord/Equibop/commit/${equibopGitHash}>)`;
|
||||
}
|
||||
return `Equibop v${VesktopNative.app.getVersion()}`;
|
||||
}
|
||||
if ("legcord" in window) return `LegCord v${window.legcord.version}`;
|
||||
|
||||
// @ts-expect-error
|
||||
|
|
@ -116,7 +96,7 @@ async function generateDebugInfoMessage() {
|
|||
const info = {
|
||||
Equicord:
|
||||
`v${VERSION} • [${shortGitHash()}](<https://github.com/Equicord/Equicord/commit/${gitHash}>)` +
|
||||
`${SettingsPlugin.getVersionInfo()} - ${Intl.DateTimeFormat("en-GB", { dateStyle: "medium" }).format(BUILD_TIMESTAMP)}`,
|
||||
`${IS_EQUIBOP ? "" : SettingsPlugin.getVersionInfo()} - ${Intl.DateTimeFormat("en-US", { dateStyle: "medium" }).format(BUILD_TIMESTAMP)}`,
|
||||
Client: `${RELEASE_CHANNEL} ~ ${client}`,
|
||||
Platform: platformName()
|
||||
};
|
||||
|
|
@ -138,6 +118,7 @@ async function generateDebugInfoMessage() {
|
|||
"Activity Sharing Disabled": tryOrElse(() => !ShowCurrentGame.getSetting(), false),
|
||||
"Link Embeds Disabled": tryOrElse(() => !ShowEmbeds.getSetting(), false),
|
||||
"Equicord DevBuild": !IS_STANDALONE,
|
||||
"Equibop DevBuild": IS_EQUIBOP && tryOrElse(() => VesktopNative.app.isDevBuild?.(), false),
|
||||
"Has UserPlugins": Object.values(PluginMeta).some(m => m.userPlugin),
|
||||
">2 Weeks Outdated": BUILD_TIMESTAMP < Date.now() - 12096e5,
|
||||
[`Potentially Problematic Plugins: ${potentiallyProblematicPlugins.join(", ")}`]: potentiallyProblematicPlugins.length
|
||||
|
|
|
|||
|
|
@ -39,22 +39,15 @@ async function lookupApp(applicationId: string): Promise<string> {
|
|||
return socket.application;
|
||||
}
|
||||
|
||||
let hideSetting = false;
|
||||
let ws: WebSocket;
|
||||
|
||||
if (IS_VESKTOP || IS_EQUIBOP || "legcord" in window) {
|
||||
hideSetting = true;
|
||||
} else if ("goofcord" in window) {
|
||||
hideSetting = false;
|
||||
}
|
||||
|
||||
migratePluginSettings("WebRichPresence", "WebRichPresence (arRPC)");
|
||||
export default definePlugin({
|
||||
name: "WebRichPresence",
|
||||
description: "Client plugin for arRPC to enable RPC on Discord Web (experimental)",
|
||||
authors: [Devs.Ducko],
|
||||
reporterTestable: ReporterTestable.None,
|
||||
hidden: hideSetting,
|
||||
hidden: !IS_EQUIBOP && !IS_VESKTOP && !("legcord" in window),
|
||||
|
||||
settingsAboutComponent: () => (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -119,18 +119,24 @@ export function tryOrElse<T>(func: () => T, fallback: T): T {
|
|||
}
|
||||
}
|
||||
|
||||
export function isEquicordGuild(id: string, isGuildId: boolean = false): boolean {
|
||||
export function isEquicordGuild(id: string | null | undefined, isGuildId: boolean = false): boolean {
|
||||
if (!id) return false;
|
||||
|
||||
if (isGuildId) return id === GUILD_ID;
|
||||
|
||||
const channel = ChannelStore.getChannel(id);
|
||||
return channel.guild_id === GUILD_ID;
|
||||
}
|
||||
|
||||
export function isSupportChannel(channelId: string): boolean {
|
||||
export function isSupportChannel(channelId: string | null | undefined): boolean {
|
||||
if (channelId) return false;
|
||||
|
||||
return channelId === SUPPORT_CHANNEL_ID;
|
||||
}
|
||||
|
||||
export function isEquicordSupport(userId: string): boolean {
|
||||
export function isEquicordSupport(userId: string | null | undefined): boolean {
|
||||
if (!userId) return false;
|
||||
|
||||
const member = GuildMemberStore.getMember(GUILD_ID, userId);
|
||||
return member?.roles?.includes(EQUICORD_HELPERS) || false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue