Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@dnd-kit/modifiers": "^9.0.0",
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"cron": "^3.2.1",
"cron": "^4.4.0",
"crypto-js": "^4.2.0",
"dayjs": "^1.11.13",
"dexie": "^4.0.10",
Expand Down
27 changes: 14 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/app/service/content/gm_api/gm_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ export default class GMApi extends GM_Base {
parentNodeId = id;
} else {
parentNodeId = null;
attrs = tagName as Record<string, string | number | boolean>;
attrs = (tagName || {}) as Record<string, string | number | boolean>;
tagName = parentNode as string;
}
if (typeof tagName !== "string") throw new Error("The parameter 'tagName' of GM_addElement shall be a string.");
Expand Down
5 changes: 4 additions & 1 deletion src/app/service/offscreen/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
SCRIPT_TYPE_CRONTAB,
SCRIPT_TYPE_NORMAL,
} from "@App/app/repo/scripts";
import { disableScript, enableScript, runScript, stopScript } from "../sandbox/client";
import { disableScript, enableScript, runScript, setSandboxLanguage, stopScript } from "../sandbox/client";
import { type Group } from "@Packages/message/server";
import type { MessageSend } from "@Packages/message/types";
import type { TDeleteScript, TInstallScript, TEnableScript } from "../queue";
Expand Down Expand Up @@ -40,6 +40,9 @@ export class ScriptService {
}

async init() {
this.messageQueue.subscribe<string>("setSandboxLanguage", async (lang) => {
setSandboxLanguage(this.windowMessage, lang);
});
this.messageQueue.subscribe<TEnableScript[]>("enableScripts", async (data) => {
for (const { uuid, enable } of data) {
const script = await this.scriptClient.info(uuid);
Expand Down
4 changes: 4 additions & 0 deletions src/app/service/sandbox/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import { type ScriptRunResource } from "@App/app/repo/scripts";
import { sendMessage } from "@Packages/message/client";
import { type WindowMessage } from "@Packages/message/window_message";

export function setSandboxLanguage(msg: WindowMessage, lang: string) {
return sendMessage(msg, "sandbox/setSandboxLanguage", lang);
}

export function enableScript(msg: WindowMessage, data: ScriptRunResource) {
return sendMessage(msg, "sandbox/enableScript", data);
}
Expand Down
98 changes: 41 additions & 57 deletions src/app/service/sandbox/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ import { proxyUpdateRunStatus } from "../offscreen/client";
import { BgExecScriptWarp } from "../content/exec_warp";
import type ExecScript from "../content/exec_script";
import type { ValueUpdateDataEncoded } from "../content/types";
import { getStorageName, getMetadataStr, getUserConfigStr } from "@App/pkg/utils/utils";
import { getStorageName, getMetadataStr, getUserConfigStr, getISOWeek } from "@App/pkg/utils/utils";
import type { EmitEventRequest, ScriptLoadInfo } from "../service_worker/types";
import { CATRetryError } from "../content/exec_warp";
import { parseUserConfig } from "@App/pkg/utils/yaml";
import { decodeRValue } from "@App/pkg/utils/message_value";
import { extraCronExpr } from "@App/pkg/utils/cron";
import { changeLanguage, initLanguage, t } from "@App/locales/locales";

const utime_1min = 60 * 1000;
const utime_1hr = 60 * 60 * 1000;
const utime_1day = 24 * 60 * 60 * 1000;

export class Runtime {
cronJob: Map<string, Array<CronJob>> = new Map();
Expand Down Expand Up @@ -181,30 +187,17 @@ export class Runtime {
crontabScript(script: ScriptLoadInfo) {
// 执行定时脚本 运行表达式
if (!script.metadata.crontab) {
throw new Error(script.name + " - 错误的crontab表达式");
throw new Error(script.name + " - " + t("cron_invalid_expr"));
}
// 如果有nextruntime,则加入重试队列
this.joinRetryList(script);
this.crontabSripts.push(script);
let flag = false;
const cronJobList: Array<CronJob> = [];
script.metadata.crontab.forEach((val) => {
let oncePos = 0;
let crontab = val;
if (crontab.includes("once")) {
const vals = crontab.split(" ");
vals.forEach((item, index) => {
if (item === "once") {
oncePos = index;
}
});
if (vals.length === 5) {
oncePos += 1;
}
crontab = crontab.replace(/once/g, "*");
}
const { cronExpr, oncePos } = extraCronExpr(val);
try {
const cron = new CronJob(crontab, this.crontabExec(script, oncePos));
const cron = new CronJob(cronExpr, this.crontabExec(script, oncePos));
cron.start();
cronJobList.push(cron);
} catch (e) {
Expand All @@ -231,56 +224,41 @@ export class Runtime {
}

crontabExec(script: ScriptLoadInfo, oncePos: number) {
if (oncePos) {
if (oncePos >= 1) {
return () => {
// 没有最后一次执行时间表示之前都没执行过,直接执行
if (!script.lastruntime) {
this.execScript(script);
return;
}
const now = new Date();
const last = new Date(script.lastruntime);
let flag = false;
// 根据once所在的位置去判断执行
switch (oncePos) {
case 1: // 每分钟
flag = last.getMinutes() !== now.getMinutes();
break;
case 2: // 每小时
flag = last.getHours() !== now.getHours();
break;
case 3: // 每天
flag = last.getDay() !== now.getDay();
break;
case 4: // 每月
flag = last.getMonth() !== now.getMonth();
break;
case 5: // 每周
flag = this.getWeek(last) !== this.getWeek(now);
break;
default:
}
if (flag) {
this.execScript(script);
if (script.lastruntime) {
const now = new Date();
const last = new Date(script.lastruntime);
// 根据once所在的位置去判断执行
const timeDiff = now.getTime() - last.getTime();
switch (oncePos) {
case 1: // 每分钟
if (timeDiff < 2 * utime_1min && last.getMinutes() === now.getMinutes()) return;
break;
case 2: // 每小时
if (timeDiff < 2 * utime_1hr && last.getHours() === now.getHours()) return;
break;
case 3: // 每天
if (timeDiff < 2 * utime_1day && last.getDay() === now.getDay()) return;
break;
case 4: // 每月
if (timeDiff < 62 * utime_1day && last.getMonth() === now.getMonth()) return;
break;
case 5: // 每周
if (timeDiff < 14 * utime_1day && getISOWeek(last) === getISOWeek(now)) return;
break;
default:
}
}
this.execScript(script);
};
}
return () => {
this.execScript(script);
};
}

// 获取本周是第几周
getWeek(date: Date) {
const nowDate = new Date(date);
const firstDay = new Date(date);
firstDay.setMonth(0); // 设置1月
firstDay.setDate(1); // 设置1号
const diffDays = Math.ceil((nowDate.getTime() - firstDay.getTime()) / (24 * 60 * 60 * 1000));
const week = Math.ceil(diffDays / 7);
return week === 0 ? 1 : week;
}

// 停止计时器
stopCronJob(uuid: string) {
const list = this.cronJob.get(uuid);
Expand Down Expand Up @@ -350,6 +328,10 @@ export class Runtime {
}
}

setSandboxLanguage(lang: string) {
changeLanguage(lang);
}

init() {
this.api.on("enableScript", this.enableScript.bind(this));
this.api.on("disableScript", this.disableScript.bind(this));
Expand All @@ -358,5 +340,7 @@ export class Runtime {

this.api.on("runtime/valueUpdate", this.valueUpdate.bind(this));
this.api.on("runtime/emitEvent", this.emitEvent.bind(this));
this.api.on("setSandboxLanguage", this.setSandboxLanguage.bind(this));
initLanguage();
}
}
6 changes: 6 additions & 0 deletions src/app/service/service_worker/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,12 @@ export class RuntimeService {
this.mq.publish<TEnableScript[]>("enableScripts", res);
}
});
this.systemConfig.getLanguage().then((lng: string) => {
this.mq.publish("setSandboxLanguage", lng);
});
this.systemConfig.addListener("language", (lng) => {
this.mq.publish("setSandboxLanguage", lng);
});
});

// 监听脚本值变更
Expand Down
8 changes: 8 additions & 0 deletions src/locales/de-DE/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@
"script_has_full_access_to": "Skript erhält vollständigen Zugriff auf die folgenden Adressen",
"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.",
"cron_oncetype": {
"minute": "{{next}} (jede Minute ausgeführt)",
"hour": "{{next}} (jede Stunde ausgeführt)",
"day": "{{next}} (jeden Tag ausgeführt)",
"month": "{{next}} (jeden Monat ausgeführt)",
"week": "{{next}} (jede Woche ausgeführt)"
},
"cron_invalid_expr": "Ungültiger Cron-Ausdruck",
"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_expr": "Geplante Aufgaben-Ausdruck",
"scheduled_script_description_description_next": "Letzte Ausführungszeit:",
Expand Down
8 changes: 8 additions & 0 deletions src/locales/en-US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@
"script_has_full_access_to": "Script will have full access to the following URLs",
"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.",
"cron_oncetype": {
"minute": "{{next}} (runs every minute)",
"hour": "{{next}} (runs every hour)",
"day": "{{next}} (runs every day)",
"month": "{{next}} (runs every month)",
"week": "{{next}} (runs every week)"
},
"cron_invalid_expr": "Invalid cron expression",
"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_expr": "Scheduled task expression:",
"scheduled_script_description_description_next": "Most recent run time:",
Expand Down
8 changes: 8 additions & 0 deletions src/locales/ja-JP/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@
"script_has_full_access_to": "スクリプトは以下のアドレスへの完全なアクセス権限を取得します",
"script_requires": "スクリプトは以下の外部リソースを参照しています",
"cookie_warning": "注意:このスクリプトはCookieの操作権限をリクエストします。これは危険な権限ですので、スクリプトの安全性を確認してください。",
"cron_oncetype": {
"minute": "{{next}}(毎分実行)",
"hour": "{{next}}(毎時間実行)",
"day": "{{next}}(毎日実行)",
"month": "{{next}}(毎月実行)",
"week": "{{next}}(毎週実行)"
},
"cron_invalid_expr": "不正な cron 式です",
"scheduled_script_description_title": "これはスケジュールスクリプトです。有効にすると特定の時間に自動実行され、手動操作も可能です。",
"scheduled_script_description_description_expr": "スケジュールタスク表現:",
"scheduled_script_description_description_next": "最近の実行時間:",
Expand Down
15 changes: 10 additions & 5 deletions src/locales/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@ export const initLocalesPromise = new Promise<string>((resolve) => {
initLocalesResolve = resolve;
});

export function initLocales(systemConfig: SystemConfig) {
const uiLanguage = chrome.i18n.getUILanguage();
const defaultLanguage = globalThis.localStorage ? localStorage["language"] || uiLanguage : uiLanguage;
export function initLanguage(lng: string = "en-US"): void {
i18n.use(initReactI18next).init({
fallbackLng: "en-US",
lng: defaultLanguage, // 优先使用localStorage中的语言设置
lng: lng, // 优先使用localStorage中的语言设置
interpolation: {
escapeValue: false, // react already safes from xss => https://www.i18next.com/translation-function/interpolation#unescape
},
Expand All @@ -59,9 +57,16 @@ export function initLocales(systemConfig: SystemConfig) {
});

// 先根据默认语言设置路径
if (!defaultLanguage.startsWith("zh-")) {
if (!lng.startsWith("zh-")) {
localePath = "/en";
}
}

export function initLocales(systemConfig: SystemConfig) {
const uiLanguage = chrome.i18n.getUILanguage();
const defaultLanguage = globalThis.localStorage ? localStorage["language"] || uiLanguage : uiLanguage;

initLanguage(defaultLanguage);

const changeLanguageCallback = (lng: string) => {
if (!lng.startsWith("zh-")) {
Expand Down
8 changes: 8 additions & 0 deletions src/locales/ru-RU/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@
"script_has_full_access_to": "Скрипт получит полный доступ к следующим адресам",
"script_requires": "Скрипт ссылается на следующие внешние ресурсы",
"cookie_warning": "Обратите внимание, что этот скрипт запрашивает разрешения на операции с Cookie. Это опасное разрешение, пожалуйста, убедитесь в безопасности скрипта.",
"cron_oncetype": {
"minute": "{{next}} (выполняется каждую минуту)",
"hour": "{{next}} (выполняется каждый час)",
"day": "{{next}} (выполняется каждый день)",
"month": "{{next}} (выполняется каждый месяц)",
"week": "{{next}} (выполняется каждую неделю)"
},
"cron_invalid_expr": "Неверное выражение cron",
"scheduled_script_description_title": "Это запланированный скрипт. После включения он будет автоматически выполняться в определенное время и может управляться вручную с панели.",
"scheduled_script_description_description_expr": "Выражение планировщика",
"scheduled_script_description_description_next": "Последнее время выполнения:",
Expand Down
8 changes: 8 additions & 0 deletions src/locales/vi-VN/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@
"script_has_full_access_to": "Script sẽ có toàn quyền truy cập vào các url sau",
"script_requires": "Script yêu cầu các tài nguyên bên ngoài sau",
"cookie_warning": "Xin lưu ý, script này yêu cầu quyền truy cập cookie, đây là một quyền nguy hiểm. Vui lòng xác minh tính bảo mật của script.",
"cron_oncetype": {
"minute": "{{next}} (chạy mỗi phút)",
"hour": "{{next}} (chạy mỗi giờ)",
"day": "{{next}} (chạy mỗi ngày)",
"month": "{{next}} (chạy mỗi tháng)",
"week": "{{next}} (chạy mỗi tuần)"
},
"cron_invalid_expr": "Biểu thức cron không hợp lệ",
"scheduled_script_description_title": "Đây là script hẹn giờ, sẽ tự động chạy vào một thời điểm cụ thể sau khi được bật và có thể được điều khiển thủ công trong bảng điều khiển.",
"scheduled_script_description_description_expr": "Biểu thức tác vụ hẹn giờ:",
"scheduled_script_description_description_next": "Thời gian chạy gần nhất:",
Expand Down
Loading
Loading