Remove PreMID

This commit is contained in:
thororen1234 2025-02-08 20:42:43 -05:00
parent 329cef3be0
commit 5d37ec8ca1
9 changed files with 2 additions and 446 deletions

View file

@ -77,7 +77,7 @@ export default definePlugin({
find: '("guildsnav")',
replacement: [
{
match: /(?<=#{intl::SERVERS}\),children:.{0,300}?)(\i)(\)?\.map\(\i\))/g,
match: /(?<=#{intl::SERVERS}\),children:.*?)(\i)(\)?\.map\(\i\))/g,
replace: "$self.useFilteredGuilds($1)$2",
},
// despite my best efforts, the above doesnt trigger a rerender

View file

@ -1,327 +0,0 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2023 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { definePluginSettings } from "@api/Settings";
import { Link } from "@components/Link";
import { Devs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType, PluginNative } from "@utils/types";
import { findByCodeLazy } from "@webpack";
import { ApplicationAssetUtils, FluxDispatcher, Forms, Toasts } from "@webpack/common";
interface ActivityAssets {
large_image: string;
large_text?: string | null;
small_image: string;
small_text: string;
}
type ActivityButton = {
label: string;
url: string;
};
export interface Activity {
state: string;
details?: string;
timestamps?: {
start?: number;
end?: number;
};
assets: ActivityAssets;
buttons?: Array<string>;
name: string;
application_id: string;
metadata?: {
button_urls?: Array<string>;
};
type: number;
flags: number;
}
interface PremidActivity {
state: string;
details?: string;
startTimestamp?: number;
endTimestamp?: number;
largeImageKey: string;
largeImageText: string;
smallImageKey: string;
smallImageText: string;
buttons?: ActivityButton[];
name?: string;
application_id: string;
type: number;
flags: number;
}
interface PresenceData {
// Only relevant types - https://github.com/PreMiD/PreMiD/blob/main/%40types/PreMiD/PresenceData.d.ts
clientId: string;
presenceData: PremidActivity;
}
const enum ActivityType {
PLAYING = 0,
LISTENING = 2,
WATCHING = 3,
COMPETING = 5
}
const enum ActivityFlag {
INSTANCE = 1 << 0
}
interface PublicApp {
id: string;
name: string;
icon: string;
statusType: ActivityType | undefined;
flags: number;
}
const logger = new Logger("Vencord-PreMiD", "#8fd0ff");
const fetchApplicationsRPC = findByCodeLazy('"Invalid Origin"', ".application");
const apps: any = {};
async function getApp(applicationId: string): Promise<PublicApp> {
if (apps[applicationId]) return apps[applicationId];
const socket: any = {};
debugLog(`Looking up ${applicationId}`);
await fetchApplicationsRPC(socket, applicationId);
logger.debug(socket);
debugLog(`Lookup finished for ${socket.application.name}`);
const activityType = await determineStatusType(socket.application);
debugLog(`Activity type for ${socket.application.name}: ${activityType}`);
socket.application.statusType = settings.store.detectCategory ? activityType : ActivityType.PLAYING || ActivityType.PLAYING;
apps[applicationId] = socket.application;
return socket.application;
}
const assetCache: Map<string, string> = new Map();
// memoized because this method isnt cached
async function getAppAsset(applicationId: string, key: string): Promise<string> {
if (assetCache.has(applicationId + key)) {
return assetCache.get(applicationId + key)!;
}
const result = (await ApplicationAssetUtils.fetchAssetIds(applicationId, [key]))[0];
assetCache.set(applicationId + key, result);
return result;
}
function setActivity(activity: Activity | undefined) {
FluxDispatcher.dispatch({
type: "LOCAL_ACTIVITY_UPDATE",
activity,
socketId: "PreMiD",
});
}
const settings = definePluginSettings({
enableSet: {
description: "Should the plugin set presences?",
type: OptionType.BOOLEAN,
default: true,
onChange: (value: boolean) => {
if (!value) clearActivity();
},
},
showButtons: {
description: "Show buttons",
type: OptionType.BOOLEAN,
default: true,
},
detectCategory: {
description: "Set your Activity Type based on presence category",
type: OptionType.BOOLEAN,
default: true,
},
hideViewChannel: {
description: "YouTube: Hide view channel button",
type: OptionType.BOOLEAN,
default: false,
}
});
function clearActivity() {
FluxDispatcher.dispatch({
type: "LOCAL_ACTIVITY_UPDATE",
activity: null,
socketId: "PreMiD",
});
}
const Native = VencordNative.pluginHelpers.PreMiD as PluginNative<typeof import("./native")>;
export default definePlugin({
name: "PreMiD",
tags: ["presence", "premid", "rpc", "watching"],
description: "A PreMiD app replacement. Supports watching/listening status. Requires extra setup (see settings)",
authors: [Devs.Nyako],
toolboxActions: {
"Toggle presence sharing": () => {
settings.store.enableSet = !settings.store.enableSet;
showToast(`Presence sharing is now ${settings.store.enableSet ? "enabled" : "disabled"}`);
clearActivity();
},
},
settingsAboutComponent: () => (
<>
<Forms.FormTitle tag="h3">How to use this plugin</Forms.FormTitle>
<Forms.FormText>
Install the <Link href="https://premid.app/downloads#ext-downloads">PreMiD browser extension</Link>. (recommended version: 2.5.2 OR 2.6.11+)
</Forms.FormText>
<Forms.FormText tag="h4">
This will not work with anything that has differing behavior (such as PreWrap)
</Forms.FormText>
<Forms.FormText>
That's all you need, if you followed the instructions in this plugin's README you should be good. This plugin replicates their electron tray process so no need to use allat.
</Forms.FormText>
</>
),
clearActivity,
settings,
logger,
start() {
Native.init();
},
stop() {
this.clearActivity();
Native.disconnect();
},
showToast,
async receiveActivity(data: PresenceData) {
logger.debug("Received activity", data);
if (!settings.store.enableSet) {
this.clearActivity();
return;
}
try {
const id = data.clientId;
if (!id) return;
const appInfo = await getApp(id);
const presence = { ...data.presenceData };
if (appInfo.name === "PreMiD") return;
logger.debug(`Setting activity of ${appInfo.name} "${presence.details}"`);
const { details, state, largeImageKey, smallImageKey, smallImageText } = presence;
const activity: Activity = {
application_id: id,
name: appInfo.name,
details: details ?? "",
state: state ?? "",
type: appInfo.statusType || ActivityType.PLAYING,
flags: ActivityFlag.INSTANCE,
assets: {
large_image: await getAppAsset(id, largeImageKey ?? "oops"),
small_image: await getAppAsset(id, smallImageKey ?? "oops"),
small_text: smallImageText || "hello there :3",
},
buttons: presence.buttons?.map((b: { label: any; }) => b.label),
metadata: {
button_urls: presence.buttons?.map((b: { url: any; }) => b.url)
},
timestamps: {
start: presence.startTimestamp,
end: presence.endTimestamp
}
};
if (activity.type === ActivityType.PLAYING) {
activity.assets = {
large_image: await getAppAsset(id, largeImageKey ?? "guh"),
large_text: "vc-premid",
small_image: await getAppAsset(id, smallImageKey ?? "guhh"),
small_text: smallImageText || "hello there :3",
};
}
if (settings.store.showButtons && activity.buttons) {
if (appInfo.name === "YouTube" && settings.store.hideViewChannel) {
activity.buttons?.pop();
if (activity.metadata && activity.metadata && activity.metadata.button_urls) {
activity.metadata.button_urls = [activity.metadata.button_urls[0]];
}
}
}
for (const k in activity) {
if (k === "type") continue; // without type, the presence is considered invalid.
const v = activity[k];
if (!v || v.length === 0)
delete activity[k];
}
setActivity(activity);
} catch (err) {
logger.error(err);
}
}
});
async function determineStatusType(info: PublicApp): Promise<ActivityType | undefined> {
let firstCharacter = info.name.charAt(0);
if (firstCharacter.match(/[a-zA-Z]/)) {
firstCharacter = firstCharacter;
} else if (firstCharacter.match(/[0-9]/)) {
firstCharacter = "0-9";
} else {
firstCharacter = "%23"; // #
}
const res = await fetch(`https://raw.githubusercontent.com/PreMiD/Presences/main/websites/${firstCharacter}/${info.name}/metadata.json`);
if (!res.ok) return ActivityType.PLAYING;
try {
const metadata = await res.json();
switch (metadata.category) {
case "socials":
if (metadata.tags.includes("video")) {
return ActivityType.WATCHING;
}
break;
case "anime":
if (metadata.tags.some((tag: string) => ["video", "media", "streaming"].includes(tag))) {
return ActivityType.WATCHING;
}
break;
case "music":
return ActivityType.LISTENING;
case "videos":
return ActivityType.WATCHING;
}
} catch (e) {
logger.error(e);
return ActivityType.PLAYING;
}
return ActivityType.PLAYING;
}
function debugLog(msg: string) {
if (IS_DEV) console.log(msg);
}
function showToast(msg: string) {
Toasts.show({
message: msg,
type: Toasts.Type.SUCCESS,
id: Toasts.genId(),
options: {
duration: 5000,
position: Toasts.Position.TOP
}
});
}

View file

@ -1,116 +0,0 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { BrowserWindow, dialog, WebContents } from "electron";
import { createServer, Server as HttpServer } from "http";
import { Server, Socket } from "socket.io";
let io: Server;
let httpServer: HttpServer;
let hasInit = false;
let webFrame: WebContents;
export function init() {
if (hasInit) return;
const windows = BrowserWindow.getAllWindows();
const discordUrls = ["https://discord.com", "https://ptb.discord.com", "https://canary.discord.com"];
for (const win of windows) {
const url = win.webContents.getURL();
if (discordUrls.some(prefix => url.startsWith(prefix))) {
webFrame = win.webContents;
}
}
httpServer = createServer();
io = new Server(httpServer, {
serveClient: false,
allowEIO3: true,
cors: { origin: "*" }
});
httpServer.listen(3020, () => {
console.log("[vc-premid] SocketIO starting on 3020");
logRenderer("SocketIO starting on 3020");
});
httpServer.on("error", onIOError);
io.on("connection", onConnect);
hasInit = true;
}
export function disconnect() {
if (!hasInit) return;
io.close();
httpServer.close();
hasInit = false;
}
async function onConnect(sio: Socket) {
try {
logRenderer("[vc-premid] PreMiD socket connected!");
// Get current user from plugin & send to extension
const {
username,
globalName,
id,
avatar,
discriminator,
flags,
premiumType
} = JSON.parse(await webFrame.executeJavaScript("JSON.stringify(window.Vencord.Webpack.Common.UserStore.getCurrentUser());"));
sio.emit("discordUser", { username, global_name: globalName, discriminator, id, avatar, bot: false, flags, premium_type: premiumType });
// Extension requests Premid version
sio.on("getVersion", () => {
logRenderer("Extension requested version");
sio.emit("receiveVersion", "221");
});
sio.on("setActivity", setActivity);
sio.on("clearActivity", clearActivity);
sio.on("selectLocalPresence", () => {
logRenderer("Selecting local presence is not supported");
dialog.showMessageBox({ message: "Selecting local presence is not supported right now!", title: "vc-premid: oops!" });
});
sio.once("disconnect", () => onIoDisconnect());
} catch (e) {
logError("Error in onConnect: ", e);
}
}
function logRenderer(message: string) {
if (webFrame) {
webFrame.executeJavaScript(`window.Vencord.Plugins.plugins.PreMiD.logger.info('${message}')`);
} else {
// just in case, dont worry about it pls
console.log(`[vc-premid (fallback)] ${message}`);
}
}
function logError(message: string, ...args: any[]) {
console.error(`${message}`, args);
}
function setActivity(activity: any) {
// hopefully this works
webFrame.executeJavaScript(`window.Vencord.Plugins.plugins.PreMiD.receiveActivity(${JSON.stringify(activity)})`).catch(console.error);
}
function clearActivity() {
webFrame.executeJavaScript("window.Vencord.Plugins.plugins.PreMiD.clearActivity()");
}
function onIOError(e: { message: string; code: string; }) {
if (e.message.includes("EADDRINUSE")) return; // dont care, probably 2+ clients open
logError("SocketIO error", e);
}
async function onIoDisconnect() {
console.log("[vc-premid] SocketIO disconnected");
logRenderer("SocketIO disconnected");
clearActivity();
}