From 95dc9e6a8fcbcb46e0db56c385120cb9efe9a19d Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 03:10:34 +0100 Subject: [PATCH 01/62] use much stricter, whitelist based CSP --- src/main/csp.ts | 109 ++++++++++++++++++++++++++++++++++++++++++++++ src/main/index.ts | 68 ++--------------------------- 2 files changed, 112 insertions(+), 65 deletions(-) create mode 100644 src/main/csp.ts diff --git a/src/main/csp.ts b/src/main/csp.ts new file mode 100644 index 00000000..332de08d --- /dev/null +++ b/src/main/csp.ts @@ -0,0 +1,109 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2025 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { session } from "electron"; + +const findHeader = (headers: Record, headerName: Lowercase) => { + return Object.keys(headers).find(h => h.toLowerCase() === headerName); +}; + +const MediaSrc = ["connect-src", "img-src", "media-src"]; +const CssSrc = ["style-src", "font-src"]; +const MediaAndCssSrc = [...MediaSrc, ...CssSrc]; +const MediaScriptsAndCssSrc = [...MediaAndCssSrc, "script-src", "worker-src"]; + +const Policies: Record = { + // Used by Themes + "*.github.io": MediaAndCssSrc, + "raw.githubusercontent.com": MediaAndCssSrc, + "*.githack.com": MediaAndCssSrc, + "jsdelivr.net": MediaAndCssSrc, + "fonts.googleapis.com": CssSrc, + + // Used by themes and some Vencord code + "cdn.discordapp.com": MediaAndCssSrc, + "media.discordapp.net": MediaSrc, + + // CDNs used for some things by Vencord. + // FIXME: we really should not be using CDNs anymore + "cdnjs.cloudflare.com": MediaScriptsAndCssSrc, + "unpkg.com": MediaScriptsAndCssSrc, + + // used for VenCloud (api.vencord.dev) and badges (badges.vencord.dev) + "*.vencord.dev": MediaSrc, +}; + +// Remove CSP +type PolicyResult = Record; + +const parsePolicy = (policy: string): PolicyResult => { + const result: PolicyResult = {}; + policy.split(";").forEach(directive => { + const [directiveKey, ...directiveValue] = directive.trim().split(/\s+/g); + if (directiveKey && !Object.prototype.hasOwnProperty.call(result, directiveKey)) { + result[directiveKey] = directiveValue; + } + }); + + return result; +}; +const stringifyPolicy = (policy: PolicyResult): string => + Object.entries(policy) + .filter(([, values]) => values?.length) + .map(directive => directive.flat().join(" ")) + .join("; "); + + +const patchCsp = (headers: Record) => { + const header = findHeader(headers, "content-security-policy"); + + if (header) { + const csp = parsePolicy(headers[header][0]); + + const pushDirective = (directive: string, ...values: string[]) => { + csp[directive] ??= []; + csp[directive].push(...values); + }; + + for (const directive of ["style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src"]) { + pushDirective(directive, "blob:", "data:", "vencord:", "'unsafe-inline'"); + } + + pushDirective("script-src", "'unsafe-inline'", "'unsafe-eval'"); + + for (const [host, directives] of Object.entries(Policies)) { + for (const directive of directives) { + pushDirective(directive, host); + } + } + + headers[header] = [stringifyPolicy(csp)]; + } +}; + +export function initCsp() { + session.defaultSession.webRequest.onHeadersReceived(({ responseHeaders, resourceType }, cb) => { + if (responseHeaders) { + if (resourceType === "mainFrame") + patchCsp(responseHeaders); + + // Fix hosts that don't properly set the css content type, such as + // raw.githubusercontent.com + if (resourceType === "stylesheet") { + const header = findHeader(responseHeaders, "content-type"); + if (header) + responseHeaders[header] = ["text/css"]; + } + } + + cb({ cancel: false, responseHeaders }); + }); + + // assign a noop to onHeadersReceived to prevent other mods from adding their own incompatible ones. + // For instance, OpenAsar adds their own that doesn't fix content-type for stylesheets which makes it + // impossible to load css from github raw despite our fix above + session.defaultSession.webRequest.onHeadersReceived = () => { }; +} diff --git a/src/main/index.ts b/src/main/index.ts index 5519d47a..a001a490 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -16,9 +16,10 @@ * along with this program. If not, see . */ -import { app, protocol, session } from "electron"; +import { app, protocol } from "electron"; import { join } from "path"; +import { initCsp } from "./csp"; import { ensureSafePath } from "./ipcMain"; import { RendererSettings } from "./settings"; import { IS_VANILLA, THEMES_DIR } from "./utils/constants"; @@ -63,70 +64,7 @@ if (IS_VESKTOP || !IS_VANILLA) { } catch { } - const findHeader = (headers: Record, headerName: Lowercase) => { - return Object.keys(headers).find(h => h.toLowerCase() === headerName); - }; - - // Remove CSP - type PolicyResult = Record; - - const parsePolicy = (policy: string): PolicyResult => { - const result: PolicyResult = {}; - policy.split(";").forEach(directive => { - const [directiveKey, ...directiveValue] = directive.trim().split(/\s+/g); - if (directiveKey && !Object.prototype.hasOwnProperty.call(result, directiveKey)) { - result[directiveKey] = directiveValue; - } - }); - - return result; - }; - const stringifyPolicy = (policy: PolicyResult): string => - Object.entries(policy) - .filter(([, values]) => values?.length) - .map(directive => directive.flat().join(" ")) - .join("; "); - - const patchCsp = (headers: Record) => { - const header = findHeader(headers, "content-security-policy"); - - if (header) { - const csp = parsePolicy(headers[header][0]); - - for (const directive of ["style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src"]) { - csp[directive] ??= []; - csp[directive].push("*", "blob:", "data:", "vencord:", "'unsafe-inline'"); - } - - // TODO: Restrict this to only imported packages with fixed version. - // Perhaps auto generate with esbuild - csp["script-src"] ??= []; - csp["script-src"].push("'unsafe-eval'", "https://unpkg.com", "https://cdnjs.cloudflare.com"); - headers[header] = [stringifyPolicy(csp)]; - } - }; - - session.defaultSession.webRequest.onHeadersReceived(({ responseHeaders, resourceType }, cb) => { - if (responseHeaders) { - if (resourceType === "mainFrame") - patchCsp(responseHeaders); - - // Fix hosts that don't properly set the css content type, such as - // raw.githubusercontent.com - if (resourceType === "stylesheet") { - const header = findHeader(responseHeaders, "content-type"); - if (header) - responseHeaders[header] = ["text/css"]; - } - } - - cb({ cancel: false, responseHeaders }); - }); - - // assign a noop to onHeadersReceived to prevent other mods from adding their own incompatible ones. - // For instance, OpenAsar adds their own that doesn't fix content-type for stylesheets which makes it - // impossible to load css from github raw despite our fix above - session.defaultSession.webRequest.onHeadersReceived = () => { }; + initCsp(); }); } From 5eb306f6d08adc2b1ae5725d22ad9be136c6a984 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 03:18:46 +0100 Subject: [PATCH 02/62] add more domains & document better --- src/main/csp.ts | 52 +++++++++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 332de08d..964cc5da 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -6,41 +6,46 @@ import { session } from "electron"; -const findHeader = (headers: Record, headerName: Lowercase) => { - return Object.keys(headers).find(h => h.toLowerCase() === headerName); -}; +type PolicyMap = Record; const MediaSrc = ["connect-src", "img-src", "media-src"]; const CssSrc = ["style-src", "font-src"]; const MediaAndCssSrc = [...MediaSrc, ...CssSrc]; const MediaScriptsAndCssSrc = [...MediaAndCssSrc, "script-src", "worker-src"]; -const Policies: Record = { - // Used by Themes - "*.github.io": MediaAndCssSrc, - "raw.githubusercontent.com": MediaAndCssSrc, - "*.githack.com": MediaAndCssSrc, - "jsdelivr.net": MediaAndCssSrc, - "fonts.googleapis.com": CssSrc, +const Policies: PolicyMap = { + "*.github.io": MediaAndCssSrc, // github pages, used by most themes + "raw.githubusercontent.com": MediaAndCssSrc, // github raw, used by some themes + "*.gitlab.io": MediaAndCssSrc, // gitlab pages, used by some themes + "gitlab.com": MediaAndCssSrc, // gitlab raw, used by some themes + "*.codeberg.page": MediaAndCssSrc, // codeberg pages, used by some themes + "codeberg.org": MediaAndCssSrc, // codeberg raw, used by some themes - // Used by themes and some Vencord code - "cdn.discordapp.com": MediaAndCssSrc, - "media.discordapp.net": MediaSrc, + "*.githack.com": MediaAndCssSrc, // githack (namely raw.githack.com), used by some themes + "jsdelivr.net": MediaAndCssSrc, // jsdeliver, used by very few themes + + "fonts.googleapis.com": CssSrc, // google fonts, used by many themes + + "i.imgur.com": MediaSrc, // imgur, used by some themes + "i.ibb.co": MediaSrc, // imgbb, used by some themes + + "cdn.discordapp.com": MediaAndCssSrc, // Discord CDN, used by Vencord and some themes to load media + "media.discordapp.net": MediaSrc, // Discord media CDN, possible alternative to Discord CDN + + "*.vencord.dev": MediaSrc, // used for VenCloud (api.vencord.dev) and badges (badges.vencord.dev) // CDNs used for some things by Vencord. // FIXME: we really should not be using CDNs anymore "cdnjs.cloudflare.com": MediaScriptsAndCssSrc, "unpkg.com": MediaScriptsAndCssSrc, - - // used for VenCloud (api.vencord.dev) and badges (badges.vencord.dev) - "*.vencord.dev": MediaSrc, }; -// Remove CSP -type PolicyResult = Record; +const findHeader = (headers: PolicyMap, headerName: Lowercase) => { + return Object.keys(headers).find(h => h.toLowerCase() === headerName); +}; -const parsePolicy = (policy: string): PolicyResult => { - const result: PolicyResult = {}; +const parsePolicy = (policy: string): PolicyMap => { + const result: PolicyMap = {}; policy.split(";").forEach(directive => { const [directiveKey, ...directiveValue] = directive.trim().split(/\s+/g); if (directiveKey && !Object.prototype.hasOwnProperty.call(result, directiveKey)) { @@ -50,7 +55,8 @@ const parsePolicy = (policy: string): PolicyResult => { return result; }; -const stringifyPolicy = (policy: PolicyResult): string => + +const stringifyPolicy = (policy: PolicyMap): string => Object.entries(policy) .filter(([, values]) => values?.length) .map(directive => directive.flat().join(" ")) @@ -58,6 +64,10 @@ const stringifyPolicy = (policy: PolicyResult): string => const patchCsp = (headers: Record) => { + const reportOnlyHeader = findHeader(headers, "content-security-policy-report-only"); + if (reportOnlyHeader) + delete headers[reportOnlyHeader]; + const header = findHeader(headers, "content-security-policy"); if (header) { From 6166a1c1154a622e0c13f17ddaec3f211872ccc3 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 03:25:52 +0100 Subject: [PATCH 03/62] unbrick discord :sorrykirino: --- src/main/csp.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 964cc5da..91ca3bec 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -74,7 +74,7 @@ const patchCsp = (headers: Record) => { const csp = parsePolicy(headers[header][0]); const pushDirective = (directive: string, ...values: string[]) => { - csp[directive] ??= []; + csp[directive] ??= ["'self'"]; csp[directive].push(...values); }; @@ -90,6 +90,7 @@ const patchCsp = (headers: Record) => { } } + console.log(csp); headers[header] = [stringifyPolicy(csp)]; } }; From 11143adb02446aed2fc55e10b7071f976cfc45e4 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 03:32:15 +0100 Subject: [PATCH 04/62] whitelist plugin specific domains --- src/main/csp.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 91ca3bec..3e0decec 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -32,12 +32,20 @@ const Policies: PolicyMap = { "cdn.discordapp.com": MediaAndCssSrc, // Discord CDN, used by Vencord and some themes to load media "media.discordapp.net": MediaSrc, // Discord media CDN, possible alternative to Discord CDN - "*.vencord.dev": MediaSrc, // used for VenCloud (api.vencord.dev) and badges (badges.vencord.dev) - // CDNs used for some things by Vencord. // FIXME: we really should not be using CDNs anymore "cdnjs.cloudflare.com": MediaScriptsAndCssSrc, "unpkg.com": MediaScriptsAndCssSrc, + + // Function Specific + "api.github.com": ["connect-src"], // used for updating Vencord itself + "ws.audioscrobbler.com": ["connect-src"], // last.fm API + "translate.googleapis.com": ["connect-src"], // Google Translate API + "*.vencord.dev": MediaSrc, // VenCloud (api.vencord.dev) and Badges (badges.vencord.dev) + "manti.vendicated.dev": MediaSrc, // ReviewDB API + "decor.fieryflames.dev": MediaSrc, // Decor API + "sponsor.ajay.app": MediaSrc, // Dearrow API + "usrbg.is-hardly.online": MediaSrc, // USRBG API }; const findHeader = (headers: PolicyMap, headerName: Lowercase) => { From 0336ea1cb29c918bc1c03cb4fd61e41e6304e8dc Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 03:33:29 +0100 Subject: [PATCH 05/62] export CspPolicies map so plugins can whitelist themselves --- src/main/csp.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 3e0decec..44272fbc 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -13,7 +13,7 @@ const CssSrc = ["style-src", "font-src"]; const MediaAndCssSrc = [...MediaSrc, ...CssSrc]; const MediaScriptsAndCssSrc = [...MediaAndCssSrc, "script-src", "worker-src"]; -const Policies: PolicyMap = { +export const CspPolicies: PolicyMap = { "*.github.io": MediaAndCssSrc, // github pages, used by most themes "raw.githubusercontent.com": MediaAndCssSrc, // github raw, used by some themes "*.gitlab.io": MediaAndCssSrc, // gitlab pages, used by some themes @@ -92,7 +92,7 @@ const patchCsp = (headers: Record) => { pushDirective("script-src", "'unsafe-inline'", "'unsafe-eval'"); - for (const [host, directives] of Object.entries(Policies)) { + for (const [host, directives] of Object.entries(CspPolicies)) { for (const directive of directives) { pushDirective(directive, host); } From f08ac7e506df03391d1dad2ddc2df419c00798e1 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 03:46:43 +0100 Subject: [PATCH 06/62] fix more plugins --- src/main/csp.ts | 15 ++++++++------- src/plugins/_api/badges/index.tsx | 2 +- src/plugins/devCompanion.dev/index.tsx | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 44272fbc..378f4b69 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -8,7 +8,8 @@ import { session } from "electron"; type PolicyMap = Record; -const MediaSrc = ["connect-src", "img-src", "media-src"]; +const ConnectSrc = ["connect-src"]; +const MediaSrc = [...ConnectSrc, "img-src", "media-src"]; const CssSrc = ["style-src", "font-src"]; const MediaAndCssSrc = [...MediaSrc, ...CssSrc]; const MediaScriptsAndCssSrc = [...MediaAndCssSrc, "script-src", "worker-src"]; @@ -38,12 +39,13 @@ export const CspPolicies: PolicyMap = { "unpkg.com": MediaScriptsAndCssSrc, // Function Specific - "api.github.com": ["connect-src"], // used for updating Vencord itself - "ws.audioscrobbler.com": ["connect-src"], // last.fm API - "translate.googleapis.com": ["connect-src"], // Google Translate API + "api.github.com": ConnectSrc, // used for updating Vencord itself + "ws.audioscrobbler.com": ConnectSrc, // last.fm API + "translate.googleapis.com": ConnectSrc, // Google Translate API "*.vencord.dev": MediaSrc, // VenCloud (api.vencord.dev) and Badges (badges.vencord.dev) "manti.vendicated.dev": MediaSrc, // ReviewDB API - "decor.fieryflames.dev": MediaSrc, // Decor API + "decor.fieryflames.dev": ConnectSrc, // Decor API + "ugc.decor.fieryflames.dev": MediaSrc, // Decor CDN "sponsor.ajay.app": MediaSrc, // Dearrow API "usrbg.is-hardly.online": MediaSrc, // USRBG API }; @@ -82,7 +84,7 @@ const patchCsp = (headers: Record) => { const csp = parsePolicy(headers[header][0]); const pushDirective = (directive: string, ...values: string[]) => { - csp[directive] ??= ["'self'"]; + csp[directive] ??= [...csp["default-src"] ?? []]; csp[directive].push(...values); }; @@ -98,7 +100,6 @@ const patchCsp = (headers: Record) => { } } - console.log(csp); headers[header] = [stringifyPolicy(csp)]; } }; diff --git a/src/plugins/_api/badges/index.tsx b/src/plugins/_api/badges/index.tsx index 2a83809d..58b2e32c 100644 --- a/src/plugins/_api/badges/index.tsx +++ b/src/plugins/_api/badges/index.tsx @@ -33,7 +33,7 @@ import definePlugin from "@utils/types"; import { Forms, Toasts, UserStore } from "@webpack/common"; import { User } from "discord-types/general"; -const CONTRIBUTOR_BADGE = "https://vencord.dev/assets/favicon.png"; +const CONTRIBUTOR_BADGE = "https://cdn.discordapp.com/emojis/1092089799109775453.png?size=64"; const ContributorBadge: ProfileBadge = { description: "Vencord Contributor", diff --git a/src/plugins/devCompanion.dev/index.tsx b/src/plugins/devCompanion.dev/index.tsx index a495907b..19d95446 100644 --- a/src/plugins/devCompanion.dev/index.tsx +++ b/src/plugins/devCompanion.dev/index.tsx @@ -91,7 +91,7 @@ function parseNode(node: Node) { function initWs(isManual = false) { let wasConnected = isManual; let hasErrored = false; - const ws = socket = new WebSocket(`ws://localhost:${PORT}`); + const ws = socket = new WebSocket(`ws://127.0.0.1:${PORT}`); ws.addEventListener("open", () => { wasConnected = true; From 4c379e590f9ebccdb4037fc898ce171811c30a1d Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 04:03:35 +0100 Subject: [PATCH 07/62] add note about unsafe-inline + strict-dynamic --- src/main/csp.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 378f4b69..c85ec7d9 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -88,12 +88,16 @@ const patchCsp = (headers: Record) => { csp[directive].push(...values); }; - for (const directive of ["style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src"]) { - pushDirective(directive, "blob:", "data:", "vencord:", "'unsafe-inline'"); - } - + pushDirective("style-src", "'unsafe-inline'"); + // we could make unsafe-inline safe by using strict-dynamic with a random nonce on our Vencord loader script https://content-security-policy.com/strict-dynamic/ + // HOWEVER, at the time of writing (24 Jan 2025), Discord is INSANE and also uses unsafe-inline + // Once they stop using it, we also should pushDirective("script-src", "'unsafe-inline'", "'unsafe-eval'"); + for (const directive of ["style-src", "connect-src", "img-src", "font-src", "media-src", "worker-src"]) { + pushDirective(directive, "blob:", "data:", "vencord:"); + } + for (const [host, directives] of Object.entries(CspPolicies)) { for (const directive of directives) { pushDirective(directive, host); From eb3351d7550143c31f22d12c30f23768aa28e95e Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 24 Jan 2025 23:02:37 +0100 Subject: [PATCH 08/62] fix dearrow --- src/main/csp.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index c85ec7d9..d1559525 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -46,7 +46,8 @@ export const CspPolicies: PolicyMap = { "manti.vendicated.dev": MediaSrc, // ReviewDB API "decor.fieryflames.dev": ConnectSrc, // Decor API "ugc.decor.fieryflames.dev": MediaSrc, // Decor CDN - "sponsor.ajay.app": MediaSrc, // Dearrow API + "sponsor.ajay.app": ConnectSrc, // Dearrow API + "dearrow-thumb.ajay.app": MediaSrc, // Dearrow Thumbnail CDN "usrbg.is-hardly.online": MediaSrc, // USRBG API }; From 99cca05db868ccb40cae2a16f2509cf5e3bb0854 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 00:56:11 +0200 Subject: [PATCH 09/62] unpkg -> jsdelivr --- src/main/csp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index d1559525..a426c553 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -36,7 +36,7 @@ export const CspPolicies: PolicyMap = { // CDNs used for some things by Vencord. // FIXME: we really should not be using CDNs anymore "cdnjs.cloudflare.com": MediaScriptsAndCssSrc, - "unpkg.com": MediaScriptsAndCssSrc, + "cdn.jsdelivr.net": MediaScriptsAndCssSrc, // Function Specific "api.github.com": ConnectSrc, // used for updating Vencord itself From 0e3e14cb36d96c466683ce7eb2833b55c3823f70 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 01:48:39 +0200 Subject: [PATCH 10/62] add card to theme settings --- src/components/VencordSettings/ThemesTab.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index f718ab11..7e2ec193 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -206,6 +206,7 @@ function ThemesTab() { } function renderLocalThemes() { + return ( <> @@ -219,6 +220,12 @@ function ThemesTab() { If using the BD site, click on "Download" and place the downloaded .theme.css file into your themes folder. + + External Resources + For security reasons, loading resources (styles, fonts, images, ...) from most sites is blocked. + Make sure all your assets are hosted on GitHub, GitLab, Codeberg, Imgur, Discord or Gogle Fonts. + + <> From e55736b9322da0030cdf5cf9b216828437519da2 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 01:52:59 +0200 Subject: [PATCH 11/62] remove empty newline --- src/components/VencordSettings/ThemesTab.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index 7e2ec193..d0543100 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -206,7 +206,6 @@ function ThemesTab() { } function renderLocalThemes() { - return ( <> From f401e0db686549586b475ebb3aae1594f824ad38 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 02:01:14 +0200 Subject: [PATCH 12/62] Fix ReverseImageSearch icons --- src/main/csp.ts | 1 + src/plugins/reverseImageSearch/index.tsx | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index a426c553..66ef2f8f 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -49,6 +49,7 @@ export const CspPolicies: PolicyMap = { "sponsor.ajay.app": ConnectSrc, // Dearrow API "dearrow-thumb.ajay.app": MediaSrc, // Dearrow Thumbnail CDN "usrbg.is-hardly.online": MediaSrc, // USRBG API + "icons.duckduckgo.com": MediaSrc, // DuckDuckGo Favicon API (Reverse Image Search) }; const findHeader = (headers: PolicyMap, headerName: Lowercase) => { diff --git a/src/plugins/reverseImageSearch/index.tsx b/src/plugins/reverseImageSearch/index.tsx index 17fdb180..a2e7b7e6 100644 --- a/src/plugins/reverseImageSearch/index.tsx +++ b/src/plugins/reverseImageSearch/index.tsx @@ -53,14 +53,12 @@ function makeSearchItem(src: string) { = 3 // Do not round Google, Yandex & SauceNAO - ? "50%" - : void 0 + borderRadius: "50%", }} aria-hidden="true" height={16} width={16} - src={new URL("/favicon.ico", Engines[engine]).toString().replace("lens.", "")} + src={`https://icons.duckduckgo.com/ip3/${new URL(Engines[engine]).host}.ico`} /> {engine} From 694c31f28f01fdb2887af7518171a4ca415203be Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 02:01:32 +0200 Subject: [PATCH 13/62] Gogle --- src/components/VencordSettings/ThemesTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/VencordSettings/ThemesTab.tsx b/src/components/VencordSettings/ThemesTab.tsx index d0543100..b4e867f7 100644 --- a/src/components/VencordSettings/ThemesTab.tsx +++ b/src/components/VencordSettings/ThemesTab.tsx @@ -222,7 +222,7 @@ function ThemesTab() { External Resources For security reasons, loading resources (styles, fonts, images, ...) from most sites is blocked. - Make sure all your assets are hosted on GitHub, GitLab, Codeberg, Imgur, Discord or Gogle Fonts. + Make sure all your assets are hosted on GitHub, GitLab, Codeberg, Imgur, Discord or Google Fonts. From ffd1bd2d6a43f0f35594e403e5b0956a0cf1e6b2 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 02:04:19 +0200 Subject: [PATCH 14/62] make intent clearer --- src/main/csp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 66ef2f8f..2b92ad57 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -86,7 +86,7 @@ const patchCsp = (headers: Record) => { const csp = parsePolicy(headers[header][0]); const pushDirective = (directive: string, ...values: string[]) => { - csp[directive] ??= [...csp["default-src"] ?? []]; + csp[directive] ??= [...(csp["default-src"] ?? [])]; csp[directive].push(...values); }; From eea3a443fadb59dcab8d1295e6e3ff434116804b Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 02:10:34 +0200 Subject: [PATCH 15/62] add comment thingie --- src/main/csp.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/csp.ts b/src/main/csp.ts index 2b92ad57..82f1dd92 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -14,6 +14,9 @@ const CssSrc = ["style-src", "font-src"]; const MediaAndCssSrc = [...MediaSrc, ...CssSrc]; const MediaScriptsAndCssSrc = [...MediaAndCssSrc, "script-src", "worker-src"]; +// Plugins can whitelist their own domains by importing this object in their native.ts +// script and just adding to it + export const CspPolicies: PolicyMap = { "*.github.io": MediaAndCssSrc, // github pages, used by most themes "raw.githubusercontent.com": MediaAndCssSrc, // github raw, used by some themes From cbf32913d20e25e40e3a4eac6d81f124ba976c00 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Tue, 8 Apr 2025 02:13:22 +0200 Subject: [PATCH 16/62] yup --- src/main/csp.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/csp.ts b/src/main/csp.ts index 82f1dd92..a9cb635a 100644 --- a/src/main/csp.ts +++ b/src/main/csp.ts @@ -15,7 +15,7 @@ const MediaAndCssSrc = [...MediaSrc, ...CssSrc]; const MediaScriptsAndCssSrc = [...MediaAndCssSrc, "script-src", "worker-src"]; // Plugins can whitelist their own domains by importing this object in their native.ts -// script and just adding to it +// script and just adding to it. But generally, you should just edit this file instead export const CspPolicies: PolicyMap = { "*.github.io": MediaAndCssSrc, // github pages, used by most themes From cb494a15c3cee107af6dcc60168a5e3591de5e84 Mon Sep 17 00:00:00 2001 From: thororen1234 <78185467+thororen1234@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:35:47 -0400 Subject: [PATCH 17/62] Mass Drop Plugins --- README.md | 12 +- .../betterAudioPlayer/index.tsx | 4 +- src/equicordplugins/cuteAnimeBoys/index.ts | 60 - src/equicordplugins/cuteNekos/index.ts | 29 - src/equicordplugins/cutePats/index.ts | 29 - .../gensokyoRadioRPC/index.tsx | 102 - .../gensokyoRadioRPC/native.ts | 20 - src/equicordplugins/gensokyoRadioRPC/types.ts | 57 - src/equicordplugins/glide/crosshair.png | Bin 108 -> 0 bytes src/equicordplugins/glide/generateTheme.tsx | 30 - src/equicordplugins/glide/index.tsx | 801 --- .../glide/themeDefinitions.tsx | 164 - src/equicordplugins/googleThat/index.ts | 77 - src/equicordplugins/identity/index.tsx | 148 - src/equicordplugins/identity/native.ts | 29 - .../moreStickers/lineEmojis.ts | 4 +- .../moreStickers/lineStickers.ts | 4 +- src/equicordplugins/moreStickers/utils.tsx | 10 +- .../sekaiStickers/Components/Canvas.tsx | 27 - .../sekaiStickers/Components/Picker.tsx | 51 - .../Components/SekaiStickersModal.tsx | 138 - .../sekaiStickers/characters.json.ts | 5035 ----------------- src/equicordplugins/sekaiStickers/index.tsx | 53 - .../sekaiStickers/kanade.svg.tsx | 21 - src/equicordplugins/tosuRPC/index.ts | 219 - src/equicordplugins/tosuRPC/type.ts | 652 --- src/equicordplugins/translatePlus/index.tsx | 77 - .../translatePlus/misc/languages.ts | 173 - .../translatePlus/misc/types.ts | 19 - src/equicordplugins/translatePlus/settings.ts | 35 - src/equicordplugins/translatePlus/style.css | 20 - .../translatePlus/utils/accessory.tsx | 42 - .../translatePlus/utils/icon.tsx | 17 - .../translatePlus/utils/translator.ts | 135 - 34 files changed, 9 insertions(+), 8285 deletions(-) delete mode 100644 src/equicordplugins/cuteAnimeBoys/index.ts delete mode 100644 src/equicordplugins/cuteNekos/index.ts delete mode 100644 src/equicordplugins/cutePats/index.ts delete mode 100644 src/equicordplugins/gensokyoRadioRPC/index.tsx delete mode 100644 src/equicordplugins/gensokyoRadioRPC/native.ts delete mode 100644 src/equicordplugins/gensokyoRadioRPC/types.ts delete mode 100644 src/equicordplugins/glide/crosshair.png delete mode 100644 src/equicordplugins/glide/generateTheme.tsx delete mode 100644 src/equicordplugins/glide/index.tsx delete mode 100644 src/equicordplugins/glide/themeDefinitions.tsx delete mode 100644 src/equicordplugins/googleThat/index.ts delete mode 100644 src/equicordplugins/identity/index.tsx delete mode 100644 src/equicordplugins/identity/native.ts delete mode 100644 src/equicordplugins/sekaiStickers/Components/Canvas.tsx delete mode 100644 src/equicordplugins/sekaiStickers/Components/Picker.tsx delete mode 100644 src/equicordplugins/sekaiStickers/Components/SekaiStickersModal.tsx delete mode 100644 src/equicordplugins/sekaiStickers/characters.json.ts delete mode 100644 src/equicordplugins/sekaiStickers/index.tsx delete mode 100644 src/equicordplugins/sekaiStickers/kanade.svg.tsx delete mode 100644 src/equicordplugins/tosuRPC/index.ts delete mode 100644 src/equicordplugins/tosuRPC/type.ts delete mode 100644 src/equicordplugins/translatePlus/index.tsx delete mode 100644 src/equicordplugins/translatePlus/misc/languages.ts delete mode 100644 src/equicordplugins/translatePlus/misc/types.ts delete mode 100644 src/equicordplugins/translatePlus/settings.ts delete mode 100644 src/equicordplugins/translatePlus/style.css delete mode 100644 src/equicordplugins/translatePlus/utils/accessory.tsx delete mode 100644 src/equicordplugins/translatePlus/utils/icon.tsx delete mode 100644 src/equicordplugins/translatePlus/utils/translator.ts diff --git a/README.md b/README.md index 8d061fa3..fa18471a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch ### Extra included plugins
-163 additional plugins +153 additional plugins ### All Platforms @@ -43,9 +43,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - CustomSounds by TheKodeToad & SpikeHD - CustomTimestamps by Rini & nvhrr - CustomUserColors by mochienya -- CuteAnimeBoys by ShadyGoat -- CuteNekos by echo -- CutePats by thororen - DecodeBase64 by ThePirateStoner - Demonstration by Samwich - DisableAnimations by S€th @@ -68,13 +65,10 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - FriendshipRanks by Samwich - FriendTags by Samwich - FullVcPfp by mochie -- GensokyoRadioRPC by RyanCaoDev & Prince527 - GifCollections by Aria & Creations - GifRoulette by Samwich - GitHubRepos by talhakf -- Glide by Samwich - GlobalBadges by HypedDomi & Hosted by Wolfie -- GoogleThat by Samwich - HideChatButtons by iamme - HideServers by bepvte - HolyNotes by Wolfie @@ -82,7 +76,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - HopOn by ImLvna - Husk by nin0dev - IconViewer by iamme -- Identity by Samwich - IgnoreCalls by TheArmagan - IgnoreTerms by D3SOX - ImagePreview by Creations @@ -132,7 +125,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - RPCEditor by Nyako & nin0dev - RPCStats by Samwich - SearchFix by Jaxx -- SekaiStickers by MaiKokain - ServerSearch by camila314 - ShowBadgesInChat by Inbestigator & KrystalSkull - SidebarChat by Joona @@ -151,8 +143,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch - Timezones by Aria - Title by Kyuuhachi - ToggleVideoBind by mochie -- TosuRPC by AutumnVN -- Translate+ by Prince527 & Ven - UnitConverter by sadan - UnlimitedAccounts by thororen - UnreadCountBadge by Joona diff --git a/src/equicordplugins/betterAudioPlayer/index.tsx b/src/equicordplugins/betterAudioPlayer/index.tsx index 0f942e90..86518258 100644 --- a/src/equicordplugins/betterAudioPlayer/index.tsx +++ b/src/equicordplugins/betterAudioPlayer/index.tsx @@ -66,8 +66,8 @@ async function addListeners(audioElement: HTMLAudioElement, url: string, parentB const madeURL = new URL(url); madeURL.searchParams.set("t", Date.now().toString()); - const corsProxyUrl = "https://corsproxy.io?" + encodeURIComponent(madeURL.href); - const response = await fetch(corsProxyUrl); + const { href } = madeURL; + const response = await fetch(href); const blob = await response.blob(); const blobUrl = URL.createObjectURL(blob); diff --git a/src/equicordplugins/cuteAnimeBoys/index.ts b/src/equicordplugins/cuteAnimeBoys/index.ts deleted file mode 100644 index 3f86d8e9..00000000 --- a/src/equicordplugins/cuteAnimeBoys/index.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { EquicordDevs } from "@utils/constants"; - -import { ApplicationCommandOptionType } from "../../api/Commands"; -import definePlugin from "../../utils/types"; - -function rand(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -async function fetchReddit(sub: string) { - const res = await fetch(`https://www.reddit.com/r/${sub}/top.json?limit=100&t=all`); - const resp = await res.json(); - try { - const { children } = resp.data; - const r = rand(0, children.length - 1); - return children[r].data.url; - } catch (err) { - console.error(resp); - console.error(err); - } - return ""; -} - -export default definePlugin({ - name: "CuteAnimeBoys", - authors: [EquicordDevs.ShadyGoat], - description: "Add a command to send cute anime boys in the chat", - commands: [{ - name: "anime-boys", - description: "Send cute anime boys", - options: [ - { - name: "cat", - description: "If set, this will send exclusively cute anime cat boys", - type: ApplicationCommandOptionType.BOOLEAN, - required: false, - }, - ], - - async execute(args) { - let sub = "cuteanimeboys"; - if (args.length > 0) { - const v = args[0].value as any as boolean; - if (v) { - sub = "animecatboys"; - } - } - - return { - content: await fetchReddit(sub), - }; - }, - }] -}); diff --git a/src/equicordplugins/cuteNekos/index.ts b/src/equicordplugins/cuteNekos/index.ts deleted file mode 100644 index e7d7a0f5..00000000 --- a/src/equicordplugins/cuteNekos/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; - -async function getcuteneko(): Promise { - const res = await fetch("https://nekos.best/api/v2/neko"); - const url = (await res.json()).results[0].url as string; - return url; -} - - - -export default definePlugin({ - name: "CuteNekos", - authors: [Devs.echo], - description: "Send Nekos to others", - commands: [{ - name: "nekos", - description: "Send Neko", - execute: async opts => ({ - content: await getcuteneko() - }) - }] -}); diff --git a/src/equicordplugins/cutePats/index.ts b/src/equicordplugins/cutePats/index.ts deleted file mode 100644 index 5ffaabde..00000000 --- a/src/equicordplugins/cutePats/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors* - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { EquicordDevs } from "@utils/constants"; -import definePlugin from "@utils/types"; - -async function getcutepats(): Promise { - const res = await fetch("https://api.waifu.pics/sfw/pat"); - const url = (await res.json()).url as string; - return url; -} - - - -export default definePlugin({ - name: "CutePats", - authors: [EquicordDevs.thororen], - description: "Sending Head Pats", - commands: [{ - name: "pat", - description: "Sends a headpat gif", - execute: async opts => ({ - content: await getcutepats() - }) - }] -}); diff --git a/src/equicordplugins/gensokyoRadioRPC/index.tsx b/src/equicordplugins/gensokyoRadioRPC/index.tsx deleted file mode 100644 index 4a166406..00000000 --- a/src/equicordplugins/gensokyoRadioRPC/index.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { definePluginSettings } from "@api/Settings"; -import { Devs, EquicordDevs } from "@utils/constants"; -import definePlugin, { OptionType, PluginNative, ReporterTestable } from "@utils/types"; -import { ApplicationAssetUtils, FluxDispatcher, Forms } from "@webpack/common"; - -import { Activity, ActivityFlag, ActivityType } from "./types"; - -const Native = VencordNative.pluginHelpers.GensokyoRadioRPC as PluginNative; - -const applicationId = "1253772057926303804"; - -function setActivity(activity: Activity | null) { - FluxDispatcher.dispatch({ - type: "LOCAL_ACTIVITY_UPDATE", - activity, - socketId: "GensokyoRadio", - }); -} - -function getImageAsset(data: string) { - return ApplicationAssetUtils.fetchAssetIds(applicationId, [data]).then(ids => ids[0]); -} - -const settings = definePluginSettings({ - refreshInterval: { - type: OptionType.SLIDER, - description: "The interval between activity refreshes (seconds)", - markers: [1, 2, 2.5, 3, 5, 10, 15], - default: 15, - restartNeeded: true, - } -}); - -export default definePlugin({ - name: "GensokyoRadioRPC", - description: "Discord rich presence for Gensokyo Radio!", - authors: [Devs.RyanCaoDev, EquicordDevs.Prince527], - reporterTestable: ReporterTestable.None, - - settingsAboutComponent() { - return <> - - Discord rich presence for Gensokyo Radio! - - ; - }, - - settings, - - start() { - this.updatePresence(); - this.updateInterval = setInterval(() => { this.updatePresence(); }, settings.store.refreshInterval * 1000); - }, - - stop() { - clearInterval(this.updateInterval); - FluxDispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", activity: null }); - }, - - updatePresence() { - this.getActivity().then(activity => { setActivity(activity); }); - }, - - async getActivity(): Promise { - const trackData = await Native.fetchTrackData(); - if (!trackData) return null; - - return { - application_id: applicationId, - - name: "Gensokyo Radio", - details: trackData.title, - state: trackData.artist, - - timestamps: { - // start: Date.now() - (trackData.position * 1000), - start: trackData.position * 1000, - // end: Date.now() - (trackData.position * 1000) + (trackData.duration * 1000), - end: trackData.duration * 1000, - }, - - assets: { - large_image: await getImageAsset(trackData.artwork), - large_text: trackData.album, - small_image: await getImageAsset("logo"), - small_text: "Gensokyo Radio" - }, - - buttons: undefined, - metadata: { button_urls: undefined }, - - type: ActivityType.LISTENING, - flags: ActivityFlag.INSTANCE, - }; - } -}); diff --git a/src/equicordplugins/gensokyoRadioRPC/native.ts b/src/equicordplugins/gensokyoRadioRPC/native.ts deleted file mode 100644 index 69dbe37a..00000000 --- a/src/equicordplugins/gensokyoRadioRPC/native.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import type { TrackData } from "./types"; - -export async function fetchTrackData(): Promise { - const song = await (await fetch("https://gensokyoradio.net/api/station/playing/")).json(); - - return { - title: song.SONGINFO.TITLE, - album: song.SONGINFO.ALBUM, - artist: song.SONGINFO.ARTIST, - position: song.SONGTIMES.SONGSTART, - duration: song.SONGTIMES.SONGEND, - artwork: song.MISC.ALBUMART ? `https://gensokyoradio.net/images/albums/500/${song.MISC.ALBUMART}` : "undefined", - }; -} diff --git a/src/equicordplugins/gensokyoRadioRPC/types.ts b/src/equicordplugins/gensokyoRadioRPC/types.ts deleted file mode 100644 index 3fa0464b..00000000 --- a/src/equicordplugins/gensokyoRadioRPC/types.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -export interface ActivityAssets { - large_image?: string; - large_text?: string; - small_image?: string; - small_text?: string; -} - -export interface Activity { - state: string; - details?: string; - timestamps?: { - start?: number; - end?: number; - }; - assets?: ActivityAssets; - buttons?: Array; - name: string; - application_id: string; - metadata?: { - button_urls?: Array; - }; - type: number; - flags: number; -} - -export interface ActivityAssets { - large_image?: string; - large_text?: string; - small_image?: string; - small_text?: string; -} - -export const enum ActivityType { - PLAYING = 0, - LISTENING = 2, -} - -export const enum ActivityFlag { - INSTANCE = 1 << 0 -} - -export interface TrackData { - title: string; - album: string; - artist: string; - - artwork: string; - - position: number; - duration: number; -} diff --git a/src/equicordplugins/glide/crosshair.png b/src/equicordplugins/glide/crosshair.png deleted file mode 100644 index 58e573623413336cc4c60aff7a514362b2da6e33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^EFjFm1|(O0oL2{=7>k44ofy`glX(f`sCl|LhDd}b z|M~yF-jWyGYFNa|z*->k+&(wxDo_W5r>mdKI;Vst E0BCC+%>V!Z diff --git a/src/equicordplugins/glide/generateTheme.tsx b/src/equicordplugins/glide/generateTheme.tsx deleted file mode 100644 index d3ca85f0..00000000 --- a/src/equicordplugins/glide/generateTheme.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -export function generateRandomColorHex(): string { - const r = Math.floor(Math.random() * 90); - const g = Math.floor(Math.random() * 90); - const b = Math.floor(Math.random() * 90); - - return `${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`; -} - -export function darkenColorHex(color: string): string { - const hex = color.replace(/^#/, ""); - const bigint = parseInt(hex, 16); - let r = (bigint >> 16) & 255; - let g = (bigint >> 8) & 255; - let b = bigint & 255; - r = Math.max(r - 5, 0); - g = Math.max(g - 5, 0); - b = Math.max(b - 5, 0); - return `${((r << 16) + (g << 8) + b).toString(16).padStart(6, "0")}`; -} - -export function saturateColorHex(color: string): string { - // i should really do something with this at some point :P - return color; -} diff --git a/src/equicordplugins/glide/index.tsx b/src/equicordplugins/glide/index.tsx deleted file mode 100644 index 5547133a..00000000 --- a/src/equicordplugins/glide/index.tsx +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { definePluginSettings, Settings } from "@api/Settings"; -import { Devs } from "@utils/constants"; -import definePlugin, { OptionType, StartAt } from "@utils/types"; -import { findComponentByCodeLazy } from "@webpack"; -import { Button, Clipboard, Forms, TextInput, Toasts, useState } from "@webpack/common"; - -import { darkenColorHex, generateRandomColorHex, saturateColorHex } from "./generateTheme"; -import { themes } from "./themeDefinitions"; - -export interface ThemePreset { - bgcol: string; - accentcol: string; - textcol: string; - brand: string; - name: string; -} - -let setPreset; - - -function LoadPreset(preset?: ThemePreset) { - if (setPreset === settings.store.ColorPreset) { return; } - const theme: ThemePreset = preset == null ? themes[settings.store.ColorPreset] : preset; - setPreset = settings.store.ColorPreset; - settings.store.Primary = theme.bgcol; - settings.store.Accent = theme.accentcol; - settings.store.Text = theme.textcol; - settings.store.Brand = theme.brand; - injectCSS(); -} - -function mute(hex, amount) { - hex = hex.replace(/^#/, ""); - const bigint = parseInt(hex, 16); - let r = (bigint >> 16) & 255; - let g = (bigint >> 8) & 255; - let b = bigint & 255; - r = Math.max(r - amount, 0); - g = Math.max(g - amount, 0); - b = Math.max(b - amount, 0); - return "#" + ((r << 16) + (g << 8) + b).toString(16).padStart(6, "0"); -} - -function copyPreset(name: string) { - const template = - ` -{ - bgcol: "${settings.store.Primary}", - accentcol: "${settings.store.Accent}", - textcol: "${settings.store.Text}", - brand: "${settings.store.Brand}", - name: "${name}" -} - `; - if (Clipboard.SUPPORTS_COPY) { - Clipboard.copy(template); - } - -} - -function CopyPresetComponent() { - - const [inputtedName, setInputtedName] = useState(""); - return ( - <> - - {"Preset name"} - - - - - - ); -} - -const ColorPicker = findComponentByCodeLazy("#{intl::USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR}", ".BACKGROUND_PRIMARY)"); - -export function generateAndApplyProceduralTheme() { - - const randomBackgroundColor = generateRandomColorHex(); - const accentColor = darkenColorHex(randomBackgroundColor); - const textColor = "ddd0d0"; - const brandColor = saturateColorHex(randomBackgroundColor); - - settings.store.Primary = randomBackgroundColor; - settings.store.Accent = accentColor; - settings.store.Text = textColor; - settings.store.Brand = brandColor; - - injectCSS(); -} - -const settings = definePluginSettings({ - serverListAnim: { - type: OptionType.BOOLEAN, - description: "Toggles if the server list hides when not hovered", - default: false, - onChange: () => injectCSS() - }, - memberListAnim: { - type: OptionType.BOOLEAN, - description: "Toggles if the member list hides when not hovered", - default: true, - onChange: () => injectCSS() - }, - privacyBlur: { - type: OptionType.BOOLEAN, - description: "Blurs potentially sensitive information when not tabbed in", - default: false, - onChange: () => injectCSS() - }, - tooltips: { - type: OptionType.BOOLEAN, - description: "If tooltips are displayed in the client", - default: false, - onChange: () => injectCSS() - }, - customFont: { - type: OptionType.STRING, - description: "The google fonts @import for a custom font (blank to disable)", - default: "@import url('https://fonts.googleapis.com/css2?family=Poppins&wght@500&display=swap');", - onChange: injectCSS - }, - animationSpeed: { - type: OptionType.STRING, - description: "The speed of animations", - default: "0.2", - onChange: injectCSS - }, - colorsEnabled: { - type: OptionType.BOOLEAN, - description: "Whether or not to enable theming", - onChange: () => injectCSS() - }, - ColorPreset: { - type: OptionType.SELECT, - description: "Some pre-made color presets (more soon hopefully)", - options: themes.map(theme => ({ label: theme.name, value: themes.indexOf(theme), default: themes.indexOf(theme) === 0 })), - onChange: () => { LoadPreset(); } - }, - Primary: { - type: OptionType.COMPONENT, - description: "", - default: "000000", - component: () => - }, - Accent: { - type: OptionType.COMPONENT, - description: "", - default: "313338", - component: () => - }, - Text: { - type: OptionType.COMPONENT, - description: "", - default: "ffffff", - component: () => - }, - Brand: { - type: OptionType.COMPONENT, - description: "", - default: "ffffff", - component: () => - }, - pastelStatuses: { - type: OptionType.BOOLEAN, - description: "Changes the status colors to be more pastel (fits with the catppuccin presets)", - default: true, - onChange: () => injectCSS() - }, - DevTools: - { - type: OptionType.COMPONENT, - description: "meow", - default: "", - component: () => - }, - ExportTheme: - { - type: OptionType.COMPONENT, - description: "", - default: "", - component: () => - } -}); - - -export function ColorPick({ propertyname }: { propertyname: string; }) { - return ( - -
- {propertyname} - - { - const hexColor = color.toString(16).padStart(6, "0"); - settings.store[propertyname] = hexColor; - injectCSS(); - } - } - showEyeDropper={false} - /> -
- ); -} - - -function copyCSS() { - if (Clipboard.SUPPORTS_COPY) { - Clipboard.copy(getCSS(parseFontContent())); - } -} - -function parseFontContent() { - const fontRegex = /family=([^&;,:]+)/; - const customFontString: string = Settings.plugins.Glide.customFont; - if (customFontString == null) { return; } - const fontNameMatch: RegExpExecArray | null = fontRegex.exec(customFontString); - const fontName = fontNameMatch ? fontNameMatch[1].replace(/[^a-zA-Z0-9]+/g, " ") : ""; - return fontName; -} -function injectCSS() { - if (Settings.plugins.Glide.enabled) { - - const fontName = parseFontContent(); - const theCSS = getCSS(fontName); - - const elementToRemove = document.getElementById("GlideStyleInjection"); - if (elementToRemove) { - elementToRemove.remove(); - } - const styleElement = document.createElement("style"); - styleElement.id = "GlideStyleInjection"; - styleElement.textContent = theCSS; - document.documentElement.appendChild(styleElement); - } -} - -function getCSS(fontName) { - return ` - /* IMPORTS */ - - /* Fonts */ - @import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap'); - @import url('https://fonts.googleapis.com/css2?family=Fira+Code&display=swap'); - ${Settings.plugins.Glide.customFont} - - /*Settings things*/ - /*Server list animation*/ - ${Settings.plugins.Glide.serverListAnim ? ` - .guilds_a4d4d9 { - width: 10px; - transition: width var(--animspeed) ease 0.1s, opacity var(--animspeed) ease 0.1s; - opacity: 0; - } - .guilds_a4d4d9:hover { - width: 65px; - opacity: 100; - } - ` : ""} - /*Member list anim toggle*/ - ${Settings.plugins.Glide.memberListAnim ? ` - .container_cbd271 - { - width: 60px; - opacity: 0.2; - transition: width var(--animspeed) ease 0.1s, opacity var(--animspeed) ease 0.1s; - - } - .container_cbd271:hover - { - width: 250px; - opacity: 1; - } - ` : ""} - /*Privacy blur*/ - ${Settings.plugins.Glide.privacyBlur ? ` - .header_f9f2ca, - .container_ee69e0, - .title_a7d72e, - .layout_ec8679, - [aria-label="Members"] { - filter: blur(0); - transition: filter 0.2s ease-in-out; - } - - body:not(:hover) .header_f9f2ca, - body:not(:hover) .container_ee69e0, - body:not(:hover) .title_a7d72e, - body:not(:hover) [aria-label="Members"], - body:not(:hover) .layout_ec8679 { - filter: blur(5px); - } - ` : ""} - /*Tooltips*/ - [class*="tooltip"] - { - ${!Settings.plugins.Glide.tooltips ? "display: none !important;" : ""} - } - /*Root configs*/ - :root - { - --animspeed: ${Settings.plugins.Glide.animationSpeed + "s"}; - --font-primary: ${(fontName.length > 0 ? fontName : "Nunito")}; - ${Settings.plugins.Glide.colorsEnabled ? ` - --accent: #${Settings.plugins.Glide.Accent}; - --bgcol: #${Settings.plugins.Glide.Primary}; - --text: #${Settings.plugins.Glide.Text}; - --brand: #${Settings.plugins.Glide.Brand}; - --mutedtext: ${mute(Settings.plugins.Glide.Text, 20)}; - --mutedbrand: ${mute(Settings.plugins.Glide.Brand, 10)}; - --mutedaccent: ${mute(Settings.plugins.Glide.Accent, 10)}; - ` : ""} - } -:root -{ - - /*VARIABLES*/ - - /*editable variables. Feel free to mess around with these to your hearts content, i recommend not editing the logic variables unless you have an understanding of css*/ - --glowcol: rgba(0, 0, 0, 0); - --mentioncol: rgb(0, 0, 0); - --mentionhighlightcol: rgb(0, 0, 0); - --linkcol: rgb(95, 231, 255); - --highlightcol: rgb(95, 231, 255); - - - - /*COLOR ASSIGNING (most of these probably effect more than whats commented)*/ - ${Settings.plugins.Glide.colorsEnabled ? ` - /*accent based*/ - - /*buttons*/ - --button-secondary-background: var(--accent); - - /*also buttons*/ - --brand-experiment: var(--brand); - --brand-experiment-560: var(--brand); - --brand-500: var(--brand); - - /*message bar*/ - --channeltextarea-background: var(--accent); - - /*selected dm background*/ - --background-modifier-selected: var(--accent); - - /*emoji autofill*/ - --primary-630: var(--accent); - - /*plugin grid square and nitro shop*/ - --background-secondary-alt: var(--accent); - - /*modal background, self explanatory*/ - --modal-background: var(--accent); - - /*color of the background of mention text*/ - --mention-background: var(--accent); - --input-background: var(--accent); - - /*the side profile thingy*/ - --profile-body-background-color: var(--accent); - - /*the weird hover thing idk*/ - --background-modifier-hover: var(--mutedaccent) !important; - - - /*background based*/ - - /*primary color, self explanatory*/ - --background-primary: var(--bgcol); - - /*dm list*/ - --background-secondary: var(--bgcol); - - /*outer frame and search background*/ - --background-tertiary: var(--bgcol); - - - /*friends header bar*/ - --bg-overlay-2: var(--bgcol); - - /*user panel*/ - --bg-overlay-1: var(--bgcol); - - /*call thingy*/ - --bg-overlay-app-frame: var(--bgcol); - - /*shop*/ - --background-mentioned-hover: var(--bgcol) !important; - --background-mentioned: var(--bgcol) !important; - - - - - /*other*/ - - /*mention side line color color*/ - --info-warning-foreground: var(--mentionhighlightcol); - - /*text color of mention text*/ - --mention-foreground: white; - - /*Link color*/ - --text-link: var(--linkcol); - --header-primary: var(--text); - --header-secondary: var(--text); - --font-display: var(--text); - --text-normal: var(--text); - --text-muted: var(--mutedtext); - --channels-default: var(--mutedtext); - --interactive-normal: var(--text) !important; - --white-500: var(--text); - -} - - - /*EXTRA COLORS*/ - - [class*="tooltipPrimary__"] - { - background-color: var(--mutedaccent) !important; - } - [class*="tooltipPointer_"] - { - border-top-color: var(--mutedaccent) !important; - } - /*sorry, forgot to document what these are when i was adding them*/ - .inspector_c3120f, .scroller_d53d65, .unicodeShortcut_dfa278 - { - background-color: var(--bgcol); - } - .inner_effbe2 - { - background-color: var(--accent); - } - /*recolor embeds*/ - [class^="embedWrap"] - { - border-color: var(--accent) !important; - background: var(--accent); - } - /*emoji menu recolor*/ - .contentWrapper_af5dbb, .header_a3bc57 - { - background-color: var(--bgcol); - } - /*vc background recolor*/ - .root_dd069c - { - background-color: var(--bgcol); - } - - /*Fix the forum page*/ - /*Set the bg color*/ - .container_a6d69a - { - background-color: var(--bgcol); - } - /*Recolor the posts to the accent*/ - .container_d331f1 - { - background-color: var(--accent); - } - - /*Recolor the background of stickers in the sticker picker that dont take up the full 1:1 ratio*/ - [id^="sticker-picker-grid"] - { - background-color: var(--bgcol); - } - /* profile sidebar*/ - [class="none_eed6a8 scrollerBase_eed6a8"] - { - background-color: var(--bgcol) !important; - } - /*Recolor the emoji, gif, and sticker picker selected button*/ - .navButtonActive_af5dbb, .stickerCategoryGenericSelected_a7a485, .categoryItemDefaultCategorySelected_dfa278 - { - background-color: var(--accent) !important; - } - - /*side profile bar*/ - [class="none_c49869 scrollerBase_c49869"] - { - background-color: var(--bgcol) !important; - } - .userPanelOverlayBackground_a2b6ae, .badgeList_ab525a - { - background-color: var(--accent) !important; - border-radius: 15px !important; - } - /*uhhhhhhhhhhhhhhh*/ - .headerText_c47fa9 - { - color: var(--text) !important; - } - /*message bar placeholder*/ - .placeholder_a552a6 - { - color: var(--mutedtext) !important - } - .menu_d90b3d - { - background: var(--accent) !important; - } - .messageGroupWrapper_ac90a2, .header_ac90a2 - { - background-color: var(--primary); - } - ${settings.store.pastelStatuses ? - ` - /*Pastel statuses*/ - rect[fill='#23a55a'], svg[fill='#23a55a'] { - fill: #80c968 !important; - } - rect[fill='#f0b232'], svg[fill='#f0b232'] { - fill: #e7ca45 !important; - } - rect[fill='#f23f43'], svg[fill='#f23f43'] { - fill: #e0526c !important; - } - rect[fill='#80848e'], svg[fill='#80848e'] { - fill: #696e88 !important; - } - rect[fill='#593695'], svg[fill='#593695'] { - fill: #ac7de6 important; - } - ` : ""} - .name_d8bfb3 - { - color: var(--text) !important; - } - .unread_d8bfb3 - { - background-color: var(--text) !important; - }` : ""} - - /*ROUNDING (rounding)*/ - - /*round message bar, some buttons, dm list button, new messages notif bar, channel buttons, emoji menu search bar, context menus, account connections(in that order)*/ - .scrollableContainer_bdf0de, .button_dd4f85, .interactive_f5eb4b, .newMessagesBar_cf58b5, .link_d8bfb3, .searchBar_c6ee36, .menu_d90b3d, .connectedAccountContainer_ab12c6 - { - border-radius: 25px; - } - /*round emojis seperately (and spotify activity icons)*/ - [data-type="emoji"], [class*="Spotify"] - { - border-radius: 5px; - } - /*round gifs and stickers (and maybe images idk lmao), and embeds*/ - [class^="imageWr"], [data-type="sticker"], [class^="embed"] - { - border-radius: 20px; - } - - .item_d90b3d - { - border-radius: 15px; - } - - - - /*slightly move messages right when hovered*/ - .cozyMessage_d5deea - { - left: 0px; - - transition-duration: 0.2s; - } - .cozyMessage_d5deea:hover - { - left: 3px; - } - - - /*CONTENT (Typically changing values or hiding elements)*/ - - /*remove status text in user thing*/ - .panelSubtextContainer_b2ca13 - { - display: none !important; - } - /*Hide most of the ugly useless scrollbars*/ - ::-webkit-scrollbar - { - display:none; - } - - - /*Hide user profile button, the dm favourite, dm close, support, gift buttons, the now playing column, and the channel + favourite icons*/ - [aria-label="Hide User Profile"], .favoriteIcon_c91bad, .closeButton_c91bad, [href="https://support.discord.com"], .nowPlayingColumn_c2739c, button[aria-label="Send a gift"], .icon_d8bfb3, .iconContainer_d8bfb3 - { - display :none; - } - - /*yeet the shitty nitro and family link tabs that no one likes*/ - .channel_c91bad[aria-posinset="2"], - .familyCenterLinkButton_f0963d - { - display: none; - - } - /*Remove the buttons at the bottom of the user pop out (seriously, who wanted this?)*/ - .addFriendSection__413d3 - { - display: none; - } - - /*No more useless spotify activity header*/ - .headerContainer_c1d9fd - { - display: none; - } - /*hide sidebar connections*/ - .profilePanelConnections_b433b4 - { - display: none; - } - /*pad the message bar right slightly. Not sure what caused the buttons to flow out of it, might be something in the theme :shrug:*/ - .inner_bdf0de - { - padding-right: 10px; - } - - /*Yeet hypesquad badges (who cares)*/ - [aria-label*="HypeSquad"] - { - display: none !important; - } - - /*Hide icon on file uploading status*/ - .icon_f46c86 - { - display: none; - } - - /*hide the play button while a soundmoji is playing*/ - .playing_bf9443 [viewBox="0 0 24 24"] - { - display:none; - } - /*hide the public servers button on member list*/ - [aria-label="Explore Discoverable Servers"] - { - display: none; - } - /*fix context menu being not symmetrical*/ - .scroller_d90b3d - { - padding: 6px 8px !important; - } - /*Hide the icon that displays what platform the user is listening with on spotify status*/ - .platformIcon_c1d9fd - { - display: none !important; - } - /*hide the album name on spotify statuses (who cares)*/ - [class="state_c1d9fd ellipsis_c1d9fd textRow_c1d9fd"] - { - display: none; - } - /*space the connections a bit better*/ - .userInfoSection_a24910 - { - margin-bottom: 0px; - padding-bottom: 0px; - } - /*Space channels*/ - .containerDefault_f6f816 - { - padding-top: 5px; - } - - /*round banners in profile popout*/ - .banner_d5fdb1:not(.panelBanner_c3e427) - { - border-radius: 20px; - } - /*round the user popout*/ - .userPopoutOuter_c69a7b - { - border-radius: 25px; - } - /*round the inner profile popout*/ - [class="userPopoutInner_c69a7b userProfileInner_c69a7b userProfileInnerThemedWithBanner_c69a7b"]::before - { - border-radius: 20px; - } - .footer_be6801 - { - display: none !important; - } - - /*STYLING (Modification of content to fit the theme)*/ - - /*Round and scale down the users banner*/ - .panelBanner_c3e427 - { - border-radius: 20px; - transform: scale(0.95); - } - /*add a soft glow to message bar contents, user panel, dms, channel names (in that order)*/ - .inner_bdf0de .layout_ec8679, .name_d8bfb3 - { - filter: drop-shadow(0px 0px 3px var(--glowcol)); - } - [type="button"] - { - transition: all 0.1s ease-in-out; - } - [type="button"]:hover - { - filter: drop-shadow(0px 0px 3px var(--glowcol)); - } - - /*Change the font*/ - :root - { - --font-code: "Fira Code"; - } - - /*Round all status symbols. basically does what that one plugin does but easier (disabled because of a bug) - .pointerEvents_c51b4e - { - mask: url(#svg-mask-status-online); - } - */ - - /*pfp uploader crosshair*/ - .overlayAvatar_ba5b9e - { - background-image: url(https://raw.githubusercontent.com/Equicord/Equicord/main/src/equicordplugins/glide/crosshair.png); - background-repeat: no-repeat; - background-position-x: 50%; - background-position-y: 50%; - border-width: 2px; - } - - /*change highlighted text color*/ - ::selection - { - color: inherit; - background-color: transparent; - text-shadow: 0px 0px 2px var(--highlightcol); - } - /*hide the line between connections and note*/ - [class="connectedAccounts_ab12c6 userInfoSection_a24910"] - { - border-top: transparent !important; - } - .container_cebd1c:not(.checked_cebd1c) - { - background-color: var(--mutedbrand) !important; - } - .checked_cebd1c - { - background-color: var(--brand) !important; - } -`; -} - -export default definePlugin({ - name: "Glide", - description: "A sleek, rounded theme for discord.", - authors: [Devs.Samwich], - settings, - start() { - injectCSS(); - }, - stop() { - const injectedStyle = document.getElementById("GlideStyleInjection"); - if (injectedStyle) { - injectedStyle.remove(); - } - }, - startAt: StartAt.DOMContentLoaded, - // preview thing, kinda low effort but eh - settingsAboutComponent: () => -}); diff --git a/src/equicordplugins/glide/themeDefinitions.tsx b/src/equicordplugins/glide/themeDefinitions.tsx deleted file mode 100644 index bc16de89..00000000 --- a/src/equicordplugins/glide/themeDefinitions.tsx +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { ThemePreset } from "."; - -export const themes: ThemePreset[] = [ - { - bgcol: "000000", - accentcol: "020202", - textcol: "c0d5e4", - brand: "070707", - name: "Amoled" - }, - { - bgcol: "0e2936", - accentcol: "0c2430", - textcol: "99b0bd", - brand: "124057", - name: "Solar" - }, - { - bgcol: "0e0e36", - accentcol: "0e0c30", - textcol: "bdbfd8", - brand: "171750", - name: "Indigo" - }, - { - bgcol: "8a2b5f", - accentcol: "812658", - textcol: "ffedfb", - brand: "b23982", - name: "Grapefruit" - }, - { - bgcol: "410b05", - accentcol: "360803", - textcol: "f8e6e6", - brand: "681109", - name: "Crimson" - }, - { - bgcol: "184e66", - accentcol: "215a72", - textcol: "d0efff", - brand: "2d718f", - name: "Azure" - }, - { - bgcol: "1d091a", - accentcol: "240d21", - textcol: "f3e1f0", - brand: "411837", - name: "Blackberry" - }, - { - bgcol: "1f073b", - accentcol: "250b44", - textcol: "dfd7e9", - brand: "340d63", - name: "Porple" - }, - { - bgcol: "0a0a0a", - accentcol: "0f0f0f", - textcol: "c9c9c9", - brand: "0a0a0a", - name: "Charcoal" - }, - { - bgcol: "00345b", - accentcol: "002f53", - textcol: "e7d8df", - brand: "944068", - name: "Lofi Pop" - }, - { - bgcol: "471b05", - accentcol: "4e2009", - textcol: "ffffff", - brand: "903e14", - name: "Oaken" - }, - { - bgcol: "040b2b", - accentcol: "000626", - textcol: "ddd0d0", - brand: "040b2b", - name: "Deep Blue" - }, - { - bgcol: "32464a", - accentcol: "2d4145", - textcol: "ddd0d0", - brand: "32464a", - name: "Steel Blue" - }, - { - bgcol: "31031f", - accentcol: "2c001a", - textcol: "ddd0d0", - brand: "31031f", - name: "Velvet" - }, - { - bgcol: "22111f", - accentcol: "1d0c1a", - textcol: "ddd0d0", - brand: "22111f", - name: "Really Oddly Depressed Purple" - }, - { - bgcol: "2b3959", - accentcol: "263454", - textcol: "ddd0d0", - brand: "2b3959", - name: "Light Sky" - }, - { - bgcol: "06403d", - accentcol: "013b38", - textcol: "ddd0d0", - brand: "06403d", - name: "Tealish" - }, - { - bgcol: "273b0b", - accentcol: "223606", - textcol: "ddd0d0", - brand: "273b0b", - name: "Leaf (or a tree perhaps)" - }, - { - bgcol: "1a2022", - accentcol: "151b1d", - textcol: "ddd0d0", - brand: "1a2022", - name: "Steel" - }, - { - bgcol: "1e1e2e", - accentcol: "181825", - textcol: "cdd6f4", - brand: "45475a", - name: "Catppuccin Mocha" - }, - { - bgcol: "303446", - accentcol: "292c3c", - textcol: "c6d0f5", - brand: "414559", - name: "Catppuccin Frappé" - }, - { - bgcol: "6b422e", - accentcol: "754b36", - textcol: "ead9c9", - brand: "8b5032", - name: "Relax" - } -]; diff --git a/src/equicordplugins/googleThat/index.ts b/src/equicordplugins/googleThat/index.ts deleted file mode 100644 index fedf8acf..00000000 --- a/src/equicordplugins/googleThat/index.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { ApplicationCommandOptionType, findOption } from "@api/Commands"; -import { definePluginSettings } from "@api/Settings"; -import { Devs } from "@utils/constants"; -import definePlugin, { OptionType } from "@utils/types"; -function getMessage(opts) { - const inputOption = findOption(opts, "input", ""); - - const queryURL = "" + searchEngines[settings.store.defaultEngine] + encodeURIComponent(inputOption); - - if (settings.store.hyperlink) { - return `[${inputOption}](${queryURL})`; - } - else { - return queryURL; - } -} - -const searchEngines = { - "Google": "https://www.google.com/search?q=", - "Bing": "https://www.bing.com/search?q=", - "Yahoo": "https://search.yahoo.com/search?p=", - "DuckDuckGo": "https://duckduckgo.com/?q=", - "Baidu": "https://www.baidu.com/s?wd=", - "Yandex": "https://yandex.com/search/?text=", - "Ecosia": "https://www.ecosia.org/search?q=", - "Ask": "https://www.ask.com/web?q=", - "LetMeGoogleThatForYou": "https://letmegooglethat.com/?q=" -}; - -const settings = definePluginSettings({ - hyperlink: { - type: OptionType.BOOLEAN, - description: "If the sent link should hyperlink with the query as the label", - default: true - }, - defaultEngine: - { - type: OptionType.SELECT, - description: "The search engine to use", - options: Object.keys(searchEngines).map((key, index) => ({ - label: key, - value: key, - default: index === 0 - })) - } -}); - -export default definePlugin({ - name: "GoogleThat", - description: "Adds a command to send a google search link to a query", - authors: [Devs.Samwich], - tags: ["search", "google", "query", "duckduckgo", "command"], - settings, - commands: [ - { - name: "googlethat", - description: "send a search engine link to a query", - options: [ - { - name: "input", - description: "The search query", - type: ApplicationCommandOptionType.STRING, - required: true, - } - ], - execute: opts => ({ - content: getMessage(opts) - }), - } - ] -}); diff --git a/src/equicordplugins/identity/index.tsx b/src/equicordplugins/identity/index.tsx deleted file mode 100644 index ac301ce3..00000000 --- a/src/equicordplugins/identity/index.tsx +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { DataStore } from "@api/index"; -import { Flex } from "@components/Flex"; -import { Devs, EquicordDevs } from "@utils/constants"; -import definePlugin, { PluginNative } from "@utils/types"; -import { findComponentByCodeLazy } from "@webpack"; -import { Alerts, Button, FluxDispatcher, Forms, Toasts, UserProfileStore, UserStore } from "@webpack/common"; -const native = VencordNative.pluginHelpers.Identity as PluginNative; - -const CustomizationSection = findComponentByCodeLazy(".customizationSectionBackground"); - -async function SetNewData() { - const PersonData = JSON.parse(await native.RequestRandomUser()); - console.log(PersonData); - - const pfpBase64 = JSON.parse(await native.ToBase64ImageUrl({ imgUrl: PersonData.picture.large })).data; - - // holy moly - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_AVATAR", avatar: pfpBase64 }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_GLOBAL_NAME", globalName: `${PersonData.name.first} ${PersonData.name.last}` }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_PRONOUNS", pronouns: `${PersonData.gender === "male" ? "he/him" : PersonData.gender === "female" ? "she/her" : ""}` }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_BANNER", banner: null }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_ACCENT_COLOR", color: null }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_THEME_COLORS", themeColors: [null, null] }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_BIO", bio: `Hello! I am ${PersonData.name.first} ${PersonData.name.last}` }); -} - -async function SaveData() { - const userData = UserProfileStore.getUserProfile(UserStore.getCurrentUser().id); - - // the getUserProfile function doesn't return all the information we need, so we append the standard user object data to the end - const extraUserObject: any = { extraUserObject: UserStore.getCurrentUser() }; - - const pfp = JSON.parse(await native.ToBase64ImageUrl({ imgUrl: `https://cdn.discordapp.com/avatars/${userData.userId}/${extraUserObject.extraUserObject.avatar}.webp?size=4096` })).data; - const banner = JSON.parse(await native.ToBase64ImageUrl({ imgUrl: `https://cdn.discordapp.com/banners/${userData.userId}/${userData.banner}.webp?size=4096` })).data; - - const fetchedBase64Data = - { - pfpBase64: pfp, - bannerBase64: banner - }; - - DataStore.set("identity-saved-base", JSON.stringify({ ...userData, ...extraUserObject, ...{ fetchedBase64Data: fetchedBase64Data } })); -} - -async function LoadData() { - const userDataMaybeNull = await DataStore.get("identity-saved-base"); - if (!userDataMaybeNull) { - Toasts.show({ message: "No saved base! Save one first.", id: Toasts.genId(), type: Toasts.Type.FAILURE }); - return; - } - - const userData = JSON.parse(userDataMaybeNull); - - console.log(userData); - - const { pfpBase64, bannerBase64 } = userData.fetchedBase64Data; - - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_AVATAR", avatar: pfpBase64 }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_GLOBAL_NAME", globalName: userData.extraUserObject.globalName }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_PRONOUNS", pronouns: userData.pronouns }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_BANNER", banner: bannerBase64 }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_ACCENT_COLOR", color: userData.accentColor }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_THEME_COLORS", themeColors: userData.themeColors }); - FluxDispatcher.dispatch({ type: "USER_SETTINGS_ACCOUNT_SET_PENDING_BIO", bio: userData.bio }); -} - -function ResetCard() { - return ( - - - - - - - - ); -} - -export default definePlugin({ - name: "Identity", - description: "Allows you to edit your profile to a random fake person with the click of a button", - authors: [Devs.Samwich, EquicordDevs.port22exposed], - ResetCard: ResetCard, - patches: [ - { - find: "DefaultCustomizationSections", - replacement: { - match: /(?<=#{intl::USER_SETTINGS_AVATAR_DECORATION}\)},"decoration"\),)/, - replace: "$self.ResetCard()," - } - }, - ] -}); diff --git a/src/equicordplugins/identity/native.ts b/src/equicordplugins/identity/native.ts deleted file mode 100644 index b838900c..00000000 --- a/src/equicordplugins/identity/native.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -export async function RequestRandomUser() { - const data = await fetch("https://randomuser.me/api").then(e => e.json()); - - return JSON.stringify(data.results[0]); -} - -export async function ToBase64ImageUrl(_, data) { - const { imgUrl } = data; - - try { - const fetchImageUrl = await fetch(imgUrl); - const responseArrBuffer = await fetchImageUrl.arrayBuffer(); - - const toBase64 = - `data:${fetchImageUrl.headers.get("Content-Type") || "image/png"};base64,${Buffer.from(responseArrBuffer).toString("base64")}`; - - return JSON.stringify({ data: toBase64 }); - - } catch (error) { - console.error("Error converting image to Base64:", error); - return JSON.stringify({ error: "Failed to convert image to Base64" }); - } -} diff --git a/src/equicordplugins/moreStickers/lineEmojis.ts b/src/equicordplugins/moreStickers/lineEmojis.ts index 39c0e4d3..de631bfb 100644 --- a/src/equicordplugins/moreStickers/lineEmojis.ts +++ b/src/equicordplugins/moreStickers/lineEmojis.ts @@ -5,7 +5,7 @@ */ import { LineEmoji, LineEmojiPack, Sticker, StickerPack } from "./types"; -import { corsFetch } from "./utils"; +import { lineFetch } from "./utils"; export interface StickerCategory { title: string; @@ -131,7 +131,7 @@ export function isLineEmojiPackHtml(html: string): boolean { * @return {Promise} The sticker pack. */ export async function getStickerPackById(id: string, region = "en"): Promise { - const res = await corsFetch(`https://store.line.me/emojishop/product/${id}/${region}`); + const res = await lineFetch(`https://store.line.me/emojishop/product/${id}/${region}`); const html = await res.text(); return parseHtml(html); diff --git a/src/equicordplugins/moreStickers/lineStickers.ts b/src/equicordplugins/moreStickers/lineStickers.ts index 66bb7c71..ee4988ca 100644 --- a/src/equicordplugins/moreStickers/lineStickers.ts +++ b/src/equicordplugins/moreStickers/lineStickers.ts @@ -5,7 +5,7 @@ */ import { LineSticker, LineStickerPack, Sticker, StickerPack } from "./types"; -import { corsFetch } from "./utils"; +import { lineFetch } from "./utils"; export interface StickerCategory { title: string; @@ -131,7 +131,7 @@ export function isLineStickerPackHtml(html: string): boolean { * @return {Promise} The sticker pack. */ export async function getStickerPackById(id: string, region = "en"): Promise { - const res = await corsFetch(`https://store.line.me/stickershop/product/${id}/${region}`); + const res = await lineFetch(`https://store.line.me/stickershop/product/${id}/${region}`); const html = await res.text(); return parseHtml(html); diff --git a/src/equicordplugins/moreStickers/utils.tsx b/src/equicordplugins/moreStickers/utils.tsx index f73a5e4c..cb928aee 100644 --- a/src/equicordplugins/moreStickers/utils.tsx +++ b/src/equicordplugins/moreStickers/utils.tsx @@ -14,14 +14,8 @@ import { FFmpegState } from "./types"; export const cl = classNameFactory("vc-more-stickers-"); export const clPicker = (className: string, ...args: any[]) => cl("picker-" + className, ...args); -const CORS_PROXY = "https://corsproxy.io?"; - -function corsUrl(url: string | URL) { - return CORS_PROXY + encodeURIComponent(url.toString()); -} - -export function corsFetch(url: string | URL, init?: RequestInit | undefined) { - return fetch(corsUrl(url), init); +export function lineFetch(url: string | URL, init?: RequestInit | undefined) { + return fetch(url, init); } export class Mutex { diff --git a/src/equicordplugins/sekaiStickers/Components/Canvas.tsx b/src/equicordplugins/sekaiStickers/Components/Canvas.tsx deleted file mode 100644 index c795290c..00000000 --- a/src/equicordplugins/sekaiStickers/Components/Canvas.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { useEffect, useRef } from "@webpack/common"; - -const Canvas = props => { - - const { draw, ...rest } = props; - const canvasRef = useRef(null); - - useEffect(() => { - - const canvas = canvasRef.current; - // @ts-ignore - const context = canvas.getContext("2d"); - - draw(context); - - }, [draw]); - - return ; -}; - -export default Canvas; diff --git a/src/equicordplugins/sekaiStickers/Components/Picker.tsx b/src/equicordplugins/sekaiStickers/Components/Picker.tsx deleted file mode 100644 index 7e0254e2..00000000 --- a/src/equicordplugins/sekaiStickers/Components/Picker.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { Flex } from "@components/Flex"; -import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal"; -import { React, ScrollerThin, Text, TextInput } from "@webpack/common"; - -import { characters } from "../characters.json"; - -export default function CharSelectModal({ modalProps, setCharacter }: { modalProps: ModalProps; setCharacter?: any; }) { - const [search, setSearch] = React.useState(""); - - const memoedSearchChar = React.useMemo(() => { - const s = search.toLowerCase(); - return characters.map((c, index) => { - if ( - s === c.id || - c.name.toLowerCase().includes(s) || - c.character.toLowerCase().includes(s) - ) { - return ( - { modalProps.onClose(); setCharacter(index); }} src={`https://st.ayaka.one/img/${c.img}`} srcSet={`https://st.ayaka.one/img/${c.img}`} loading="lazy" /> - ); - } - - return null; - }); - }, [search, characters]); - return ( - - - Select character menu - - - - - setSearch(e)} /> - -
- {memoedSearchChar} -
-
-
- -
-
- ); -} diff --git a/src/equicordplugins/sekaiStickers/Components/SekaiStickersModal.tsx b/src/equicordplugins/sekaiStickers/Components/SekaiStickersModal.tsx deleted file mode 100644 index 4f283647..00000000 --- a/src/equicordplugins/sekaiStickers/Components/SekaiStickersModal.tsx +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2024 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { Flex } from "@components/Flex"; -import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal"; -import { Button, ChannelStore, Forms, React, SelectedChannelStore, Slider, Switch, Text, TextArea, UploadHandler } from "@webpack/common"; - -import { characters } from "../characters.json"; -import Canvas from "./Canvas"; -import CharSelectModal from "./Picker"; - -export default function SekaiStickersModal({ modalProps, settings }: { modalProps: ModalProps; settings: any; }) { - const [text, setText] = React.useState("奏でーかわいい"); - const [character, setChracter] = React.useState(49); - const [fontSize, setFontSize] = React.useState(characters[character].defaultText.s); - const [rotate, setRotate] = React.useState(characters[character].defaultText.r); - const [curve, setCurve] = React.useState(false); - const [isImgLoaded, setImgLoaded] = React.useState(false); - const [position, setPosition] = React.useState<{ x: number, y: number; }>({ x: characters[character].defaultText.x, y: characters[character].defaultText.y }); - const [spaceSize, setSpaceSize] = React.useState(1); - let canvast!: HTMLCanvasElement; - const img = new Image(); - img.crossOrigin = "anonymous"; - img.src = "https://st.ayaka.one/img/" + characters[character].img; - - React.useEffect(() => { - setPosition({ - x: characters[character].defaultText.x, - y: characters[character].defaultText.y - }); - setFontSize(characters[character].defaultText.s); - setRotate(characters[character].defaultText.r); - setImgLoaded(false); - }, [character]); - - img.onload = () => { setImgLoaded(true); }; - const angle = (Math.PI * text.length) / 7; - - const draw = ctx => { - ctx.canvas.width = 296; - ctx.canvas.height = 256; - - if (isImgLoaded && document.fonts.check("12px YurukaStd")) { - const hRatio = ctx.canvas.width / img.width; - const vRatio = ctx.canvas.height / img.height; - const ratio = Math.min(hRatio, vRatio); - const centerShiftX = (ctx.canvas.width - img.width * ratio) / 2; - const centerShiftY = (ctx.canvas.height - img.height * ratio) / 2; - ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); - ctx.drawImage( - img, - 0, - 0, - img.width, - img.height, - centerShiftX, - centerShiftY, - img.width * ratio, - img.height * ratio - ); - ctx.font = `${fontSize}px YurukaStd, SSFangTangTi`; - ctx.lineWidth = 9; - ctx.save(); - - ctx.translate(position.x, position.y); - ctx.rotate(rotate / 10); - ctx.textAlign = "center"; - ctx.strokeStyle = "white"; - ctx.fillStyle = characters[character].color; - const lines = text.split("\n"); - if (curve) { - for (const line of lines) { - for (let i = 0; i < line.length; i++) { - ctx.rotate(angle / line.length / 2.5); - ctx.save(); - ctx.translate(0, -1 * fontSize * 3.5); - ctx.strokeText(line[i], 0, -1 * spaceSize); - ctx.fillText(line[i], 0, -1 * spaceSize); - ctx.restore(); - } - } - } else { - for (let i = 0, k = 0; i < lines.length; i++) { - ctx.strokeText(lines[i], 0, k); - ctx.fillText(lines[i], 0, k); - k += spaceSize; - } - ctx.restore(); - } - canvast = ctx.canvas; - } - }; - return ( - - - Sekai Stickers - - - - -
- - Text Y Pos - { va = Math.round(va); setPosition({ x: position.x, y: curve ? 256 + fontSize * 3 - va : 256 - va }); }} initialValue={curve ? 256 - position.y + fontSize * 3 : 256 - position.y} orientation={"vertical"} onValueRender={va => String(Math.round(va))} /> - Text XZ Pos - { va = Math.round(va); setPosition({ y: position.y, x: va }); }} initialValue={position.x} orientation={"horizontal"} onValueRender={(v: number) => String(Math.round(v))} /> -
-
- Text -