-
-
-
-
{t("favicon_service_desc")}
+
+
+ {t("favicon_service")}
+
+
{t("favicon_service_desc")}
From 86ed745fb94fa0ed976d4847d156dc16bbe4538d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?=
Date: Wed, 11 Mar 2026 21:40:13 +0800
Subject: [PATCH 5/9] =?UTF-8?q?=F0=9F=90=9B=20=E4=BF=AE=E5=A4=8D=20local?=
=?UTF-8?q?=20=E6=A8=A1=E5=BC=8F=E4=B8=8B=20favicon=20=E8=8E=B7=E5=8F=96?=
=?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=8C=E8=BF=98=E5=8E=9F=E6=9C=AC=E5=9C=B0?=
=?UTF-8?q?=E6=8A=93=E5=8F=96=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/store/favicons.ts | 73 ++++++++++++++++++++++++++++++++-----
1 file changed, 63 insertions(+), 10 deletions(-)
diff --git a/src/pages/store/favicons.ts b/src/pages/store/favicons.ts
index 28b5bffa8..34d68e1fd 100644
--- a/src/pages/store/favicons.ts
+++ b/src/pages/store/favicons.ts
@@ -9,9 +9,6 @@ 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模式中提取域名
*/
@@ -96,6 +93,17 @@ 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 sDomain = new URL(url).hostname;
- if (!sDomain || sDomain.length > 253) {
- throw new Error("invalid domain name");
+ 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);
}
- return `${FETCH_SERVICE_URL}?domain=${encodeURIComponent(sDomain)}&sz=${FETCH_ICON_SIZE}`;
+
+ 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[];
}
/**
@@ -140,12 +190,15 @@ export async function fetchIconByService(domain: string, service: FaviconService
case "google":
return [`https://www.google.com/s2/favicons?domain=${encodeURIComponent(domain)}&sz=64`];
case "local":
- return fetchIconByDomain(domain);
+ return await fetchIconByDomain(domain);
}
}
// 获取脚本的favicon
-export const getScriptFavicon = async (uuid: string, service: FaviconService = "scriptcat"): Promise => {
+export const getScriptFavicon = async (
+ uuid: string,
+ service: FaviconService = "scriptcat"
+): Promise => {
scriptDAO ||= new ScriptDAO();
faviconDAO ||= new FaviconDAO();
const script = await scriptDAO.get(uuid);
From 0a69c27cb74033549cc6e43dd6367603b018df0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?=
Date: Wed, 11 Mar 2026 21:43:25 +0800
Subject: [PATCH 6/9] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=9B=BE=E6=A0=87?=
=?UTF-8?q?=E6=9C=8D=E5=8A=A1=E4=BD=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/pages/options/routes/Setting.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/pages/options/routes/Setting.tsx b/src/pages/options/routes/Setting.tsx
index 41ff6e6a3..3f03ca51d 100644
--- a/src/pages/options/routes/Setting.tsx
+++ b/src/pages/options/routes/Setting.tsx
@@ -334,8 +334,8 @@ function Setting() {
}}
>
{t("favicon_service_scriptcat")}
- {t("favicon_service_local")}
{t("favicon_service_google")}
+ {t("favicon_service_local")}
From ff828522e5d4a9b1fb53112d54d11b796f7a87d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?=