Plugin

CopyStickerLinks

Adds the ability to copy & open Sticker links

Emotes Utility
index.tsx
Download

Source

src/plugins/copyStickerLinks/index.tsx
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
8import { isPluginEnabled } from "@api/PluginManager";
9import ExpressionClonerPlugin from "@plugins/expressionCloner";
10import { Devs } from "@utils/constants";
11import { copyWithToast } from "@utils/discord";
12import definePlugin from "@utils/types";
13import { Message, Sticker } from "@vencord/discord-types";
14import { Menu, React, StickersStore } from "@webpack/common";
15
16const StickerExt = [, "png", "png", "json", "gif"] as const;
17
18type PartialSticker = Pick<Sticker, "id" | "format_type">;
19
20function getUrl(data: PartialSticker): string {
21 if (data.format_type === 4)
22 return `https:${window.GLOBAL_ENV.MEDIA_PROXY_ENDPOINT}/stickers/${data.id}.gif?size=512&lossless=true`;
23
24 return `https:class="ts-cmt">//${window.GLOBAL_ENV.CDN_HOST}/stickers/${data.id}.${StickerExt[data.format_type]}?size=512&lossless=true`;
25}
26
27function buildMenuItem(sticker: PartialSticker, addBottomSeparator: boolean) {
28 return (
29 <>
30 <Menu.MenuGroup>
31 <Menu.MenuItem
32 id="vc-copy-sticker-link"
33 key="vc-copy-sticker-link"
34 label="Copy Link"
35 action={() => copyWithToast(getUrl(sticker), "Link copied!")}
36 />
37
38 <Menu.MenuItem
39 id="vc-open-sticker-link"
40 key="vc-open-sticker-link"
41 label="Open Link"
42 action={() => VencordNative.native.openExternal(getUrl(sticker))}
43 />
44 </Menu.MenuGroup>
45 {addBottomSeparator && <Menu.MenuSeparator />}
46 </>
47 );
48}
49
50const messageContextMenuPatch: NavContextMenuPatchCallback = (
51 children,
52 { favoriteableId, favoriteableType, message }: { favoriteableId: string; favoriteableType: string; message: Message; }
53) => {
54 if (!favoriteableId || favoriteableType !== "sticker") return;
55
56 const sticker = message.stickerItems.find(s => s.id === favoriteableId);
57 if (!sticker?.format_type) return;
58
59 const idx = children.findIndex(c => Array.isArray(c) && findGroupChildrenByChildId("vc-copy-sticker-url", c) != null);
60
61 children.splice(idx, 0, buildMenuItem(sticker, idx !== -1));
62};
63
64const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
65 const id = props?.target?.dataset?.id;
66 if (!id) return;
67 if (props.target.className?.includes("lottieCanvas")) return;
68
69 const sticker = StickersStore.getStickerById(id);
70 if (sticker) {
71 children.push(buildMenuItem(sticker, isPluginEnabled(ExpressionClonerPlugin.name)));
72 }
73};
74
75export default definePlugin({
76 name: "CopyStickerLinks",
77 description: "Adds the ability to copy & open Sticker links",
78 tags: ["Emotes", "Utility"],
79 authors: [Devs.Ven, Devs.Byeoon],
80 contextMenus: {
81 "message": messageContextMenuPatch,
82 "expression-picker": expressionPickerPatch
83 }
84});
85