EmojiDumper -> GuildPickerDumper + StickersStore
Some checks failed
Test / Test (push) Has been cancelled

This commit is contained in:
thororen1234 2025-05-09 21:12:17 -04:00
parent df6b6a0766
commit a884f24e31
No known key found for this signature in database
7 changed files with 102 additions and 85 deletions

View file

@ -52,7 +52,6 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
- DisableAnimations by S€th
- DisableCameras by Joona
- DontFilterMe by Samwich
- EmojiDumper by Cortex, Samwich, Woosh
- Encryptcord by Inbestigator
- EquicordHelper by thororen & nyx
- Equissant by SomeAspy & thororen
@ -77,6 +76,7 @@ You can join our [discord server](https://discord.gg/5Xh2W87egW) for commits, ch
- Glide by Samwich
- GlobalBadges by HypedDomi & Hosted by Wolfie
- GoogleThat by Samwich
- GuildPickerDumper by Cortex, Samwich, Woosh, thororen
- HideChatButtons by iamme
- HideServers by bepvte
- HolyNotes by Wolfie

View file

@ -1,62 +0,0 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
import { Menu } from "@webpack/common";
import type { Guild } from "discord-types/general";
import { zipSync } from "fflate";
const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => {
// Assuming "privacy" is the correct ID for the group you want to modify.
const group = findGroupChildrenByChildId("privacy", children);
if (group) {
group.push(
<Menu.MenuItem id="emoji.download" label="Download Emojis" action={() => zipServerEmojis(guild)}></Menu.MenuItem>
);
}
};
export default definePlugin({
name: "EmojiDumper",
description: "Context menu to dump and download a server's emojis.",
authors: [EquicordDevs.Cortex, Devs.Samwich, EquicordDevs.Woosh],
contextMenus: {
"guild-context": Patch,
"guild-header-popout": Patch
}
});
async function zipServerEmojis(guild: Guild) {
const emojis = Vencord.Webpack.Common.EmojiStore.getGuilds()[guild.id]?.emojis;
if (!emojis) {
return console.log("Server not found!");
}
const fetchEmojis = async e => {
const filename = e.id + (e.animated ? ".gif" : ".png");
const emoji = await fetch("https://cdn.discordapp.com/emojis/" + filename + "?size=512&quality=lossless").then(res => res.blob());
return { file: new Uint8Array(await emoji.arrayBuffer()), filename };
};
const emojiPromises = emojis.map(e => fetchEmojis(e));
Promise.all(emojiPromises)
.then(results => {
const emojis = zipSync(Object.fromEntries(results.map(({ file, filename }) => [filename, file])));
const blob = new Blob([emojis], { type: "application/zip" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = `${guild.name}-emojis.zip`;
link.click();
link.remove();
})
.catch(error => {
console.error(error);
});
}

View file

@ -0,0 +1,75 @@
/*
* Vencord, a Discord client mod
* Copyright (c) 2024 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { migratePluginSettings } from "@api/Settings";
import { Devs, EquicordDevs } from "@utils/constants";
import definePlugin from "@utils/types";
import { EmojiStore, Menu, StickersStore } from "@webpack/common";
import type { Guild } from "discord-types/general";
import { zipSync } from "fflate";
const Patch: NavContextMenuPatchCallback = (children, { guild }: { guild: Guild; }) => {
// Assuming "privacy" is the correct ID for the group you want to modify.
const group = findGroupChildrenByChildId("privacy", children);
if (group) {
group.push(
<>
<Menu.MenuItem id="emoji.download" label="Download Emojis" action={() => zipGuildAssets(guild, "emojis")}></Menu.MenuItem>
<Menu.MenuItem id="sticker.download" label="Download Stickers" action={() => zipGuildAssets(guild, "stickers")}></Menu.MenuItem>
</>
);
}
};
async function zipGuildAssets(guild: Guild, type: "emojis" | "stickers") {
const isEmojis = type === "emojis";
const items = isEmojis
? EmojiStore.getGuilds()[guild.id]?.emojis
: StickersStore.getStickersByGuildId(guild.id);
if (!items) {
return console.log("Server not found!");
}
const fetchAsset = async e => {
const ext = e.animated ? ".gif" : ".png";
const filename = e.id + ext;
const url = isEmojis
? `https://${window.GLOBAL_ENV.MEDIA_PROXY_ENDPOINT}/emojis/${filename}?size=512&quality=lossless`
: `https://${window.GLOBAL_ENV.MEDIA_PROXY_ENDPOINT}/stickers/${filename}?size=4096&lossless=true`;
const response = await fetch(url);
const blob = await response.blob();
return { file: new Uint8Array(await blob.arrayBuffer()), filename };
};
const assetPromises = items.map(e => fetchAsset(e));
Promise.all(assetPromises)
.then(results => {
const zipped = zipSync(Object.fromEntries(results.map(({ file, filename }) => [filename, file])));
const blob = new Blob([zipped], { type: "application/zip" });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = `${guild.name}-${type}.zip`;
link.click();
link.remove();
})
.catch(console.error);
}
migratePluginSettings("GuildPickerDumper", "EmojiDumper");
export default definePlugin({
name: "GuildPickerDumper",
description: "Context menu to dump and download a server's emojis and stickers.",
authors: [EquicordDevs.Cortex, Devs.Samwich, EquicordDevs.Woosh, EquicordDevs.thororen],
contextMenus: {
"guild-context": Patch,
"guild-header-popout": Patch
}
});

View file

@ -9,14 +9,11 @@ import "./styles.css";
import { EquicordDevs } from "@utils/constants";
import { Logger } from "@utils/Logger";
import definePlugin from "@utils/types";
import { findStoreLazy } from "@webpack";
import { StickersStore } from "@webpack/common";
import { getMimeType, isLinkAnImage, settings, stripDiscordParams } from "./settings";
const logger = new Logger("ImagePreview", "#FFFFFF");
const StickerStore = findStoreLazy("StickersStore") as {
getStickerById(id: string): any;
};
let currentPreview: HTMLDivElement | null = null;
let currentPreviewFile: HTMLImageElement | HTMLVideoElement | null = null;
@ -124,7 +121,7 @@ function loadImagePreview(url: string, sticker: boolean) {
if (sticker) {
const stickerId = url.split("/").pop()?.split(".")[0] ?? null;
const stickerData = stickerId ? StickerStore.getStickerById(stickerId) : null;
const stickerData = stickerId ? StickersStore.getStickerById(stickerId) : null;
if (stickerData) {
switch (stickerData.type) {

View file

@ -24,7 +24,7 @@ import { getCurrentGuild, getEmojiURL } from "@utils/discord";
import { Logger } from "@utils/Logger";
import definePlugin, { OptionType, Patch } from "@utils/types";
import { findByCodeLazy, findByPropsLazy, findStoreLazy, proxyLazyWebpack } from "@webpack";
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
import { Alerts, ChannelStore, DraftType, EmojiStore, FluxDispatcher, Forms, GuildMemberStore, lodash, Parser, PermissionsBits, PermissionStore, StickersStore, UploadHandler, UserSettingsActionCreators, UserStore } from "@webpack/common";
import type { Emoji } from "@webpack/types";
import type { Message } from "discord-types/general";
import { applyPalette, GIFEncoder, quantize } from "gifenc";
@ -33,12 +33,6 @@ import type { ReactElement, ReactNode } from "react";
// @ts-ignore
const premiumType = UserStore?.getCurrentUser()?._realPremiumType ?? UserStore?.getCurrentUser()?.premiumType ?? 0;
const StickerStore = findStoreLazy("StickersStore") as {
getPremiumPacks(): StickerPack[];
getAllGuildStickers(): Map<string, Sticker[]>;
getStickerById(id: string): Sticker | undefined;
};
const UserSettingsProtoStore = findStoreLazy("UserSettingsProtoStore");
const BINARY_READ_OPTIONS = findByPropsLazy("readerFactory");
@ -558,8 +552,8 @@ export default definePlugin({
const gifMatch = child.props.href.match(fakeNitroGifStickerRegex);
if (gifMatch) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(gifMatch[1])) return null;
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
if (StickersStore.getStickerById(gifMatch[1])) return null;
}
}
@ -647,7 +641,7 @@ export default definePlugin({
url = new URL(item);
} catch { }
const stickerName = StickerStore.getStickerById(imgMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroSticker";
const stickerName = StickersStore.getStickerById(imgMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroSticker";
stickers.push({
format_type: 1,
id: imgMatch[1],
@ -660,9 +654,9 @@ export default definePlugin({
const gifMatch = item.match(fakeNitroGifStickerRegex);
if (gifMatch) {
if (!StickerStore.getStickerById(gifMatch[1])) continue;
if (!StickersStore.getStickerById(gifMatch[1])) continue;
const stickerName = StickerStore.getStickerById(gifMatch[1])?.name ?? "FakeNitroSticker";
const stickerName = StickersStore.getStickerById(gifMatch[1])?.name ?? "FakeNitroSticker";
stickers.push({
format_type: 2,
id: gifMatch[1],
@ -695,8 +689,8 @@ export default definePlugin({
const gifMatch = embed.url!.match(fakeNitroGifStickerRegex);
if (gifMatch) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(gifMatch[1])) return true;
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
if (StickersStore.getStickerById(gifMatch[1])) return true;
}
}
@ -713,8 +707,8 @@ export default definePlugin({
const match = attachment.url.match(fakeNitroGifStickerRegex);
if (match) {
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickerStore contains the id of the fake sticker
if (StickerStore.getStickerById(match[1])) return false;
// There is no way to differentiate a regular gif attachment from a fake nitro animated sticker, so we check if the StickersStore contains the id of the fake sticker
if (StickersStore.getStickerById(match[1])) return false;
}
return true;
@ -870,7 +864,7 @@ export default definePlugin({
if (!s.enableStickerBypass)
break stickerBypass;
const sticker = StickerStore.getStickerById(extra.stickers?.[0]!);
const sticker = StickersStore.getStickerById(extra.stickers?.[0]!);
if (!sticker)
break stickerBypass;

View file

@ -54,6 +54,7 @@ export let RelationshipStore: Stores.RelationshipStore & t.FluxStore & {
};
export let EmojiStore: t.EmojiStore;
export let StickersStore: t.StickersStore;
export let ThemeStore: t.ThemeStore;
export let WindowStore: t.WindowStore;
export let DraftStore: t.DraftStore;
@ -86,5 +87,6 @@ waitForStore("GuildChannelStore", m => GuildChannelStore = m);
waitForStore("MessageStore", m => MessageStore = m);
waitForStore("WindowStore", m => WindowStore = m);
waitForStore("EmojiStore", m => EmojiStore = m);
waitForStore("StickersStore", m => StickersStore = m);
waitForStore("TypingStore", m => TypingStore = m);
waitForStore("ThemeStore", m => ThemeStore = m);

View file

@ -177,6 +177,17 @@ export class EmojiStore extends FluxStore {
};
}
export class StickersStore extends FluxStore {
getStickerById(id: string): Sticker | undefined;
getStickerPack(id: string): StickerPack | undefined;
getPremiumPacks(): StickerPack[];
isPremiumPack(id: string): boolean;
getRawStickersByGuild(): Map<string, Sticker[]>;
getAllStickersIterator(): IterableIterator<Sticker>;
getAllGuildStickers(): Map<string, Sticker[]>;
getStickersByGuildId(id: string): Sticker[] | undefined;
}
export interface DraftObject {
channelId: string;
timestamp: number;