diff --git a/README.md b/README.md
index 47f3723c..a04423c1 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/equicordplugins/emojiDumper/index.tsx b/src/equicordplugins/emojiDumper/index.tsx
deleted file mode 100644
index 9bc3f1c7..00000000
--- a/src/equicordplugins/emojiDumper/index.tsx
+++ /dev/null
@@ -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(
-
zipServerEmojis(guild)}>
- );
- }
-};
-
-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);
- });
-}
diff --git a/src/equicordplugins/guildPickerDumper/index.tsx b/src/equicordplugins/guildPickerDumper/index.tsx
new file mode 100644
index 00000000..1e9ad32a
--- /dev/null
+++ b/src/equicordplugins/guildPickerDumper/index.tsx
@@ -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(
+ <>
+ zipGuildAssets(guild, "emojis")}>
+ zipGuildAssets(guild, "stickers")}>
+ >
+ );
+ }
+};
+
+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
+ }
+});
diff --git a/src/equicordplugins/imagePreview/index.ts b/src/equicordplugins/imagePreview/index.ts
index 486eb737..2d177f28 100644
--- a/src/equicordplugins/imagePreview/index.ts
+++ b/src/equicordplugins/imagePreview/index.ts
@@ -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) {
diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx
index 6adcb032..f560211d 100644
--- a/src/plugins/fakeNitro/index.tsx
+++ b/src/plugins/fakeNitro/index.tsx
@@ -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;
- 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;
diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts
index 76804488..c238350e 100644
--- a/src/webpack/common/stores.ts
+++ b/src/webpack/common/stores.ts
@@ -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);
diff --git a/src/webpack/common/types/stores.d.ts b/src/webpack/common/types/stores.d.ts
index 67148303..c54811b0 100644
--- a/src/webpack/common/types/stores.d.ts
+++ b/src/webpack/common/types/stores.d.ts
@@ -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;
+ getAllStickersIterator(): IterableIterator;
+ getAllGuildStickers(): Map;
+ getStickersByGuildId(id: string): Sticker[] | undefined;
+}
+
export interface DraftObject {
channelId: string;
timestamp: number;