From 9b433c82611339eb0f175cb953110f5c84943e18 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 21 Feb 2026 20:16:51 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E6=8A=8A=20fetchIconByDomain=20=E6=94=B9?= =?UTF-8?q?=E6=88=90=20scriptcat.org?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/store/favicons.ts | 67 ++++--------------------------------- 1 file changed, 6 insertions(+), 61 deletions(-) diff --git a/src/pages/store/favicons.ts b/src/pages/store/favicons.ts index 0ed61ef6f..488acb1aa 100644 --- a/src/pages/store/favicons.ts +++ b/src/pages/store/favicons.ts @@ -2,7 +2,6 @@ import { type Script, ScriptDAO } from "@App/app/repo/scripts"; import { FaviconDAO, type FaviconFile, type FaviconRecord } from "@App/app/repo/favicon"; import { v5 as uuidv5 } from "uuid"; import { getFaviconRootFolder } from "@App/app/service/service_worker/utils"; -import { readBlobContent } from "@App/pkg/utils/encoding"; let scriptDAO: ScriptDAO | null = null; let faviconDAO: FaviconDAO | null = null; @@ -92,17 +91,6 @@ export const timeoutAbortSignal = return signal; }; -/** - * 解析相对URL为绝对URL - */ -const resolveUrl = (href: string, base: string): string => { - try { - return new URL(href, base).href; - } catch { - return href; // 如果解析失败,返回原始href - } -}; - export const parseFaviconsNew = (html: string, callback: (href: string) => void) => { // Early exit if no link tags if (!html.toLowerCase().includes(" void) return; }; -const getFilename = (url: string) => { - const i = url.lastIndexOf("/"); - if (i >= 0) return url.substring(i + 1); - return url; -}; - -const checkFileNameEqual = (a: string, b: string) => { - const name1 = getFilename(a); - const name2 = getFilename(b); - return 0 === name1.localeCompare(name2, "en", { sensitivity: "base" }); -}; - /** * 从域名获取favicon */ -export async function fetchIconByDomain(domain: string): Promise { +export async function fetchIconByDomain(domain: string): Promise { const url = `https://${domain}`; - const icons: string[] = []; - - // 设置超时时间(例如 5 秒) - const timeout = 5000; // 单位:毫秒 - - // 获取页面HTML - const response = await fetch(url, { signal: timeoutAbortSignal(timeout) }); - const html = await readBlobContent(response, response.headers.get("content-type")); - const resolvedPageUrl = response.url; - const resolvedUrl = new URL(resolvedPageUrl); - const resolvedOrigin = resolvedUrl.origin; - - parseFaviconsNew(html, (href) => icons.push(resolveUrl(href, resolvedPageUrl))); - - // 检查默认favicon位置 - if (icons.length === 0) { - const faviconUrl = `${resolvedOrigin}/favicon.ico`; - icons.push(faviconUrl); + const sDomain = new URL(url).hostname; + if (!sDomain || sDomain.length > 253) { + throw new Error("invalid domain name"); } - - const urls = await Promise.all( - icons.map((icon) => - fetch(icon, { method: "HEAD", signal: timeoutAbortSignal(timeout) }) - .then((res) => { - if (res.ok && checkFileNameEqual(res.url, icon)) { - return res.url; - } - }) - .catch(() => { - // 忽略错误 - }) - ) - ); - - return urls.filter((url) => !!url) as string[]; + return `https://scriptcat.org/api/v2/open/favicons?domain=${encodeURIComponent(sDomain)}&sz=64`; } // 获取脚本的favicon @@ -199,8 +145,7 @@ export const getScriptFavicon = async (uuid: string): Promise = domains.map(async (domain) => { try { if (domain.domain) { - const icons = await fetchIconByDomain(domain.domain); - const icon = icons.length > 0 ? icons[0] : ""; + const icon = await fetchIconByDomain(domain.domain); return { match: domain.match, website: "http://" + domain.domain, icon }; } } catch { From 4f3b91884d830fd67c509ce071cdecad88b356d5 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:20:58 +0900 Subject: [PATCH 2/2] scriptcat.org -> ext.scriptcat.org --- src/pages/store/favicons.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/store/favicons.ts b/src/pages/store/favicons.ts index 488acb1aa..541eb8fe7 100644 --- a/src/pages/store/favicons.ts +++ b/src/pages/store/favicons.ts @@ -7,6 +7,9 @@ let scriptDAO: ScriptDAO | null = null; let faviconDAO: FaviconDAO | null = null; const loadFaviconPromises = new Map(); // 关联 iconUrl 和 blobUrl +const FETCH_SERVICE_URL = "https://ext.scriptcat.org/api/v1/open/favicons"; +const FETCH_ICON_SIZE = 64; + /** * 从URL模式中提取域名 */ @@ -122,7 +125,7 @@ export async function fetchIconByDomain(domain: string): Promise { if (!sDomain || sDomain.length > 253) { throw new Error("invalid domain name"); } - return `https://scriptcat.org/api/v2/open/favicons?domain=${encodeURIComponent(sDomain)}&sz=64`; + return `${FETCH_SERVICE_URL}?domain=${encodeURIComponent(sDomain)}&sz=${FETCH_ICON_SIZE}`; } // 获取脚本的favicon