Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugin): CopyStickerLinks #3191

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
139 changes: 139 additions & 0 deletions src/plugins/copyStickerLinks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2024 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 { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findStoreLazy } from "@webpack";
import { Clipboard, Constants, FluxDispatcher, Menu, React, RestAPI, Toasts } from "@webpack/common";
import { Promisable } from "type-fest";

const StickersStore = findStoreLazy("StickersStore");

interface Sticker {
t: "Sticker";
description: string;
format_type: number;
guild_id: string;
id: string;
name: string;
tags: string;
type: number;
}

type Data = Sticker;

const StickerExt = [, "png", "png", "json", "gif"] as const;

function getUrl(data: Data) {
if (data.t === "Sticker")
return `https:${window.GLOBAL_ENV.MEDIA_PROXY_ENDPOINT}/stickers/${data.id}.${StickerExt[data.format_type]}?size=2048&lossless=true`;

return "";
}

async function fetchSticker(id: string) {
const cached = StickersStore.getStickerById(id);
if (cached) return cached;

const { body } = await RestAPI.get({
url: Constants.Endpoints.STICKER(id)
});

FluxDispatcher.dispatch({
type: "STICKER_FETCH_SUCCESS",
sticker: body
});

return body as Sticker;
}

function buildMenuItem(type: "Sticker", fetchData: () => Promisable<Omit<Sticker, "t">>) {
return (
<>
<Menu.MenuSeparator></Menu.MenuSeparator>

<Menu.MenuItem
id="copystickerurl"
key="copystickerurl"
label={"Copy URL"}
action={async () => {
const res = await fetchData();
const data = { t: type, ...res } as Sticker;
const url = getUrl(data);
Toasts.show({
message: "Link to sticker copied!",
type: Toasts.Type.SUCCESS,
id: Toasts.genId()
});
Clipboard.copy(url);
}
}
/>

<Menu.MenuItem
id="openstickerlink"
key="openstickerlink"
label={"Open URL"}
action={async () => {
const res = await fetchData();
const data = { t: type, ...res } as Sticker;
const url = getUrl(data);
VencordNative.native.openExternal(url);
}
}
/>
</>
);
}

const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => {
const { favoriteableId, favoriteableType } = props ?? {};
if (!favoriteableId) return;
const menuItem = (() => {
switch (favoriteableType) {
case "sticker":
const sticker = props.message.stickerItems.find(s => s.id === favoriteableId);
if (sticker?.format_type === 3) return;

return buildMenuItem("Sticker", () => fetchSticker(favoriteableId));
}
})();

if (menuItem)
findGroupChildrenByChildId("devmode-copy-id", children, true)?.push(menuItem);
};

const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { target: HTMLElement; }) => {
const { id, type } = props?.target?.dataset ?? {};
if (!id) return;

if (type === "sticker" && !props.target.className?.includes("lottieCanvas")) {
children.push(buildMenuItem("Sticker", () => fetchSticker(id)));
}
};

export default definePlugin({
name: "CopyStickerLinks",
description: "Adds the ability to copy and open sticker links to your browser.",
authors: [Devs.Byeoon],
contextMenus: {
"message": messageContextMenuPatch,
"expression-picker": expressionPickerPatch
}
});
2 changes: 1 addition & 1 deletion src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ export const Devs = /* #__PURE__*/ Object.freeze({
name: "Sqaaakoi",
id: 259558259491340288n
},
Byron: {
Byeoon: {
name: "byeoon",
id: 1167275288036655133n
},
Expand Down