Cute Pats

This commit is contained in:
thororen1234 2024-07-18 18:14:06 -04:00
parent 0d9457e1bc
commit 8266478227
8 changed files with 354 additions and 10 deletions

View file

@ -58,6 +58,9 @@ jobs:
- name: Generate plugin list
run: pnpm generatePluginJson dist/plugins.json dist/plugin-readmes.json
- name: Generate Equicord plugin list
run: pnpm generateEquicordPluginJson dist/equicordplugins.json
- name: Clean up obsolete files
run: |
rm -rf dist/*-unpacked dist/monaco Vencord.user.css vencordDesktopRenderer.css vencordDesktopRenderer.css.map
@ -66,3 +69,23 @@ jobs:
if: github.repository == 'Equicord/Equicord'
run: |
gh release upload latest --clobber dist/*
- name: Upload DevBuild to builds repo
if: github.repository == 'Equicord/Equicord'
run: |
git config --global user.name "$USERNAME"
git config --global user.email "78185467+thororen1234@users.noreply.github.com"
git clone https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git upload
cd upload
rm plugins.json
cp -r ../dist/equicordplugins.json plugins.json
git add -A
git commit -m "Plugins for https://github.com/$GITHUB_REPOSITORY/commit/$GITHUB_SHA"
git push --force https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git
env:
API_TOKEN: ${{ secrets.ETOKEN }}
GH_REPO: Equicord/Ignore
USERNAME: thororen1234

View file

@ -21,7 +21,7 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
- Request for plugins from Discord.
<details>
<summary>Extra included plugins (61 additional plugins)</summary>
<summary>Extra included plugins (113 additional plugins)</summary>
- AllCallTimers by MaxHerbold and D3SOX
- AltKrispSwitch by newwares
@ -31,45 +31,69 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
- BetterActivities by D3SOX, Arjix, AutumnVN
- BetterBanReasons by Inbestigator
- BetterQuickReact by Ven and Sqaaakoi
- BetterUserArea by Samwich
- BlockKeywords by catcraft
- BlockKrsip by D3SOX
- BypassDND by Inbestigator
- CleanChannelName by AutumnVN
- ClientSideBlock by Samwich
- ColorMessage by Kyuuhachi
- CommandPalette by Ethan
- CopyUserMention by Cortex and castdrian
- CustomAppIcons by Happy Enderman and SerStars
- CustomSounds by ScattrdBlade
- CuteAnimeBoys by ShadyGoat
- CuteNekos by echo
- CutePats by thororen
- DeadMembers by Kyuuhachi
- Demonstration by Samwich
- DiscordColorways by DaBluLite
- DNDWhilePlaying by thororen
- DoNotLeak by Perny
- DontFilterMe by Samwich
- DoubleCounterBypass by nyx
- EmojiDumper by Cortex, Samwich, Woosh
- Encryptcord by Inbestigator
- EquicordCSS by FoxStorm1 and thororen (and all respective css developers)
- ExportContacts by dat_insanity
- FindReply by newwares
- FrequentQuickSwitcher by Samwich
- FriendshipRanks by Samwich
- FriendTags by Samwich
- GensokyoRadioRPC by RyanCaoDev and Prince527
- GifRoulette by Samwich
- Glide by Samwich
- GlobalBadges by HypedDomi and Hosted by Wolfie
- GodMode by Tolgchu
- GoogleThat by Samwich
- Grammar by Samwich
- GrammarFix by unstream
- HideMessage by Hanzy
- HolyNotes by Wolfie
- Hop On by ImLvna
- HomeTyping by Samwich
- HopOn by ImLvna
- Identity by Samwich
- IgnoreTerms by D3SOX
- IrcColors by Grzesiek11
- IRememberYou by zoodogood
- JumpToStart by Samwich
- KeyboardSounds by HypedDomi
- KeywordNotify by camila314
- MediaDownloader by Colorman
- Meow by Samwich
- MessageLinkTooltip by Kyuuhachi
- MessageLoggerEnhanced by Aria
- MessageTranslate by Samwich
- ModalFade by Kyuuhachi
- ModViewBypass by Sqaaakoi
- NewPluginsManager by Sqaaakoi
- noAppsAllowed by kvba
- NoBulletPoints by Samwich
- NoDefaultEmojis by Samwich
- NoDeleteSafety by Samwich
- NoModalAnimation by AutumnVN
- NoNitroUpsell by thororen
- NoRoleHeaders by Samwich
- NotificationTitle by Kyuuhachi
- NotifyUserChanges by D3SOX
- OnePingPerDM by ProffDea
@ -78,11 +102,13 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
- PhilsPluginLibrary by Philhk
- PlatformSpoofer by Drag
- PurgeMessages by bhop and nyx
- Quest Completer by HappyEnderman, SerStars, thororen
- QuestCompleter by HappyEnderman, SerStars, thororen
- QuestionMarkReplacement by nyx
- Quoter by Samwich
- RepeatMessage by Tolgchu
- ReplaceActivityTypes by Nyako
- ReplyPingControl by ant0n and MrDiamond
- RPCStats by Samwich
- ScreenRecorder by AutumnVN
- SearchFix by Jaxx
- SekaiStickers by MaiKokain
@ -92,14 +118,19 @@ An enhanced version of [Vencord](https://github.com/Vendicated/Vencord) by [Vend
- SoundBoardLogger by Moxxie, fres, echo, thororen
- TalkInReverse by Tolgchu
- TeX by Kyuuhachi
- TextToSpeech by Samwich
- ThemeLibrary by Fafa
- Title by Kyuuhachi
- TosuRPC by AutumnVN
- Translate+ by Prince527 (Using Translate by Ven)
- TriggerWarning by Joona
- UnlimitedAccounts by Balaclava and thororen
- UserPFP by nexpid and thororen
- UtilityDock by Samwich
- UwUifier by echo
- VCSupport by thororen
- VencordRPC by AutumnVN
- VideoSpeed by Samwich
- ViewRaw2 by Kyuuhachi
- VoiceChatUtilities by Dams and D3SOX
- WebpackTarball by Kyuuhachi

View file

@ -0,0 +1,263 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Dirent, readdirSync, readFileSync, writeFileSync } from "fs";
import { access, readFile } from "fs/promises";
import { join, sep } from "path";
import { normalize as posixNormalize, sep as posixSep } from "path/posix";
import { BigIntLiteral, createSourceFile, Identifier, isArrayLiteralExpression, isCallExpression, isExportAssignment, isIdentifier, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyAssignment, isSatisfiesExpression, isStringLiteral, isVariableStatement, NamedDeclaration, NodeArray, ObjectLiteralExpression, ScriptTarget, StringLiteral, SyntaxKind } from "typescript";
import { getPluginTarget } from "./utils.mjs";
interface Dev {
name: string;
id: string;
}
interface PluginData {
name: string;
description: string;
tags: string[];
authors: Dev[];
dependencies: string[];
hasPatches: boolean;
hasCommands: boolean;
required: boolean;
enabledByDefault: boolean;
target: "discordDesktop" | "vencordDesktop" | "equicordDesktop" | "desktop" | "web" | "dev";
filePath: string;
}
const devs = {} as Record<string, Dev>;
const equicordDevs = {} as Record<string, Dev>;
function getName(node: NamedDeclaration) {
return node.name && isIdentifier(node.name) ? node.name.text : undefined;
}
function hasName(node: NamedDeclaration, name: string) {
return getName(node) === name;
}
function getObjectProp(node: ObjectLiteralExpression, name: string) {
const prop = node.properties.find(p => hasName(p, name));
if (prop && isPropertyAssignment(prop)) return prop.initializer;
return prop;
}
function parseDevs() {
const file = createSourceFile("constants.ts", readFileSync("src/utils/constants.ts", "utf8"), ScriptTarget.Latest);
for (const child of file.getChildAt(0).getChildren()) {
if (!isVariableStatement(child)) continue;
const devsDeclaration = child.declarationList.declarations.find(d => hasName(d, "Devs"));
if (!devsDeclaration?.initializer || !isCallExpression(devsDeclaration.initializer)) continue;
const value = devsDeclaration.initializer.arguments[0];
if (!isSatisfiesExpression(value) || !isObjectLiteralExpression(value.expression)) throw new Error("Failed to parse devs: not an object literal");
for (const prop of value.expression.properties) {
const name = (prop.name as Identifier).text;
const value = isPropertyAssignment(prop) ? prop.initializer : prop;
if (!isObjectLiteralExpression(value)) throw new Error(`Failed to parse devs: ${name} is not an object literal`);
devs[name] = {
name: (getObjectProp(value, "name") as StringLiteral).text,
id: (getObjectProp(value, "id") as BigIntLiteral).text.slice(0, -1)
};
}
return;
}
throw new Error("Could not find Devs constant");
}
function parseEquicordDevs() {
const file = createSourceFile("constants.ts", readFileSync("src/utils/constants.ts", "utf8"), ScriptTarget.Latest);
for (const child of file.getChildAt(0).getChildren()) {
if (!isVariableStatement(child)) continue;
const devsDeclaration = child.declarationList.declarations.find(d => hasName(d, "EquicordDevs"));
if (!devsDeclaration?.initializer || !isCallExpression(devsDeclaration.initializer)) continue;
const value = devsDeclaration.initializer.arguments[0];
if (!isSatisfiesExpression(value) || !isObjectLiteralExpression(value.expression)) throw new Error("Failed to parse EquicordDevs: not an object literal");
for (const prop of value.expression.properties) {
const name = (prop.name as Identifier).text;
const value = isPropertyAssignment(prop) ? prop.initializer : prop;
if (!isObjectLiteralExpression(value)) throw new Error(`Failed to parse EquicordDevs: ${name} is not an object literal`);
equicordDevs[name] = {
name: (getObjectProp(value, "name") as StringLiteral).text,
id: (getObjectProp(value, "id") as BigIntLiteral).text.slice(0, -1)
};
}
return;
}
throw new Error("Could not find EquicordDevs constant");
}
async function parseFile(fileName: string) {
const file = createSourceFile(fileName, await readFile(fileName, "utf8"), ScriptTarget.Latest);
const fail = (reason: string) => {
return new Error(`Invalid plugin ${fileName}, because ${reason}`);
};
for (const node of file.getChildAt(0).getChildren()) {
if (!isExportAssignment(node) || !isCallExpression(node.expression)) continue;
const call = node.expression;
if (!isIdentifier(call.expression) || call.expression.text !== "definePlugin") continue;
const pluginObj = node.expression.arguments[0];
if (!isObjectLiteralExpression(pluginObj)) throw fail("no object literal passed to definePlugin");
const data = {
hasPatches: false,
hasCommands: false,
enabledByDefault: false,
required: false,
tags: [] as string[]
} as PluginData;
for (const prop of pluginObj.properties) {
const key = getName(prop);
const value = isPropertyAssignment(prop) ? prop.initializer : prop;
switch (key) {
case "name":
case "description":
if (!isStringLiteral(value)) throw fail(`${key} is not a string literal`);
data[key] = value.text;
break;
case "patches":
data.hasPatches = true;
break;
case "commands":
data.hasCommands = true;
break;
case "authors":
if (!isArrayLiteralExpression(value)) throw fail("authors is not an array literal");
data.authors = value.elements.map(e => {
if (!isPropertyAccessExpression(e)) throw fail("authors array contains non-property access expressions");
const d = devs[getName(e)!] || equicordDevs[getName(e)!];
if (!d) throw fail(`couldn't look up author ${getName(e)}`);
return d;
});
break;
case "tags":
if (!isArrayLiteralExpression(value)) throw fail("tags is not an array literal");
data.tags = value.elements.map(e => {
if (!isStringLiteral(e)) throw fail("tags array contains non-string literals");
return e.text;
});
break;
case "dependencies":
if (!isArrayLiteralExpression(value)) throw fail("dependencies is not an array literal");
const { elements } = value;
if (elements.some(e => !isStringLiteral(e))) throw fail("dependencies array contains non-string elements");
data.dependencies = (elements as NodeArray<StringLiteral>).map(e => e.text);
break;
case "required":
case "enabledByDefault":
data[key] = value.kind === SyntaxKind.TrueKeyword;
break;
}
}
if (!data.name || !data.description || !data.authors) throw fail("name, description or authors are missing");
const target = getPluginTarget(fileName);
if (target) {
if (!["web", "discordDesktop", "vencordDesktop", "equicordDesktop", "desktop", "dev"].includes(target)) throw fail(`invalid target ${target}`);
data.target = target as any;
}
data.filePath = posixNormalize(fileName)
.split(sep)
.join(posixSep)
.replace(/\/index\.([jt]sx?)$/, "")
.replace(/^src\/plugins\//, "");
let readme = "";
try {
readme = readFileSync(join(fileName, "..", "README.md"), "utf-8");
} catch { }
return [data, readme] as const;
}
throw fail("no default export called 'definePlugin' found");
}
async function getEntryPoint(dir: string, dirent: Dirent) {
const base = join(dir, dirent.name);
if (!dirent.isDirectory()) return base;
for (const name of ["index.ts", "index.tsx"]) {
const full = join(base, name);
try {
await access(full);
return full;
} catch { }
}
throw new Error(`${dirent.name}: Couldn't find entry point`);
}
function isPluginFile({ name }: { name: string; }) {
if (name === "index.ts") return false;
return !name.startsWith("_") && !name.startsWith(".");
}
(async () => {
parseDevs();
parseEquicordDevs();
const plugins = [] as PluginData[];
const readmes = {} as Record<string, string>;
await Promise.all(["src/equicordplugins"].flatMap(dir =>
readdirSync(dir, { withFileTypes: true })
.filter(isPluginFile)
.map(async dirent => {
const [data, readme] = await parseFile(await getEntryPoint(dir, dirent));
plugins.push(data);
if (readme) readmes[data.name] = readme;
})
));
const data = JSON.stringify(plugins);
if (process.argv.length > 3) {
writeFileSync(process.argv[2], data);
writeFileSync(process.argv[3], JSON.stringify(readmes));
} else {
console.log(data);
}
})();

View file

@ -37,7 +37,7 @@ export const settings = definePluginSettings({
export default definePlugin({
name: "Anammox",
description: "A microbial process that plays an important part in the nitrogen cycle",
description: "Remove Some Discord Settings",
authors: [Devs.Kyuuhachi],
settings,

View file

@ -28,7 +28,7 @@ async function fetchReddit(sub: string) {
}
export default definePlugin({
name: "Cute-Anime-Boys",
name: "CuteAnimeBoys",
authors: [EquicordDevs.ShadyGoat],
description: "Add a command to send cute anime boys in the chat",
dependencies: ["CommandsAPI"],

View file

@ -0,0 +1,30 @@
/*
* 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<string> {
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",
description: "Pat Command",
dependencies: ["CommandsAPI"],
authors: [EquicordDevs.thororen],
commands: [{
name: "pat",
description: "Baby don't hurt me no more",
execute: async opts => ({
content: await getcutepats()
})
}]
});

View file

@ -767,10 +767,7 @@ function getCSS(fontName) {
export default definePlugin({
name: "Glide",
description: "A sleek, rounded theme for discord.",
authors:
[
Devs.Samwich
],
authors: [Devs.Samwich],
settings,
start() {
injectCSS();

View file

@ -112,7 +112,7 @@ function utilityDock({ children }: { children: ReactNode[]; }) {
}
export default definePlugin({
name: "utilityDock",
name: "UtilityDock",
description: "Adds a button on your titlebar with multiple useful features",
authors: [Devs.Samwich],