From d5c1ca9145793deef346d0b239b214d7f7a114db Mon Sep 17 00:00:00 2001 From: lisonge Date: Fri, 31 May 2024 20:43:47 +0800 Subject: [PATCH] refactor: import id --- src/components/ActionCard.vue | 22 +++++------- src/components/SearchCard.vue | 18 ++++------ src/router/index.ts | 4 +-- src/utils/export.ts | 17 +++++---- src/utils/import.ts | 16 +++------ src/utils/storage.ts | 66 ++++++++++++++++++++++++++++------- src/utils/store.ts | 4 +-- src/utils/url.ts | 49 +++++++++++++++++--------- src/views/ImportPage.vue | 30 ++++++---------- src/views/SnapshotPage.vue | 10 +++--- 10 files changed, 136 insertions(+), 100 deletions(-) diff --git a/src/components/ActionCard.vue b/src/components/ActionCard.vue index 3fe1b87..4c85d11 100644 --- a/src/components/ActionCard.vue +++ b/src/components/ActionCard.vue @@ -2,20 +2,20 @@ import { showTextDLg, waitShareAgree } from '@/utils/dialog'; import { message } from '@/utils/discrete'; import { + exportSnapshotAsImportId, exportSnapshotAsJpg, exportSnapshotAsJpgUrl, exportSnapshotAsZip, - exportSnapshotAsZipUrl, } from '@/utils/export'; import { buildEmptyFn, delay } from '@/utils/others'; import { githubJpgStorage, - githubZipStorage, + importStorage, snapshotStorage, } from '@/utils/storage'; import { useTask } from '@/utils/task'; import type { Snapshot } from '@/utils/types'; -import { githubUrlToSelfUrl } from '@/utils/url'; +import { getImportUrl, githubUrlToSelfUrl } from '@/utils/url'; import { NButton, NIcon, NPopover, NSpace } from 'naive-ui'; import { computed } from 'vue'; import { useRouter } from 'vue-router'; @@ -61,18 +61,18 @@ const exportJpgUrl = useTask(async () => { ); showTextDLg({ title: `分享链接`, - content: githubUrlToSelfUrl(router, pngUrl), + content: githubUrlToSelfUrl(pngUrl), }); }); const exportZipUrl = useTask(async () => { await waitShareAgree(); - const zipUrl = await exportSnapshotAsZipUrl( + const importId = await exportSnapshotAsImportId( (await snapshotStorage.getItem(props.snapshot.id))!, ); showTextDLg({ title: `分享链接`, - content: githubUrlToSelfUrl(router, zipUrl), + content: location.origin + `/i/${importId}`, }); }); @@ -166,10 +166,8 @@ const copy = async (content: string) => { 复制链接-快照 @@ -182,9 +180,7 @@ const copy = async (content: string) => { 复制链接-图片 diff --git a/src/components/SearchCard.vue b/src/components/SearchCard.vue index 3d3acac..4a247ec 100644 --- a/src/components/SearchCard.vue +++ b/src/components/SearchCard.vue @@ -5,9 +5,9 @@ import { getNodeLabel } from '@/utils/node'; import { buildEmptyFn, copy } from '@/utils/others'; import type { Selector } from '@/utils/selector'; import { parseSelector, wasmLoadTask } from '@/utils/selector'; -import { githubJpgStorage, githubZipStorage } from '@/utils/storage'; +import { githubJpgStorage, importStorage } from '@/utils/storage'; import type { RawNode, Snapshot } from '@/utils/types'; -import { githubUrlToSelfUrl } from '@/utils/url'; +import { getImportUrl, githubUrlToSelfUrl } from '@/utils/url'; import dayjs from 'dayjs'; import JSON5 from 'json5'; import { @@ -162,12 +162,10 @@ const generateRules = errorTry( async (result: { key: number; selector: Selector; nodes: RawNode[][] }) => { let jpgUrl = githubJpgStorage[props.snapshot.id]; if (jpgUrl) { - jpgUrl = githubUrlToSelfUrl(router, jpgUrl); - } - let zipUrl = githubZipStorage[props.snapshot.id]; - if (zipUrl) { - zipUrl = githubUrlToSelfUrl(router, zipUrl); + jpgUrl = githubUrlToSelfUrl(jpgUrl); } + const importId = importStorage[props.snapshot.id]; + const zipUrl = importId ? getImportUrl(importId) : undefined; const s = result.selector; const t = result.nodes[0][0]; @@ -203,13 +201,11 @@ const generateRules = errorTry( ); const enableSearchBySelector = shallowRef(true); const hasZipId = computed(() => { - return githubZipStorage[props.snapshot.id]; + return importStorage[props.snapshot.id]; }); const shareResult = (result: SearchResult) => { if (!hasZipId.value) return; - const importUrl = new URL( - githubUrlToSelfUrl(router, githubZipStorage[props.snapshot.id]), - ); + const importUrl = new URL(getImportUrl(importStorage[props.snapshot.id])); if (typeof result.selector == 'object') { importUrl.searchParams.set( 'gkd', diff --git a/src/router/index.ts b/src/router/index.ts index 5304c2e..e276e72 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,4 +1,5 @@ import { toValidURL } from '@/utils/check'; +import { getImportFileUrl } from '@/utils/url'; import type { RouteRecordRedirectOption } from 'vue-router'; import { createRouter, createWebHistory } from 'vue-router'; @@ -7,12 +8,11 @@ const redirectImport: RouteRecordRedirectOption = (to) => { if (!github_asset_id) { return { path: '/404' }; } - const url = `https://github.com/user-attachments/files/${github_asset_id}/file.zip`; return { path: '/i', query: { ...to.query, - url, + url: getImportFileUrl(github_asset_id), }, }; }; diff --git a/src/utils/export.ts b/src/utils/export.ts index b9aaef5..6baf9dd 100644 --- a/src/utils/export.ts +++ b/src/utils/export.ts @@ -5,7 +5,7 @@ import { uploadPoliciesAssets } from './github'; import { delay } from './others'; import { githubJpgStorage, - githubZipStorage, + importStorage, screenshotStorage, syncImportStorage, urlStorage, @@ -87,25 +87,24 @@ export const exportSnapshotAsJpgUrl = async (snapshot: Snapshot) => { 'file.jpg', 'image/jpeg', ).then((r) => { - // urlStorage[r.href] = snapshot.id; githubJpgStorage[snapshot.id] = r.href; return r.href; }) ); }; -export const exportSnapshotAsZipUrl = async (snapshot: Snapshot) => { +export const exportSnapshotAsImportId = async (snapshot: Snapshot) => { return ( - githubZipStorage[snapshot.id] ?? + importStorage[snapshot.id] || uploadPoliciesAssets( await snapshotAsZip(snapshot).then((r) => r.arrayBuffer()), 'file.zip', 'application/x-zip-compressed', ).then((r) => { - githubZipStorage[snapshot.id] = r.href; - urlStorage[r.href] = snapshot.id; + importStorage[snapshot.id] = r.id; + urlStorage[r.id] = snapshot.id; detectSnapshot(r.id); - return r.href; + return r.id; }) ); }; @@ -127,9 +126,9 @@ export const batchCreateZipUrl = async (snapshots: Snapshot[]) => { const limit = pLimit(3); return ( await Promise.allSettled( - snapshots.map((s) => limit(() => exportSnapshotAsZipUrl(s))), + snapshots.map((s) => limit(() => exportSnapshotAsImportId(s))), ) - ).reduce((p, c) => { + ).reduce((p, c) => { if (c.status == 'fulfilled') { p.push(c.value); } diff --git a/src/utils/import.ts b/src/utils/import.ts index 96615c3..62c81f6 100644 --- a/src/utils/import.ts +++ b/src/utils/import.ts @@ -6,6 +6,7 @@ import { enhanceFetch } from './fetch'; import { isZipBf } from './file_type'; import { setSnapshot, snapshotStorage, urlStorage } from './storage'; import type { Snapshot } from './types'; +import { getImportFileUrl, getImportId } from './url'; const parseZip = async (zip: JSZip) => { const snapshotFile = zip.filter((s) => s.endsWith(`.json`))[0]; @@ -58,7 +59,6 @@ export const importFromLocal = async () => { } }; -const importReg = /^\/(i|(import))\/[0-9]+$/; export const importFromNetwork = async (urls: string[] | string = []) => { if (typeof urls == 'string') { urls = [urls]; @@ -67,15 +67,9 @@ export const importFromNetwork = async (urls: string[] | string = []) => { return; } urls = urls.map((url) => { - if ( - url.startsWith(location.origin) || - url.startsWith('https://i.gkd.li/') - ) { - const pathname = new URL(url).pathname; - if (importReg.test(pathname)) { - const github_asset_id = pathname.split('/').at(-1)!; - return `https://github.com/gkd-kit/inspect/files/${github_asset_id}/file.zip`; - } + const importId = getImportId(url); + if (importId) { + return getImportFileUrl(importId); } return url; }); @@ -85,7 +79,7 @@ export const importFromNetwork = async (urls: string[] | string = []) => { const result = await Promise.allSettled( urls.map((url) => { return limit(async () => { - const snapshotId = urlStorage[url]; + const snapshotId = urlStorage[getImportId(url) || '']; if (snapshotId) { const snapshot = await snapshotStorage.getItem(snapshotId); if (snapshot) { diff --git a/src/utils/storage.ts b/src/utils/storage.ts index 6cc5d74..d974ad0 100644 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -1,6 +1,7 @@ import localforage from 'localforage'; import { reactive, toRaw, watch } from 'vue'; import type { Snapshot } from './types'; +import { getImportId } from './url'; const useStorage = (options: LocalForageOptions = {}) => { options.driver ??= localforage.INDEXEDDB; @@ -40,18 +41,22 @@ const useStorage = (options: LocalForageOptions = {}) => { const useReactiveStorage = ( key: string, - initialValue: (() => T) | T, + initialValue: T, + transform?: (v: T) => T, ) => { - const store = reactive( - typeof initialValue == 'function' ? initialValue() : initialValue, - ); + const store = reactive(initialValue); let storeInited = false; watch(store, async () => { if (!storeInited) return; await localforage.setItem(key, toRaw(store)); }); localforage.getItem(key).then((r) => { - r && Object.assign(store, r); + if (r) { + if (transform) { + r = transform(r as T); + } + Object.assign(store, r); + } storeInited = true; }); return store; @@ -99,8 +104,8 @@ export const setSnapshot = async (snapshot: Snapshot, bf: ArrayBuffer) => { if (githubJpgStorage[snapshot.id]) { delete githubJpgStorage[snapshot.id]; } - if (githubZipStorage[snapshot.id]) { - delete githubZipStorage[snapshot.id]; + if (importStorage[snapshot.id]) { + delete importStorage[snapshot.id]; } importTimeStorage[snapshot.id] = Date.now(); await Promise.all([ @@ -114,7 +119,30 @@ export const cacheStorage = useStorage({ version: 1, }); -export const urlStorage = useReactiveStorage>(`url`, {}); +const isIntString = (v: string | number) => { + if (typeof v === 'number') return true; + if (!v) return false; + return Array.prototype.every.call(v, (c) => '0' <= c && c <= '9'); +}; + +export const urlStorage = useReactiveStorage>( + `url`, + {}, + (obj) => { + // 转换旧数据 + Object.keys(obj).forEach((url) => { + if (isIntString(url)) { + return; + } + const importId = getImportId(url); + if (importId) { + obj[importId] = obj[url]; + } + delete obj[url]; + }); + return obj; + }, +); export const importTimeStorage = useReactiveStorage>( 'importTime', @@ -126,10 +154,24 @@ export const githubJpgStorage = useReactiveStorage>( {}, ); -export const githubZipStorage = useReactiveStorage>( - `githubZip`, - {}, -); +export const importStorage = useReactiveStorage< + Record +>(`githubZip`, {}, (obj) => { + // 转换旧数据 + Object.entries(obj).forEach(([k, _v]) => { + const v = _v as unknown as string; + if (isIntString(v)) { + return; + } + const n1 = getImportId(v); + if (n1) { + obj[k] = +n1; + } else { + delete obj[k]; + } + }); + return obj; +}); export const syncImportStorage = useReactiveStorage< Record diff --git a/src/utils/store.ts b/src/utils/store.ts index e357b5f..2fc4ff6 100644 --- a/src/utils/store.ts +++ b/src/utils/store.ts @@ -1,6 +1,6 @@ -import { reactive } from 'vue'; +import { shallowReactive } from 'vue'; -const store = reactive({ +const store = shallowReactive({ networkErrorDlgVisible: false, githubErrorDlgVisible: false, wasmErrorDlgVisible: false, diff --git a/src/utils/url.ts b/src/utils/url.ts index 31cd6ab..49bef3a 100644 --- a/src/utils/url.ts +++ b/src/utils/url.ts @@ -1,12 +1,9 @@ -import type { Router } from 'vue-router'; - const corsOkOrigins = new Set([ location.origin, `https://cdn.jsdelivr.net`, `https://fastly.jsdelivr.net`, `https://raw.githubusercontent.com`, `https://gist.githubusercontent.com`, - `https://raw.githubusercontents.com`, `https://raw.gitmirror.com`, `https://registry.npmmirror.com`, 'https://detect.gkd.li', @@ -29,24 +26,44 @@ export const isAllowCorsUrl = (targetUrl: string | URL) => { return corsOkOrigins.has(targetUrl.origin); }; -export const githubZipUrlReg = - /^https:\/\/github\.com\/gkd-kit\/inspect\/files\/([0-9]+)\/file\.zip$/; +const urlRegList = [ + /^https:\/\/f\.gkd\.li\/(\d+)$/, + /^https:\/\/github\.com\/gkd-kit\/inspect\/files\/(\d+)\/file\.zip$/, + /^https:\/\/github\.com\/user-attachments\/files\/(\d+)\/file\.zip$/, + /^https:\/\/i\.gkd\.li\/i\/(\d+)$/, + /^https:\/\/i\.gkd\.li\/import\/(\d+)$/, +]; + +export const getImportId = (url: string) => { + if (typeof url !== 'string') return; + if (url.startsWith(location.origin)) { + const importId = +new URL(url).pathname.substring(1); + if (Number.isSafeInteger(importId) && importId > 0) { + return importId; + } + } + for (const reg of urlRegList) { + const id = url.match(reg)?.[1]; + if (id) { + return +id; + } + } +}; + +export const getImportUrl = (importId: number | string) => { + return location.origin + `/i/${importId}`; +}; + +export const getImportFileUrl = (importId: number | string) => { + return `https://github.com/user-attachments/files/${importId}/file.zip`; +}; export const githubImageUrlReg = /^https:\/\/github\.com\/gkd-kit\/inspect\/assets\/([0-9]+)\/([0-9a-z-]+)$/; -export const githubUrlToSelfUrl = (router: Router, u: string | URL): string => { - u = u.toString(); - const { 1: zipAssetId } = u.match(githubZipUrlReg) || []; +export const githubUrlToSelfUrl = (u: string): string => { const { 1: userId, 2: imgAssetId } = u.match(githubImageUrlReg) || []; - if (zipAssetId) { - return ( - location.origin + - router.resolve({ - path: `/i/${zipAssetId}`, - }).href - ); - } else if (userId && imgAssetId) { + if (userId && imgAssetId) { return `https://m.gkd.li/${userId}/${imgAssetId}`; } else { throw new Error( diff --git a/src/views/ImportPage.vue b/src/views/ImportPage.vue index 205c903..35558ce 100644 --- a/src/views/ImportPage.vue +++ b/src/views/ImportPage.vue @@ -1,24 +1,16 @@