From e913cf86b79e0e21b10aca81243f79cb7c240a7e Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:12:53 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20WakeUpPing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/offscreen.ts | 2 ++ src/pkg/utils/wakeup-ping.ts | 65 ++++++++++++++++++++++++++++++++++++ src/service_worker.ts | 6 ++++ 3 files changed, 73 insertions(+) create mode 100644 src/pkg/utils/wakeup-ping.ts diff --git a/src/offscreen.ts b/src/offscreen.ts index 9cc1cb42c..f8c51f8a3 100644 --- a/src/offscreen.ts +++ b/src/offscreen.ts @@ -2,6 +2,7 @@ import LoggerCore from "./app/logger/core"; import MessageWriter from "./app/logger/message_writer"; import { OffscreenManager } from "./app/service/offscreen"; import { ServiceWorkerClientMessage } from "@Packages/message/window_message"; +import { startRepetitivePing } from "./pkg/utils/wakeup-ping"; function main() { // 通过postMessage与SW通信,支持结构化克隆(Blob等) @@ -15,6 +16,7 @@ function main() { // 初始化管理器 const manager = new OffscreenManager(swPostMessage); manager.initManager(); + startRepetitivePing(); } main(); diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts new file mode 100644 index 000000000..c1f22dd8e --- /dev/null +++ b/src/pkg/utils/wakeup-ping.ts @@ -0,0 +1,65 @@ +const PING_INTERVAL_MS = 14_225; + +/** + * scheduler 用于后台排程:Chrome 94+, Firefox 142+ + * @link https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask + */ +const nativeScheduler = + //@ts-ignore + typeof scheduler !== "undefined" && typeof scheduler?.postTask === "function" && scheduler; + +// 高效的 BroadcastChannel 通讯:service worker 和 offscreen 共用同一通道 +const channel = new BroadcastChannel("custom-ping"); + +export const startRepetitivePing = () => { + if (typeof frameElement === "object" && typeof document === "object" && document) { + let counter = 0; + let isMutationPending = false; + + const customPingHandler = (e: Event) => { + chrome.storage.session.set({ persistentWakeup: `${e.timeStamp}` }); + }; + + const pingNode = document.createComment("0"); + + const incrementCounter = () => { + if (!isMutationPending) { + isMutationPending = true; + counter = counter > 8 ? 1 : counter + 1; + pingNode.data = `${counter}`; + } + }; + + pingNode.addEventListener("custom-ping", customPingHandler); + + const pingTask = async () => { + channel.postMessage({}); + incrementCounter(); + }; + + const mutationObserver = new MutationObserver(() => { + if (isMutationPending) { + isMutationPending = false; + if (nativeScheduler) { + nativeScheduler.postTask(pingTask, { priority: "background", delay: PING_INTERVAL_MS }); + } else { + setTimeout(pingTask, PING_INTERVAL_MS); + } + } + }); + mutationObserver.observe(pingNode, { characterData: true }); + incrementCounter(); + } +}; + +export const listenWakeupPing = (onWakeupPing: (...args: any) => any) => { + chrome.storage.session.onChanged.addListener((obj) => { + // consume persistentWakeup + if (typeof obj.persistentWakeup !== "undefined") { + onWakeupPing(); + } + }); + channel.onmessage = (e) => { + chrome.storage.session.set({ persistentWakeup: `${e.timeStamp}` }); + }; +}; diff --git a/src/service_worker.ts b/src/service_worker.ts index 407a27922..85d445516 100644 --- a/src/service_worker.ts +++ b/src/service_worker.ts @@ -8,6 +8,7 @@ import { MessageQueue } from "@Packages/message/message_queue"; import { ServiceWorkerMessageSend } from "@Packages/message/window_message"; import migrate, { migrateChromeStorage } from "./app/migrate"; import { cleanInvalidKeys } from "./app/repo/resource"; +import { listenWakeupPing } from "./pkg/utils/wakeup-ping"; migrate(); migrateChromeStorage(); @@ -59,6 +60,10 @@ async function setupOffscreenDocument() { } } +export const onWakeupPing = () => { + console.debug("onWakeupPing"); // 不用记录在系统日志 +}; + function main() { cleanInvalidKeys(); // 初始化管理器 @@ -77,6 +82,7 @@ function main() { manager.initManager(); // 初始化沙盒环境 setupOffscreenDocument(); + listenWakeupPing(onWakeupPing); } main(); From fb8d80c0021269c2d463fbb3fc6f63206103cade Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:59:39 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=9C=AA=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pkg/utils/wakeup-ping.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index c1f22dd8e..fe05194e8 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -16,10 +16,6 @@ export const startRepetitivePing = () => { let counter = 0; let isMutationPending = false; - const customPingHandler = (e: Event) => { - chrome.storage.session.set({ persistentWakeup: `${e.timeStamp}` }); - }; - const pingNode = document.createComment("0"); const incrementCounter = () => { @@ -30,8 +26,6 @@ export const startRepetitivePing = () => { } }; - pingNode.addEventListener("custom-ping", customPingHandler); - const pingTask = async () => { channel.postMessage({}); incrementCounter(); From efda557e771a068736695b81091d420411c97b8b Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:01:51 +0900 Subject: [PATCH 3/9] =?UTF-8?q?=E4=B8=AD=E6=96=87=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pkg/utils/wakeup-ping.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index fe05194e8..47d40ff37 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -48,12 +48,14 @@ export const startRepetitivePing = () => { export const listenWakeupPing = (onWakeupPing: (...args: any) => any) => { chrome.storage.session.onChanged.addListener((obj) => { - // consume persistentWakeup + // 消耗 persistentWakeup if (typeof obj.persistentWakeup !== "undefined") { + // 执行任意 callback onWakeupPing(); } }); channel.onmessage = (e) => { + // 触发 chrome storage onChanged 使 service worker 保持活跃 chrome.storage.session.set({ persistentWakeup: `${e.timeStamp}` }); }; }; From 86491b98162631aa79cecae193e469bf95e7e345 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:09:46 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=E9=87=87=E7=94=A8=E9=9A=8F=E6=9C=BA?= =?UTF-8?q?=E9=97=B4=E9=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pkg/utils/wakeup-ping.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index 47d40ff37..016e95e28 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -1,4 +1,5 @@ -const PING_INTERVAL_MS = 14_225; +const PING_INTERVAL_MS_1 = 13_225; +const PING_INTERVAL_MS_2 = 17_765; /** * scheduler 用于后台排程:Chrome 94+, Firefox 142+ @@ -34,10 +35,11 @@ export const startRepetitivePing = () => { const mutationObserver = new MutationObserver(() => { if (isMutationPending) { isMutationPending = false; + const pingIntervalMs = Math.random() * (PING_INTERVAL_MS_2 - PING_INTERVAL_MS_1) + PING_INTERVAL_MS_1; if (nativeScheduler) { - nativeScheduler.postTask(pingTask, { priority: "background", delay: PING_INTERVAL_MS }); + nativeScheduler.postTask(pingTask, { priority: "background", delay: pingIntervalMs }); } else { - setTimeout(pingTask, PING_INTERVAL_MS); + setTimeout(pingTask, pingIntervalMs); } } }); From 8f33bd4b533492fc906e553ed4326d399fa92677 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 25 Apr 2026 06:51:32 +0900 Subject: [PATCH 5/9] Update service_worker.ts --- src/service_worker.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/service_worker.ts b/src/service_worker.ts index 85d445516..648372aba 100644 --- a/src/service_worker.ts +++ b/src/service_worker.ts @@ -61,7 +61,8 @@ async function setupOffscreenDocument() { } export const onWakeupPing = () => { - console.debug("onWakeupPing"); // 不用记录在系统日志 + //@ts-ignore + self.lastWakeupPing = new Date().toLocaleString("zh"); // 僅在後台DevTools debug用 }; function main() { From adebb9bcaf62453cecb441586937e4451847f272 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 25 Apr 2026 09:52:31 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=E6=94=B9=E4=B8=BA=20wakeupPingCommand=20?= =?UTF-8?q?=EF=BC=9A=E5=8F=AA=E5=9C=A8=E9=9C=80=E8=A6=81=E6=97=B6=20ping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/service_worker/gm_api/gm_api.ts | 19 +++++++++ src/offscreen.ts | 4 +- src/pkg/utils/wakeup-ping.ts | 39 ++++++++++++++++--- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/app/service/service_worker/gm_api/gm_api.ts b/src/app/service/service_worker/gm_api/gm_api.ts index 755096d21..2579d1653 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -54,6 +54,7 @@ import { headerModifierMap, headersReceivedMap } from "./gm_xhr"; import { BgGMXhr } from "@App/pkg/utils/xhr/bg_gm_xhr"; import { mightPrepareSetClipboard, setClipboard } from "../clipboard"; import { nativePageWindowOpen } from "../../offscreen/gm_api"; +import { WakeUpCommand, wakeupPingCommand } from "@App/pkg/utils/wakeup-ping"; let generatedUniqueMarkerIDs = ""; let generatedUniqueMarkerIDWhen = ""; @@ -799,11 +800,27 @@ export default class GMApi { if (!sender.isType(GetSenderType.CONNECT)) { throw new Error("GM_xmlhttpRequest ERROR: sender is not MessageConnect"); } + + // https://github.com/scriptscat/scriptcat/issues/1343 + let wakeupTrigger = true; + wakeupPingCommand(WakeUpCommand.START); + const wakeupStop = () => { + try { + if (wakeupTrigger) { + wakeupTrigger = false; + wakeupPingCommand(WakeUpCommand.STOP); + } + } catch { + // ignored + } + }; + const msgConn = sender.getConnect()!; let isConnDisconnected = false; msgConn.onDisconnect(() => { isConnDisconnected = true; + wakeupStop(); }); // 关联自己生成的请求id与chrome.webRequest的请求id @@ -854,6 +871,7 @@ export default class GMApi { useFetch = isFetch || !!redirect || anonymous || isBufferStream; } const loadendCleanUp = () => { + wakeupStop(); redirectedUrls.delete(markerID); nwErrorResults.delete(markerID); const reqId = scXhrRequests.get(markerID); @@ -905,6 +923,7 @@ export default class GMApi { msgConn.onDisconnect(offscreenCon.disconnect.bind(offscreenCon)); } } catch (e: any) { + wakeupStop(); const errorMsg = `GM_xmlhttpRequest ERROR: ${e?.message || e || "Unknown Error"}`; if (!isConnDisconnected) { msgConn.sendMessage({ diff --git a/src/offscreen.ts b/src/offscreen.ts index f8c51f8a3..4c666c2a8 100644 --- a/src/offscreen.ts +++ b/src/offscreen.ts @@ -2,7 +2,7 @@ import LoggerCore from "./app/logger/core"; import MessageWriter from "./app/logger/message_writer"; import { OffscreenManager } from "./app/service/offscreen"; import { ServiceWorkerClientMessage } from "@Packages/message/window_message"; -import { startRepetitivePing } from "./pkg/utils/wakeup-ping"; +import { initializeWakeupPing } from "./pkg/utils/wakeup-ping"; function main() { // 通过postMessage与SW通信,支持结构化克隆(Blob等) @@ -16,7 +16,7 @@ function main() { // 初始化管理器 const manager = new OffscreenManager(swPostMessage); manager.initManager(); - startRepetitivePing(); + initializeWakeupPing(); } main(); diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index 016e95e28..2f9d4e880 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -1,6 +1,13 @@ const PING_INTERVAL_MS_1 = 13_225; const PING_INTERVAL_MS_2 = 17_765; +export const WakeUpCommand = { + START: 0x100, + STOP: 0x200, +} as const; + +export type WakeUpCommand = ValueOf; + /** * scheduler 用于后台排程:Chrome 94+, Firefox 142+ * @link https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask @@ -10,17 +17,22 @@ const nativeScheduler = typeof scheduler !== "undefined" && typeof scheduler?.postTask === "function" && scheduler; // 高效的 BroadcastChannel 通讯:service worker 和 offscreen 共用同一通道 -const channel = new BroadcastChannel("custom-ping"); +const channel = new BroadcastChannel("custom-ping"); // offscreen -> sw +const channelCommand = new BroadcastChannel("custom-ping-command"); // sw -> offscreen +let startCounter = 0; + +let incrementCounter = () => {}; -export const startRepetitivePing = () => { +// initializeWakeupPing only execute once in offscreen +export const initializeWakeupPing = () => { if (typeof frameElement === "object" && typeof document === "object" && document) { let counter = 0; let isMutationPending = false; const pingNode = document.createComment("0"); - const incrementCounter = () => { - if (!isMutationPending) { + incrementCounter = () => { + if (startCounter >= 1 && !isMutationPending) { isMutationPending = true; counter = counter > 8 ? 1 : counter + 1; pingNode.data = `${counter}`; @@ -44,10 +56,22 @@ export const startRepetitivePing = () => { } }); mutationObserver.observe(pingNode, { characterData: true }); - incrementCounter(); + // incrementCounter(); + + channelCommand.onmessage = (e) => { + if (e.data === WakeUpCommand.START) { + startCounter++; + if (startCounter === 1) { + incrementCounter(); + } + } else if (e.data === WakeUpCommand.STOP) { + if (startCounter > 0) startCounter--; + } + }; } }; +// initializeWakeupPing only execute once in service worker export const listenWakeupPing = (onWakeupPing: (...args: any) => any) => { chrome.storage.session.onChanged.addListener((obj) => { // 消耗 persistentWakeup @@ -61,3 +85,8 @@ export const listenWakeupPing = (onWakeupPing: (...args: any) => any) => { chrome.storage.session.set({ persistentWakeup: `${e.timeStamp}` }); }; }; + +// wakeupPingCommand only execute in service worker +export const wakeupPingCommand = (command: WakeUpCommand) => { + channelCommand.postMessage(command); +}; From abf8da120bc23ddc94f95f9ab8c327972fee5306 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 25 Apr 2026 09:56:47 +0900 Subject: [PATCH 7/9] Update wakeup-ping.ts --- src/pkg/utils/wakeup-ping.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index 2f9d4e880..03f636ef6 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -21,8 +21,6 @@ const channel = new BroadcastChannel("custom-ping"); // offscreen -> sw const channelCommand = new BroadcastChannel("custom-ping-command"); // sw -> offscreen let startCounter = 0; -let incrementCounter = () => {}; - // initializeWakeupPing only execute once in offscreen export const initializeWakeupPing = () => { if (typeof frameElement === "object" && typeof document === "object" && document) { @@ -31,7 +29,7 @@ export const initializeWakeupPing = () => { const pingNode = document.createComment("0"); - incrementCounter = () => { + const incrementCounter = () => { if (startCounter >= 1 && !isMutationPending) { isMutationPending = true; counter = counter > 8 ? 1 : counter + 1; From 436f58206aa982d5115c28205a38c9dbbaa405ac Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 25 Apr 2026 09:58:31 +0900 Subject: [PATCH 8/9] Update wakeup-ping.ts --- src/pkg/utils/wakeup-ping.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index 03f636ef6..86c42d376 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -32,7 +32,7 @@ export const initializeWakeupPing = () => { const incrementCounter = () => { if (startCounter >= 1 && !isMutationPending) { isMutationPending = true; - counter = counter > 8 ? 1 : counter + 1; + counter = counter & 8 ? 1 : counter + 1; pingNode.data = `${counter}`; } }; From 76abf19e4c4bb52a8b2d2a38ab5dabf4eb376995 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sat, 25 Apr 2026 10:00:46 +0900 Subject: [PATCH 9/9] Update wakeup-ping.ts --- src/pkg/utils/wakeup-ping.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkg/utils/wakeup-ping.ts b/src/pkg/utils/wakeup-ping.ts index 86c42d376..ef97f9bfa 100644 --- a/src/pkg/utils/wakeup-ping.ts +++ b/src/pkg/utils/wakeup-ping.ts @@ -38,7 +38,7 @@ export const initializeWakeupPing = () => { }; const pingTask = async () => { - channel.postMessage({}); + channel.postMessage(true); incrementCounter(); };