Skip to content
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
29c949c
不依赖外部网站访问进行安装
cyfung1031 Oct 18, 2025
d5f6310
Update script.ts
cyfung1031 Oct 18, 2025
404daa7
修正 fetchScriptBody
cyfung1031 Oct 18, 2025
49ccdb4
css
cyfung1031 Oct 18, 2025
8e00da0
css
cyfung1031 Oct 18, 2025
d5dd55f
css
cyfung1031 Oct 18, 2025
984b571
i18n t
cyfung1031 Oct 18, 2025
59ba067
css
cyfung1031 Oct 18, 2025
031d412
css
cyfung1031 Oct 18, 2025
d95d5b4
显示 7.5 个项目来提醒使用者以滚动浏览更多
cyfung1031 Oct 18, 2025
f6ebfb9
空白调整
cyfung1031 Oct 18, 2025
aac9f3f
Merge remote-tracking branch 'upstream/main' into pr-network-1003
cyfung1031 Oct 18, 2025
d8ff8fd
.
cyfung1031 Oct 19, 2025
694177b
兼容修正
cyfung1031 Oct 24, 2025
1d5db72
#876
cyfung1031 Oct 24, 2025
cd8fae0
lint
cyfung1031 Oct 24, 2025
ebd6a4f
i18n
cyfung1031 Oct 24, 2025
9eca6c4
#877
cyfung1031 Oct 24, 2025
9fe2303
#877 修正
cyfung1031 Nov 5, 2025
ace4c07
Merge remote-tracking branch 'upstream/main' into pr-network-1003
cyfung1031 Nov 15, 2025
fde4eac
Merge branch 'release/v1.3' into pr/cyfung1031/842
CodFrm Nov 18, 2025
e0375eb
合并
CodFrm Nov 18, 2025
55cf73f
typescript fix
cyfung1031 Nov 18, 2025
5b8b1fb
Update src/locales/de-DE/translation.json
cyfung1031 Nov 19, 2025
350b592
Update src/pages/install/App.tsx
cyfung1031 Nov 19, 2025
d075143
Update src/pages/install/App.tsx
cyfung1031 Nov 19, 2025
b8631e2
chrome.runtime.lastError
cyfung1031 Nov 19, 2025
4e31818
fix
cyfung1031 Nov 19, 2025
121e737
中文
cyfung1031 Nov 19, 2025
a22e03c
formatBytes
cyfung1031 Nov 19, 2025
b844d56
整理代码和添加单元测试
CodFrm Nov 20, 2025
d18b9cb
修复typecheck
CodFrm Nov 20, 2025
33383ec
添加dels测试
CodFrm Nov 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/app/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ class ExtCache implements CacheStorage {
});
}

dels(keys: string[]): Promise<void> {
return new Promise((resolve) => {
chrome.storage.session.remove(keys, () => {
const lastError = chrome.runtime.lastError;
if (lastError) {
console.error("chrome.runtime.lastError in chrome.storage.session.remove:", lastError);
// 无视storage API错误,继续执行
}
resolve();
});
});
}

clear(): Promise<void> {
return new Promise((resolve) => {
chrome.storage.session.clear(() => {
Expand Down
191 changes: 104 additions & 87 deletions src/app/service/service_worker/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ import { type ResourceService } from "./resource";
import { type ValueService } from "./value";
import { compileScriptCode } from "../content/utils";
import { type SystemConfig } from "@App/pkg/config/config";
import { localePath, watchLanguageChange } from "@App/locales/locales";
import { arrayMove } from "@dnd-kit/sortable";
import { DocumentationSite } from "@App/app/const";
import type {
TScriptRunStatus,
TDeleteScript,
Expand All @@ -39,7 +37,6 @@ import type {
TSortedScript,
TInstallScriptParams,
} from "../queue";
import { timeoutExecution } from "@App/pkg/utils/timer";
import { buildScriptRunResourceBasic, selfMetadataUpdate } from "./utils";
import {
BatchUpdateListActionCode,
Expand All @@ -54,8 +51,6 @@ import { CompiledResourceDAO } from "@App/app/repo/resource";
import { initRegularUpdateCheck } from "./regular_updatecheck";
// import { gzip as pakoGzip } from "pako";

const cIdKey = `(cid_${Math.random()})`;

export type TCheckScriptUpdateOption = Partial<
{ checkType: "user"; noUpdateCheck?: number } | ({ checkType: "system" } & Record<string, any>)
>;
Expand Down Expand Up @@ -84,13 +79,14 @@ export class ScriptService {

listenerScriptInstall() {
// 初始化脚本安装监听
chrome.webRequest.onBeforeRequest.addListener(
(req: chrome.webRequest.OnBeforeRequestDetails) => {
// 处理url, 实现安装脚本
if (req.method !== "GET") {
return undefined;
chrome.webNavigation.onBeforeNavigate.addListener(
(req: chrome.webNavigation.WebNavigationBaseCallbackDetails) => {
const lastError = chrome.runtime.lastError;
if (lastError) {
console.error(lastError.message);
}
Comment on lines +84 to 88
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

webNavigation.onBeforeNavigate监听器中检查chrome.runtime.lastError的时机不正确。chrome.runtime.lastError应该在异步API的回调函数中检查,而不是在事件监听器的开始。

在这个上下文中,lastError应该总是undefined,因为这里没有进行任何Chrome API调用。建议删除这段代码:

const lastError = chrome.runtime.lastError;
if (lastError) {
  console.error(lastError.message);
}
Suggested change
const lastError = chrome.runtime.lastError;
if (lastError) {
console.error(lastError.message);
}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

什麼鬼?

let targetUrl: string | null = null;
// 处理url, 实现安装脚本
let targetUrl: string;
// 判断是否为 file:///*/*.user.js
if (req.url.startsWith("file://") && req.url.endsWith(".user.js")) {
targetUrl = req.url;
Expand All @@ -101,11 +97,12 @@ export class ScriptService {
return undefined;
}
// 判断是否有url参数
if (!reqUrl.hash.includes("url=")) {
const idx = reqUrl.hash.indexOf("url=");
if (idx < 0) {
return undefined;
}
// 获取url参数
targetUrl = reqUrl.hash.split("url=")[1];
targetUrl = reqUrl.hash.substring(idx + 4);
}
// 读取脚本url内容, 进行安装
const logger = this.logger.with({ url: targetUrl });
Expand Down Expand Up @@ -153,15 +150,30 @@ export class ScriptService {
});
},
{
urls: [
`${DocumentationSite}/docs/script_installation/*`,
`${DocumentationSite}/en/docs/script_installation/*`,
"https://www.tampermonkey.net/script_installation.php*",
"file:///*/*.user.js*",
url: [
{ schemes: ["http", "https"], hostEquals: "docs.scriptcat.org", pathPrefix: "/docs/script_installation/" },
{ schemes: ["http", "https"], hostEquals: "docs.scriptcat.org", pathPrefix: "/en/docs/script_installation/" },
{ schemes: ["http", "https"], hostEquals: "www.tampermonkey.net", pathPrefix: "/script_installation.php" },
{ schemes: ["file"], pathSuffix: ".user.js" },
],
types: ["main_frame"],
}
);

// chrome.webRequest.onHeadersReceived.addListener(
// (details) => {
// const lastError = chrome.runtime.lastError;
// if (lastError) {
// console.error(lastError.message);
// }
// console.log("onHeadersReceived inspect", details);
// return undefined;
// },
// {
// urls: ["*://*/*.user.js", "*://*/*.user.bg.js", "*://*/*.user.sub.js"],
// },
// ["responseHeaders"]
// );

Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

大段注释掉的代码(第162-175行)应该被删除。如果这是用于调试或将来可能需要的功能,应该在代码注释中说明原因,或者直接删除并依赖版本控制系统。保留大量注释代码会影响代码的可读性和维护性。

Suggested change
// chrome.webRequest.onHeadersReceived.addListener(
// (details) => {
// const lastError = chrome.runtime.lastError;
// if (lastError) {
// console.error(lastError.message);
// }
// console.log("onHeadersReceived inspect", details);
// return undefined;
// },
// {
// urls: ["*://*/*.user.js", "*://*/*.user.bg.js", "*://*/*.user.sub.js"],
// },
// ["responseHeaders"]
// );

Copilot uses AI. Check for mistakes.
// 兼容 chrome 内核 < 128 处理
const browserType = getBrowserType();
const addResponseHeaders = browserType.chrome && browserType.chromeVersion >= 128;
Expand Down Expand Up @@ -243,94 +255,99 @@ export class ScriptService {
requestDomains: ["bitbucket.org"], // Chrome 101+
},
];
watchLanguageChange(() => {
const rules = conditions.map((condition, idx) => {
const installPageURL = chrome.runtime.getURL("src/install.html");
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listenerScriptInstall方法中,chrome.runtime.getURL("src/install.html")在每次方法调用时都会执行。由于这个URL在扩展的生命周期内是不变的,建议将其移到类的构造函数或作为类的静态属性,避免重复计算。

例如:

private readonly installPageURL: string;

constructor(...) {
  // ...
  this.installPageURL = chrome.runtime.getURL("src/install.html");
}

Copilot uses AI. Check for mistakes.
const rules = conditions.map((condition, idx) => {
Object.assign(condition, {
excludedTabIds: [chrome.tabs.TAB_ID_NONE],
});
if (addResponseHeaders) {
Object.assign(condition, {
excludedTabIds: [chrome.tabs.TAB_ID_NONE],
});
if (addResponseHeaders) {
Object.assign(condition, {
responseHeaders: [
{
header: "Content-Type",
values: [
"text/javascript*",
"application/javascript*",
"text/html*",
"text/plain*",
"application/octet-stream*",
"application/force-download*",
],
},
],
});
}
return {
id: 1000 + idx,
priority: 1,
action: {
type: "redirect" as chrome.declarativeNetRequest.RuleActionType,
redirect: {
regexSubstitution: `${DocumentationSite}${localePath}/docs/script_installation/#url=\\1`,
responseHeaders: [
{
header: "Content-Type",
values: [
"text/javascript*",
"application/javascript*",
"text/html*",
"text/plain*",
"application/octet-stream*",
"application/force-download*",
],
},
],
});
}
return {
id: 1000 + idx,
priority: 1,
action: {
type: "redirect" as chrome.declarativeNetRequest.RuleActionType,
redirect: {
regexSubstitution: `${installPageURL}?url=\\1`,
},
condition: condition,
} as chrome.declarativeNetRequest.Rule;
});
// 重定向到脚本安装页
chrome.declarativeNetRequest.updateDynamicRules(
{
removeRuleIds: [1],
},
() => {
if (chrome.runtime.lastError) {
console.error(
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateDynamicRules:",
chrome.runtime.lastError
);
}
condition: condition,
} as chrome.declarativeNetRequest.Rule;
});
// 重定向到脚本安装页
chrome.declarativeNetRequest.updateDynamicRules(
{
removeRuleIds: [1],
},
() => {
if (chrome.runtime.lastError) {
console.error(
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateDynamicRules:",
chrome.runtime.lastError
);
}
);
chrome.declarativeNetRequest.updateSessionRules(
{
removeRuleIds: [...rules.map((rule) => rule.id)],
addRules: rules,
},
() => {
if (chrome.runtime.lastError) {
console.error(
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateSessionRules:",
chrome.runtime.lastError
);
}
}
);
chrome.declarativeNetRequest.updateSessionRules(
{
removeRuleIds: [...rules.map((rule) => rule.id)],
addRules: rules,
},
() => {
if (chrome.runtime.lastError) {
console.error(
"chrome.runtime.lastError in chrome.declarativeNetRequest.updateSessionRules:",
chrome.runtime.lastError
);
}
);
});
}
);
}

public async openInstallPageByUrl(
url: string,
options: { source: InstallSource; byWebRequest?: boolean }
): Promise<{ success: boolean; msg: string }> {
const uuid = uuidv4();
try {
await this.openUpdateOrInstallPage(uuid, url, options, false);
timeoutExecution(
`${cIdKey}_cleanup_${uuid}`,
() => {
// 清理缓存
cacheInstance.del(`${CACHE_KEY_SCRIPT_INFO}${uuid}`);
},
30 * 1000
);
await openInCurrentTab(`/src/install.html?uuid=${uuid}`);
const installPageUrl = await this.getInstallPageUrl(url, options);
if (!installPageUrl) throw new Error("getInstallPageUrl failed");
await openInCurrentTab(installPageUrl);
return { success: true, msg: "" };
} catch (err: any) {
console.error(err);
return { success: false, msg: err.message };
}
}

public async getInstallPageUrl(
url: string,
options: { source: InstallSource; byWebRequest?: boolean }
): Promise<string> {
const uuid = uuidv4();
try {
await this.openUpdateOrInstallPage(uuid, url, options, false);
return `/src/install.html?uuid=${uuid}`;
} catch (err: any) {
console.error(err);
return "";
}
}

// 直接通过url静默安装脚本
async installByUrl(url: string, source: InstallSource, subscribeUrl?: string) {
const uuid = uuidv4();
Expand Down
6 changes: 5 additions & 1 deletion src/locales/ach-UG/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@
"script_requires": "crwdns8440:0crwdne8440:0",
"cookie_warning": "crwdns8442:0crwdne8442:0",
"scheduled_script_description_title": "crwdns8706:0crwdne8706:0",
"scheduled_script_description_description": "crwdns8708:0{{expression}}crwdnd8708:0{{time}}crwdne8708:0",
"scheduled_script_description_description_expr": "crwdns8708:0",
"scheduled_script_description_description_next": "crwdns8708:0",
"background_script_description": "crwdns8444:0crwdne8444:0",
"install_success": "crwdns8446:0crwdne8446:0",
"install": {
Expand Down Expand Up @@ -321,6 +322,9 @@
"status_autoclose": "crwdns12778:0crwdne12778:0",
"header_other_update": "crwdns12784:0crwdne12784:0"
},
"downloading_status_text": "Downloading. Received {{bytes}}.",
"install_page_loading": "Installation page loading",
"invalid_page": "Invalid page",
"background_script_tag": "crwdns8460:0crwdne8460:0",
"scheduled_script_tag": "crwdns8462:0crwdne8462:0",
"background_script": "crwdns8464:0crwdne8464:0",
Expand Down
6 changes: 5 additions & 1 deletion src/locales/de-DE/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@
"script_requires": "Skript referenziert die folgenden externen Ressourcen",
"cookie_warning": "Achtung: Dieses Skript beantragt Cookie-Operationsberechtigung. Dies ist eine gefährliche Berechtigung, bitte stellen Sie die Sicherheit des Skripts sicher.",
"scheduled_script_description_title": "Dies ist ein geplantes Skript. Wenn aktiviert, wird es zu bestimmten Zeiten automatisch ausgeführt und kann im Panel manuell gesteuert werden.",
"scheduled_script_description_description": "Geplante Aufgaben-Ausdruck: {{expression}}, letzte Ausführungszeit: {{time}}",
"scheduled_script_description_description_expr": "Geplante Aufgaben-Ausdruck",
"scheduled_script_description_description_next": "Letzte Ausführungszeit",
Comment thread
cyfung1031 marked this conversation as resolved.
Outdated
"background_script_description": "Dies ist ein Hintergrundskript. Wenn aktiviert, wird es automatisch einmal ausgeführt, wenn der Browser geöffnet wird, und kann im Panel manuell gesteuert werden.",
"install_success": "Installation erfolgreich",
"install": {
Expand Down Expand Up @@ -321,6 +322,9 @@
"status_autoclose": "Automatisches Schließen in $0 Sekunden",
"header_other_update": "Andere verfügbare Updates"
},
"downloading_status_text": "Wird heruntergeladen. {{bytes}} empfangen.",
"install_page_loading": "Installationsseite wird geladen",
"invalid_page": "Ungültige Seite",
"background_script_tag": "Dies ist ein Hintergrundskript",
"scheduled_script_tag": "Dies ist ein geplantes Skript",
"background_script": "Hintergrundskript",
Expand Down
6 changes: 5 additions & 1 deletion src/locales/en-US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@
"script_requires": "Script requires the following external resources",
"cookie_warning": "Please note, this script requests access to Cookie permissions, which is a dangerous permission. Please verify the security of the script.",
"scheduled_script_description_title": "This is a scheduled script, which will automatically run at a specific time once enabled and can be manually controlled in the panel.",
"scheduled_script_description_description": "Scheduled task expression: {{expression}}, most recent run time: {{time}}",
"scheduled_script_description_description_expr": "Scheduled task expression:",
"scheduled_script_description_description_next": "Most recent run time:",
"background_script_description": "This is a background script, which will automatically run once when the browser opens once enabled, and can be manually controlled in the panel.",
"install_success": "Install Successful",
"install": {
Expand Down Expand Up @@ -321,6 +322,9 @@
"status_autoclose": "Auto-closing in $0 seconds",
"header_other_update": "Other available updates"
},
"downloading_status_text": "Downloading. Received {{bytes}}.",
"install_page_loading": "Installation page loading",
"invalid_page": "Invalid page",
"background_script_tag": "This is a Background Script",
"scheduled_script_tag": "This is a Scheduled Script",
"background_script": "Background Script",
Expand Down
6 changes: 5 additions & 1 deletion src/locales/ja-JP/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@
"script_requires": "スクリプトは以下の外部リソースを参照しています",
"cookie_warning": "注意:このスクリプトはCookieの操作権限を申請します。これは危険な権限ですので、スクリプトの安全性を確認してください。",
"scheduled_script_description_title": "これはスケジュールスクリプトです。有効にすると特定の時間に自動実行され、手動操作も可能です。",
"scheduled_script_description_description": "スケジュールタスク式:{{expression}}、最近の実行時間:{{time}}",
"scheduled_script_description_description_expr": "スケジュールタスク表現:",
"scheduled_script_description_description_next": "最近の実行時間:",
"background_script_description": "これはバックグラウンドスクリプトです。有効にするとブラウザを開いたときに自動的に一度実行され、パネルで手動制御できます。",
"install_success": "インストールに成功しました",
"install": {
Expand Down Expand Up @@ -321,6 +322,9 @@
"status_autoclose": "$0 秒後に自動的に閉じます",
"header_other_update": "その他の利用可能な更新"
},
"downloading_status_text": "ダウンロード中。{{bytes}} を受信しました。",
"install_page_loading": "インストールページを読み込み中",
"invalid_page": "無効なページ",
"background_script_tag": "これはバックグラウンドスクリプトです",
"scheduled_script_tag": "これはスケジュールスクリプトです",
"background_script": "バックグラウンドスクリプト",
Expand Down
6 changes: 5 additions & 1 deletion src/locales/ru-RU/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,8 @@
"script_requires": "Скрипт ссылается на следующие внешние ресурсы",
"cookie_warning": "Обратите внимание, что этот скрипт запрашивает разрешения на операции с Cookie. Это опасное разрешение, пожалуйста, убедитесь в безопасности скрипта.",
"scheduled_script_description_title": "Это запланированный скрипт. После включения он будет автоматически выполняться в определенное время и может управляться вручную с панели.",
"scheduled_script_description_description": "Выражение планировщика: {{expression}}, последнее время выполнения: {{time}}",
"scheduled_script_description_description_expr": "Выражение планировщика",
Copy link

Copilot AI Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

俄语翻译缺少冒号。对比其他语言版本(英语、中文、日语、越南语等),这个字符串应该以冒号结尾以保持一致性。

Suggested change
"scheduled_script_description_description_expr": "Выражение планировщика",
"scheduled_script_description_description_expr": "Выражение планировщика:",

Copilot uses AI. Check for mistakes.
"scheduled_script_description_description_next": "Последнее время выполнения:",
"background_script_description": "Это фоновый скрипт. После включения он будет автоматически выполняться один раз при открытии браузера и может управляться вручную с панели.",
"install_success": "Установка успешна",
"install": {
Expand Down Expand Up @@ -321,6 +322,9 @@
"status_autoclose": "Автоматическое закрытие через $0 сек.",
"header_other_update": "Другие доступные обновления"
},
"downloading_status_text": "Загрузка. Получено {{bytes}}.",
"install_page_loading": "Загрузка страницы установки",
"invalid_page": "Недействительная страница",
"background_script_tag": "Это фоновый скрипт",
"scheduled_script_tag": "Это запланированный скрипт",
"background_script": "Фоновый скрипт",
Expand Down
Loading
Loading