diff --git a/src/equicordplugins/moreStickers/components/misc.tsx b/src/equicordplugins/moreStickers/components/misc.tsx index e6c3bcd3..b9194675 100644 --- a/src/equicordplugins/moreStickers/components/misc.tsx +++ b/src/equicordplugins/moreStickers/components/misc.tsx @@ -11,7 +11,7 @@ import { Button, Forms, React, TabBar, Text, TextArea, Toasts } from "@webpack/c import { convert as convertLineEP, getIdFromUrl as getLineEmojiPackIdFromUrl, getStickerPackById as getLineEmojiPackById, isLineEmojiPackHtml, parseHtml as getLineEPFromHtml } from "../lineEmojis"; import { convert as convertLineSP, getIdFromUrl as getLineStickerPackIdFromUrl, getStickerPackById as getLineStickerPackById, isLineStickerPackHtml, parseHtml as getLineSPFromHtml } from "../lineStickers"; -import { migrate } from "../migrate-v1"; +import { isV1, migrate } from "../migrate-v1"; import { deleteStickerPack, getStickerPack, getStickerPackMetas, saveStickerPack } from "../stickers"; import { SettingsTabsKey, Sticker, StickerPack, StickerPackMeta } from "../types"; import { cl, clPicker, Mutex } from "../utils"; @@ -92,6 +92,7 @@ export const Settings = () => { const [addStickerHtml, setAddStickerHtml] = React.useState(""); const [tab, setTab] = React.useState(SettingsTabsKey.ADD_STICKER_PACK_URL); const [hoveredStickerPackId, setHoveredStickerPackId] = React.useState(null); + const [_isV1, setV1] = React.useState(false); async function refreshStickerPackMetas() { setstickerPackMetas(await getStickerPackMetas()); @@ -99,6 +100,9 @@ export const Settings = () => { React.useEffect(() => { refreshStickerPackMetas(); }, []); + React.useEffect(() => { + isV1().then(setV1); + }, []); return (
@@ -365,7 +369,7 @@ export const Settings = () => {
diff --git a/src/equicordplugins/moreStickers/index.tsx b/src/equicordplugins/moreStickers/index.tsx index f02e6dc3..5716f8e1 100644 --- a/src/equicordplugins/moreStickers/index.tsx +++ b/src/equicordplugins/moreStickers/index.tsx @@ -64,11 +64,11 @@ export default definePlugin({ } }, { - find: "#{intl::EXPRESSION_PICKER_GIF}", + find: `role:"tablist","aria-label":`, replacement: { - match: /role:"tablist",.+?#{intl::EXPRESSION_PICKER_CATEGORIES_A11Y_LABEL}\),children:(\[.*?\)\]}\)}\):null,)(.*?closePopout:\w.*?:null)/s, + match: /role:"tablist",.*?,?"aria-label":.+?\),children:(\[.*?\)\]}\)}\):null,)(.*?closePopout:\w.*?:null)/s, replace: m => { - const stickerTabRegex = /(\w+?)\?(\([^()]+?\))\((.{1,2}),{.{0,128},isActive:(.{1,2})===.{1,150},children:(.{1,10}#{intl::EXPRESSION_PICKER_STICKER}).*?:null/s; + const stickerTabRegex = /(\w+?)\?(\([^()]+?\))\((.{1,2}),{.{0,128},isActive:(.{1,2})===.{1,6}\.STICKER.{1,140},children:(.{1,2}\.intl\.string\(.+?\)).*?:null/s; const res = m.replace(stickerTabRegex, (_m, canUseStickers, jsx, tabHeaderComp, currentTab, stickerText) => { const isActive = `${currentTab}==="stickers+"`; return ( diff --git a/src/equicordplugins/moreStickers/migrate-v1.ts b/src/equicordplugins/moreStickers/migrate-v1.ts index 539ea004..cdf01aa9 100644 --- a/src/equicordplugins/moreStickers/migrate-v1.ts +++ b/src/equicordplugins/moreStickers/migrate-v1.ts @@ -57,6 +57,20 @@ function migrateStickerPack(oldStickerPack: StickerPack): StickerPack { }; } +export async function isV1() { + const newPackMetas = await getStickerPackMetas(PACKS_KEY); + if (newPackMetas.length > 0) { + return false; + } + + const oldPackMetas = await getStickerPackMetas(PACKS_KEY_OLD); + if (oldPackMetas.length === 0) { + return false; + } + + return true; +} + export async function migrate() { const newPackMetas = await getStickerPackMetas(PACKS_KEY); if (newPackMetas.length > 0) { diff --git a/src/equicordplugins/moreStickers/stickers.ts b/src/equicordplugins/moreStickers/stickers.ts index 4a12bda3..2e7e1f7c 100644 --- a/src/equicordplugins/moreStickers/stickers.ts +++ b/src/equicordplugins/moreStickers/stickers.ts @@ -7,11 +7,12 @@ import * as DataStore from "@api/DataStore"; import { removeRecentStickerByPackId } from "./components"; -import { StickerPack, StickerPackMeta } from "./types"; +import { DynamicPackSetMeta, DynamicStickerPackMeta, StickerPack, StickerPackMeta } from "./types"; import { Mutex } from "./utils"; const mutex = new Mutex(); const PACKS_KEY = "MoreStickers:Packs"; +const DYNAMIC_PACK_SET_METAS_KEY = "MoreStickers:DynamicPackSetMetas"; /** * Convert StickerPack to StickerPackMeta @@ -24,7 +25,8 @@ function stickerPackToMeta(sp: StickerPack): StickerPackMeta { id: sp.id, title: sp.title, author: sp.author, - logo: sp.logo + logo: sp.logo, + dynamic: sp.dynamic, }; } @@ -43,8 +45,11 @@ export async function saveStickerPack(sp: StickerPack, packsKey: string = PACKS_ const unlock = await mutex.lock(); try { - const packs = (await DataStore.get(packsKey) ?? null) as (StickerPackMeta[] | null); - await DataStore.set(packsKey, packs === null ? [meta] : [...packs, meta]); + let packs = (await DataStore.get(packsKey) ?? null) as (StickerPackMeta[] | null); + if (packs?.some(p => p.id === sp.id)) { + packs = packs.map(p => p.id === sp.id ? meta : p); + } + await DataStore.set(packsKey, packs === null ? [meta] : packs); } finally { unlock(); } @@ -106,3 +111,66 @@ export async function deleteStickerPack(id: string, packsKey: string = PACKS_KEY })() ]); } + +// ---------------------------- Dynamic Packs ---------------------------- + +export async function getDynamicStickerPack(dspm: DynamicStickerPackMeta): Promise { + const dsp = await fetch(dspm.dynamic.refreshUrl, { + headers: dspm.dynamic.authHeaders, + }); + if (!dsp.ok) return null; + return await dsp.json(); +} + +export async function getDynamicPackSetMetas(dpsmKey: string = DYNAMIC_PACK_SET_METAS_KEY): Promise { + return (await DataStore.get(dpsmKey)) ?? null as DynamicPackSetMeta[] | null; +} + +function hasDynamicPackSetMeta(dpsm: DynamicPackSetMeta, metas?: DynamicPackSetMeta[] | null): boolean { + return !!metas?.some(m => m.id === dpsm.id); +} + +export async function fetchDynamicPackSetMeta(dpsm: DynamicPackSetMeta): Promise { + const dpsm_ = await fetch(dpsm.refreshUrl, { + headers: dpsm.authHeaders, + }); + if (!dpsm_.ok) return null; + + const dpsmData = await dpsm_.json(); + return dpsmData as DynamicPackSetMeta; +} + +export async function refreshDynamicPackSet(old: DynamicPackSetMeta, _new: DynamicPackSetMeta): Promise { + const oldPacks = old.packs.map(p => p.id); + const newPacks = _new.packs.map(p => p.id); + + const toRemove = oldPacks.filter(p => !newPacks.includes(p)); + const toAdd = newPacks.filter(p => !oldPacks.includes(p)); + + await Promise.all([ + ...toRemove.map(id => deleteStickerPack(id)), + ...toAdd.map(id => getDynamicStickerPack(_new.packs.find(p => p.id === id)!).then(sp => sp && saveStickerPack(sp))) + ]); +} + +export async function saveDynamicPackSetMeta(dpsm: DynamicPackSetMeta, dpsmKey: string = DYNAMIC_PACK_SET_METAS_KEY): Promise { + let metas = (await DataStore.get(dpsmKey) ?? null) as (DynamicPackSetMeta[] | null); + if (hasDynamicPackSetMeta(dpsm, metas)) { + await refreshDynamicPackSet(metas!.find(m => m.id === dpsm.id)!, dpsm); + metas = metas!.map(m => m.id === dpsm.id ? dpsm : m); + } + + const unlock = await mutex.lock(); + try { + await DataStore.set(dpsmKey, metas === null ? [dpsm] : metas); + } finally { + unlock(); + } +} + +export async function fetchAndRefreshDynamicPackSet(dpsm: DynamicPackSetMeta, dpsmKey: string = DYNAMIC_PACK_SET_METAS_KEY): Promise { + const _new = await fetchDynamicPackSetMeta(dpsm); + if (!_new) return; + + await saveDynamicPackSetMeta(_new, dpsmKey); +} diff --git a/src/equicordplugins/moreStickers/types.ts b/src/equicordplugins/moreStickers/types.ts index 1f20d052..5d545bdf 100644 --- a/src/equicordplugins/moreStickers/types.ts +++ b/src/equicordplugins/moreStickers/types.ts @@ -138,6 +138,16 @@ export interface StickerPackMeta { url?: string; }; logo: Sticker; + + dynamic?: DynamicStickerPackMeta["dynamic"]; +} + +export interface DynamicStickerPackMeta extends StickerPackMeta { + dynamic: { + version?: string; + refreshUrl: string; + authHeaders?: Record; + }; } export interface StickerPack extends StickerPackMeta { @@ -148,3 +158,18 @@ export interface FFmpegState { ffmpeg?: FFmpeg; isLoaded: boolean; } + +export interface DynamicPackSetMeta { + id: string; + version?: string; + + title?: string; + author?: { + name: string; + url?: string; + }; + + packs: DynamicStickerPackMeta[]; + refreshUrl: string; + authHeaders?: Record; +}