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 + }; +}