diff --git a/src/equicordplugins/gifCollections/index.tsx b/src/equicordplugins/gifCollections/index.tsx
index c345aea25..772aa574f 100644
--- a/src/equicordplugins/gifCollections/index.tsx
+++ b/src/equicordplugins/gifCollections/index.tsx
@@ -16,9 +16,10 @@ import { ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal
import definePlugin, { OptionType } from "@utils/types";
import { Alerts, Button, ContextMenuApi, FluxDispatcher, Forms, Menu, React, showToast, TextInput, Toasts, useCallback, useState } from "@webpack/common";
-import { addToCollection, cache_collections, createCollection, DATA_COLLECTION_NAME, deleteCollection, fixPrefix, getCollections, getGifById, getItemCollectionNameFromId, moveGifToCollection, refreshCacheCollection, removeFromCollection, renameCollection } from "./utils/collectionManager";
+import { addToCollection, cache_collections, createCollection, DATA_COLLECTION_NAME, deleteCollection, fixPrefix, getCollections, getGifById, getItemCollectionNameFromId, moveGifToCollection, refreshCacheCollection, removeFromCollection, renameCollection, updateGif } from "./utils/collectionManager";
import { getFormat } from "./utils/getFormat";
import { getGif } from "./utils/getGif";
+import { refreshGifUrl } from "./utils/refreshUrl";
import { downloadCollections, uploadGifCollections } from "./utils/settingsUtils";
import { uuidv4 } from "./utils/uuidv4";
@@ -131,6 +132,11 @@ export const settings = definePluginSettings({
type: OptionType.BOOLEAN,
default: false,
},
+ preventDuplicates: {
+ description: "Prevent adding the same GIF to a collection multiple times",
+ type: OptionType.BOOLEAN,
+ default: false,
+ },
defaultEmptyCollectionImage: {
description: "The image / gif that will be shown when a collection has no images / gifs",
type: OptionType.STRING,
@@ -539,6 +545,40 @@ const RemoveItemContextMenu = ({ type, nameOrId, instance }) => (
}}
/>
+ {
+ const gifInfo = getGifById(nameOrId);
+ if (!gifInfo) return;
+
+ if (!gifInfo.channelId || !gifInfo.messageId || !gifInfo.attachmentId) {
+ showToast("Cannot refresh: GIF missing metadata (re-add to collection)", Toasts.Type.FAILURE);
+ return;
+ }
+
+ showToast("Refreshing URL...", Toasts.Type.MESSAGE);
+ const refreshedGif = await refreshGifUrl(gifInfo);
+
+ if (refreshedGif) {
+ await updateGif(nameOrId, refreshedGif);
+ const collectionName = getItemCollectionNameFromId(nameOrId);
+ FluxDispatcher.dispatch({
+ type: "GIF_PICKER_QUERY",
+ query: `${collectionName} `
+ });
+ FluxDispatcher.dispatch({
+ type: "GIF_PICKER_QUERY",
+ query: `${collectionName}`
+ });
+ showToast("URL refreshed successfully", Toasts.Type.SUCCESS);
+ } else {
+ showToast("Failed to refresh URL", Toasts.Type.FAILURE);
+ }
+ }}
+ />
+
=>
const collectionIndex = collections.findIndex(c => c.name === name);
if (collectionIndex === -1) return console.warn("collection not found");
+ if (settings.store.preventDuplicates) {
+ const isDuplicate = collections[collectionIndex].gifs.some(g => g.url === gif.url);
+ if (isDuplicate) {
+ return Toasts.show({
+ message: "This GIF is already in the collection",
+ type: Toasts.Type.FAILURE,
+ id: Toasts.genId(),
+ options: {
+ duration: 3000,
+ position: Toasts.Position.BOTTOM
+ }
+ });
+ }
+ }
+
collections[collectionIndex].gifs.push(gif);
collections[collectionIndex].src = gif.src;
collections[collectionIndex].format = getFormat(gif.src);
@@ -164,3 +179,18 @@ export const moveGifToCollection = async (gifId: string, fromCollection: string,
await DataStore.set(DATA_COLLECTION_NAME, collections);
return await refreshCacheCollection();
};
+
+export const updateGif = async (gifId: string, updatedGif: Gif): Promise => {
+ const collections = await getCollections();
+ const collectionIndex = collections.findIndex(c => c.gifs.some(g => g.id === gifId));
+ if (collectionIndex === -1) return console.warn("collection not found");
+
+ const gifIndex = collections[collectionIndex].gifs.findIndex(g => g.id === gifId);
+ if (gifIndex === -1) return console.warn("gif not found");
+
+ collections[collectionIndex].gifs[gifIndex] = updatedGif;
+ collections[collectionIndex].lastUpdated = Date.now();
+
+ await DataStore.set(DATA_COLLECTION_NAME, collections);
+ return await refreshCacheCollection();
+};
diff --git a/src/equicordplugins/gifCollections/utils/getGif.ts b/src/equicordplugins/gifCollections/utils/getGif.ts
index 951791557..de00df481 100644
--- a/src/equicordplugins/gifCollections/utils/getGif.ts
+++ b/src/equicordplugins/gifCollections/utils/getGif.ts
@@ -93,7 +93,10 @@ export function getGifByMessageAndUrl(url: string, message: Message): Gif | null
height: attachment.height ?? 50,
width: attachment.width ?? 50,
src: attachment.proxy_url,
- url: attachment.url
+ url: attachment.url,
+ channelId: message.channel_id,
+ messageId: message.id,
+ attachmentId: attachment.id
};
return null;
diff --git a/src/equicordplugins/gifCollections/utils/refreshUrl.ts b/src/equicordplugins/gifCollections/utils/refreshUrl.ts
new file mode 100644
index 000000000..ecc900270
--- /dev/null
+++ b/src/equicordplugins/gifCollections/utils/refreshUrl.ts
@@ -0,0 +1,50 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { RestAPI } from "@webpack/common";
+
+import { Gif } from "../types";
+
+async function fetchMessageFromAPI(channelId: string, messageId: string): Promise {
+ try {
+ const response = await RestAPI.get({
+ url: `/channels/${channelId}/messages`,
+ query: {
+ limit: 1,
+ around: messageId
+ }
+ });
+
+ if (response.ok && response.body.length > 0) {
+ return response.body.find((m: any) => m.id === messageId);
+ }
+ } catch (error) {
+ console.error("Failed to fetch message for GIF refresh:", error);
+ }
+ return null;
+}
+
+export async function refreshGifUrl(gif: Gif): Promise {
+ if (!gif.channelId || !gif.messageId || !gif.attachmentId) {
+ return null;
+ }
+
+ const message = await fetchMessageFromAPI(gif.channelId, gif.messageId);
+ if (!message) {
+ return null;
+ }
+
+ const attachment = message.attachments?.find((a: any) => a.id === gif.attachmentId);
+ if (!attachment) {
+ return null;
+ }
+
+ return {
+ ...gif,
+ src: attachment.proxy_url,
+ url: attachment.url
+ };
+}