feat: Extensive refactoring and modification to support any number of interfaces
This commit is contained in:
@@ -6,7 +6,7 @@ const parseMSToken = (token) => {
|
||||
try {
|
||||
return JSON.parse(atob(token.split(".")[1])).exp;
|
||||
} catch (err) {
|
||||
kissLog(err, "parseMSToken");
|
||||
kissLog("parseMSToken", err);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -131,17 +131,15 @@ const queueMap = new Map();
|
||||
|
||||
/**
|
||||
* 获取批处理实例
|
||||
* @param {*} translator
|
||||
* @returns
|
||||
*/
|
||||
export const getBatchQueue = (args, opts) => {
|
||||
const { translator, from, to } = args;
|
||||
const key = `${translator}_${from}_${to}`;
|
||||
export const getBatchQueue = (args) => {
|
||||
const { from, to, apiSetting } = args;
|
||||
const key = `${apiSetting.apiSlug}_${from}_${to}`;
|
||||
if (queueMap.has(key)) {
|
||||
return queueMap.get(key);
|
||||
}
|
||||
|
||||
const queue = BatchQueue(args, opts);
|
||||
const queue = BatchQueue(args, apiSetting);
|
||||
queueMap.set(key, queue);
|
||||
return queue;
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ function _browser() {
|
||||
try {
|
||||
return require("webextension-polyfill");
|
||||
} catch (err) {
|
||||
// kissLog(err, "browser");
|
||||
// kissLog("browser", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ export const getHttpCache = async (input, init) => {
|
||||
return await parseResponse(res);
|
||||
}
|
||||
} catch (err) {
|
||||
kissLog(err, "get cache");
|
||||
kissLog("get cache", err);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -54,7 +54,12 @@ export const getHttpCache = async (input, init) => {
|
||||
* @param {*} init
|
||||
* @param {*} data
|
||||
*/
|
||||
export const putHttpCache = async (input, init, data) => {
|
||||
export const putHttpCache = async (
|
||||
input,
|
||||
init,
|
||||
data,
|
||||
maxAge = DEFAULT_CACHE_TIMEOUT // todo: 从设置里面读取最大缓存时间
|
||||
) => {
|
||||
try {
|
||||
const req = await newCacheReq(input, init);
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
@@ -62,13 +67,13 @@ export const putHttpCache = async (input, init, data) => {
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Cache-Control": `max-age=${DEFAULT_CACHE_TIMEOUT}`,
|
||||
"Cache-Control": `max-age=${maxAge}`,
|
||||
},
|
||||
});
|
||||
// res.headers.set("Cache-Control", `max-age=${DEFAULT_CACHE_TIMEOUT}`);
|
||||
// res.headers.set("Cache-Control", `max-age=${maxAge}`);
|
||||
await cache.put(req, res);
|
||||
} catch (err) {
|
||||
kissLog(err, "put cache");
|
||||
kissLog("put cache", err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ export const fetchPatcher = async (input, init = {}, opts) => {
|
||||
try {
|
||||
timeout = (await getSettingWithDefault()).httpTimeout;
|
||||
} catch (err) {
|
||||
kissLog(err, "getSettingWithDefault");
|
||||
kissLog("getSettingWithDefault", err);
|
||||
}
|
||||
}
|
||||
if (!timeout) {
|
||||
|
||||
@@ -28,7 +28,7 @@ export const tryClearCaches = async () => {
|
||||
try {
|
||||
caches.delete(CACHE_NAME);
|
||||
} catch (err) {
|
||||
kissLog(err, "clean caches");
|
||||
kissLog("clean caches", err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ export const tryDetectLang = async (
|
||||
try {
|
||||
lang = await langdetectMap[langDetector](q);
|
||||
} catch (err) {
|
||||
kissLog(err, "detect lang remote");
|
||||
kissLog("detect lang remote", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export const tryDetectLang = async (
|
||||
const res = await browser?.i18n?.detectLanguage(q);
|
||||
lang = res?.languages?.[0]?.language;
|
||||
} catch (err) {
|
||||
kissLog(err, "detect lang local");
|
||||
kissLog("detect lang local", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {
|
||||
DEFAULT_INPUT_RULE,
|
||||
DEFAULT_TRANS_APIS,
|
||||
DEFAULT_INPUT_SHORTCUT,
|
||||
OPT_LANGS_LIST,
|
||||
DEFAULT_API_SETTING,
|
||||
} from "../config";
|
||||
import { genEventName, removeEndchar, matchInputStr, sleep } from "./utils";
|
||||
import { stepShortcutRegister } from "./shortcut";
|
||||
@@ -87,7 +87,7 @@ export default function inputTranslate({
|
||||
inputRule: {
|
||||
transOpen,
|
||||
triggerShortcut,
|
||||
translator,
|
||||
apiSlug,
|
||||
fromLang,
|
||||
toLang,
|
||||
triggerCount,
|
||||
@@ -100,7 +100,8 @@ export default function inputTranslate({
|
||||
return;
|
||||
}
|
||||
|
||||
const apiSetting = transApis?.[translator] || DEFAULT_TRANS_APIS[translator];
|
||||
const apiSetting =
|
||||
transApis.find((api) => api.apiSlug === apiSlug) || DEFAULT_API_SETTING;
|
||||
if (triggerShortcut.length === 0) {
|
||||
triggerShortcut = DEFAULT_INPUT_SHORTCUT;
|
||||
triggerCount = 1;
|
||||
@@ -156,7 +157,7 @@ export default function inputTranslate({
|
||||
addLoading(node, loadingId);
|
||||
|
||||
const [trText, isSame] = await apiTranslate({
|
||||
translator,
|
||||
apiSlug,
|
||||
text,
|
||||
fromLang,
|
||||
toLang,
|
||||
@@ -188,7 +189,7 @@ export default function inputTranslate({
|
||||
collapseToEnd(node);
|
||||
}
|
||||
} catch (err) {
|
||||
kissLog(err, "translate input");
|
||||
kissLog("translate input", err);
|
||||
} finally {
|
||||
removeLoading(node, loadingId);
|
||||
}
|
||||
|
||||
136
src/libs/log.js
136
src/libs/log.js
@@ -1,12 +1,126 @@
|
||||
/**
|
||||
* 日志函数
|
||||
* @param {*} msg
|
||||
* @param {*} type
|
||||
*/
|
||||
export const kissLog = (msg, type) => {
|
||||
let prefix = `[KISS-Translator]`;
|
||||
if (type) {
|
||||
prefix += `[${type}]`;
|
||||
}
|
||||
console.log(`${prefix} ${msg}`);
|
||||
// 定义日志级别
|
||||
export const LogLevel = {
|
||||
DEBUG: { value: 0, name: "DEBUG", color: "#6495ED" }, // 宝蓝色
|
||||
INFO: { value: 1, name: "INFO", color: "#4CAF50" }, // 绿色
|
||||
WARN: { value: 2, name: "WARN", color: "#FFC107" }, // 琥珀色
|
||||
ERROR: { value: 3, name: "ERROR", color: "#F44336" }, // 红色
|
||||
SILENT: { value: 4, name: "SILENT" }, // 特殊级别,用于关闭所有日志
|
||||
};
|
||||
|
||||
class Logger {
|
||||
/**
|
||||
* @param {object} [options={}] 配置选项
|
||||
* @param {LogLevel} [options.level=LogLevel.INFO] 要显示的最低日志级别
|
||||
* @param {string} [options.prefix='App'] 日志前缀,用于区分模块
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.config = {
|
||||
level: options.level || LogLevel.INFO,
|
||||
prefix: options.prefix || "KISS-Translator",
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态设置日志级别
|
||||
* @param {LogLevel} level - 新的日志级别
|
||||
*/
|
||||
setLevel(level) {
|
||||
if (level && typeof level.value === "number") {
|
||||
this.config.level = level;
|
||||
console.log(`[${this.config.prefix}] Log level set to ${level.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 核心日志记录方法
|
||||
* @private
|
||||
* @param {LogLevel} level - 当前消息的日志级别
|
||||
* @param {...any} args - 要记录的多个参数,可以是任何类型
|
||||
*/
|
||||
_log(level, ...args) {
|
||||
// 如果当前级别低于配置的最低级别,则不打印
|
||||
if (level.value < this.config.level.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timestamp = new Date().toISOString();
|
||||
const prefixStr = `[${this.config.prefix}]`;
|
||||
const levelStr = `[${level.name}]`;
|
||||
|
||||
// 判断是否在浏览器环境并且浏览器支持 console 样式
|
||||
const isBrowser =
|
||||
typeof window !== "undefined" && typeof window.document !== "undefined";
|
||||
|
||||
if (isBrowser) {
|
||||
// 在浏览器中使用颜色高亮
|
||||
const consoleMethod = this._getConsoleMethod(level);
|
||||
consoleMethod(
|
||||
`%c${timestamp} %c${prefixStr} %c${levelStr}`,
|
||||
"color: gray; font-weight: lighter;", // 时间戳样式
|
||||
"color: #7c57e0; font-weight: bold;", // 前缀样式 (紫色)
|
||||
`color: ${level.color}; font-weight: bold;`, // 日志级别样式
|
||||
...args
|
||||
);
|
||||
} else {
|
||||
// 在 Node.js 或不支持样式的环境中,输出纯文本
|
||||
const consoleMethod = this._getConsoleMethod(level);
|
||||
consoleMethod(timestamp, prefixStr, levelStr, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据日志级别获取对应的 console 方法
|
||||
* @private
|
||||
*/
|
||||
_getConsoleMethod(level) {
|
||||
switch (level) {
|
||||
case LogLevel.ERROR:
|
||||
return console.error;
|
||||
case LogLevel.WARN:
|
||||
return console.warn;
|
||||
case LogLevel.INFO:
|
||||
return console.info;
|
||||
default:
|
||||
return console.log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录 DEBUG 级别的日志
|
||||
* @param {...any} args
|
||||
*/
|
||||
debug(...args) {
|
||||
this._log(LogLevel.DEBUG, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录 INFO 级别的日志
|
||||
* @param {...any} args
|
||||
*/
|
||||
info(...args) {
|
||||
this._log(LogLevel.INFO, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录 WARN 级别的日志
|
||||
* @param {...any} args
|
||||
*/
|
||||
warn(...args) {
|
||||
this._log(LogLevel.WARN, ...args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录 ERROR 级别的日志
|
||||
* @param {...any} args
|
||||
*/
|
||||
error(...args) {
|
||||
this._log(LogLevel.ERROR, ...args);
|
||||
}
|
||||
}
|
||||
|
||||
const isDevelopment =
|
||||
typeof process === "undefined" || process.env.NODE_ENV !== "development";
|
||||
const defaultLevel = isDevelopment ? LogLevel.DEBUG : LogLevel.INFO;
|
||||
|
||||
export const logger = new Logger({ level: defaultLevel });
|
||||
export const kissLog = logger.info.bind(logger);
|
||||
|
||||
@@ -70,7 +70,7 @@ class TaskPool {
|
||||
const res = await fn(args);
|
||||
resolve(res);
|
||||
} catch (err) {
|
||||
kissLog(err, "task");
|
||||
kissLog("task pool", err);
|
||||
if (retry < this.#maxRetry) {
|
||||
setTimeout(() => {
|
||||
this.#pool.unshift({ ...task, retry: retry + 1 }); // unshift 保证重试任务优先
|
||||
|
||||
@@ -2,12 +2,12 @@ import { matchValue, type, isMatch } from "./utils";
|
||||
import {
|
||||
GLOBAL_KEY,
|
||||
REMAIN_KEY,
|
||||
OPT_TRANS_ALL,
|
||||
OPT_STYLE_ALL,
|
||||
OPT_LANGS_FROM,
|
||||
OPT_LANGS_TO,
|
||||
// OPT_TIMING_ALL,
|
||||
GLOBLA_RULE,
|
||||
DEFAULT_API_TYPE,
|
||||
} from "../config";
|
||||
import { loadOrFetchSubRules } from "./subRules";
|
||||
import { getRulesWithDefault, setRules } from "./storage";
|
||||
@@ -50,7 +50,7 @@ export const matchRule = async (
|
||||
rules.splice(-1, 0, ...subRules);
|
||||
}
|
||||
} catch (err) {
|
||||
kissLog(err, "load injectRules");
|
||||
kissLog("load injectRules", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ export const matchRule = async (
|
||||
});
|
||||
|
||||
[
|
||||
"translator",
|
||||
"apiSlug",
|
||||
"fromLang",
|
||||
"toLang",
|
||||
"transOpen",
|
||||
@@ -158,7 +158,7 @@ export const checkRules = (rules) => {
|
||||
parentStyle,
|
||||
injectJs,
|
||||
injectCss,
|
||||
translator,
|
||||
apiSlug,
|
||||
fromLang,
|
||||
toLang,
|
||||
textStyle,
|
||||
@@ -193,7 +193,7 @@ export const checkRules = (rules) => {
|
||||
injectCss: type(injectCss) === "string" ? injectCss : "",
|
||||
bgColor: type(bgColor) === "string" ? bgColor : "",
|
||||
textDiyStyle: type(textDiyStyle) === "string" ? textDiyStyle : "",
|
||||
translator: matchValue([GLOBAL_KEY, ...OPT_TRANS_ALL], translator),
|
||||
apiSlug: apiSlug?.trim() || DEFAULT_API_TYPE,
|
||||
fromLang: matchValue([GLOBAL_KEY, ...fromLangs], fromLang),
|
||||
toLang: matchValue([GLOBAL_KEY, ...toLangs], toLang),
|
||||
textStyle: matchValue([GLOBAL_KEY, ...OPT_STYLE_ALL], textStyle),
|
||||
|
||||
@@ -33,7 +33,7 @@ export class ShadowRootMonitor {
|
||||
try {
|
||||
monitorInstance.callback(shadowRoot);
|
||||
} catch (error) {
|
||||
kissLog(error, "Error in ShadowRootMonitor callback");
|
||||
kissLog("Error in ShadowRootMonitor callback", error);
|
||||
}
|
||||
}
|
||||
return shadowRoot;
|
||||
|
||||
@@ -1,112 +1,106 @@
|
||||
import { isSameSet } from "./utils";
|
||||
|
||||
/**
|
||||
* 键盘快捷键监听
|
||||
* @param {*} fn
|
||||
* @param {*} target
|
||||
* @param {*} timeout
|
||||
* @returns
|
||||
* 键盘快捷键监听器
|
||||
* @param {(pressedKeys: Set<string>, event: KeyboardEvent) => void} onKeyDown - Keydown 回调
|
||||
* @param {(pressedKeys: Set<string>, event: KeyboardEvent) => void} onKeyUp - Keyup 回调
|
||||
* @param {EventTarget} target - 监听的目标元素
|
||||
* @returns {() => void} - 用于注销监听的函数
|
||||
*/
|
||||
export const shortcutListener = (fn, target = document, timeout = 3000) => {
|
||||
const allkeys = new Set();
|
||||
const curkeys = new Set();
|
||||
let timer = null;
|
||||
export const shortcutListener = (
|
||||
onKeyDown = () => {},
|
||||
onKeyUp = () => {},
|
||||
target = document
|
||||
) => {
|
||||
const pressedKeys = new Set();
|
||||
|
||||
const handleKeydown = (e) => {
|
||||
timer && clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
allkeys.clear();
|
||||
curkeys.clear();
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}, timeout);
|
||||
|
||||
if (e.code) {
|
||||
allkeys.add(e.code);
|
||||
curkeys.add(e.code);
|
||||
fn([...curkeys], [...allkeys]);
|
||||
}
|
||||
const handleKeyDown = (e) => {
|
||||
if (pressedKeys.has(e.code)) return;
|
||||
pressedKeys.add(e.code);
|
||||
onKeyDown(new Set(pressedKeys), e);
|
||||
};
|
||||
|
||||
const handleKeyup = (e) => {
|
||||
curkeys.delete(e.code);
|
||||
if (curkeys.size === 0) {
|
||||
fn([...curkeys], [...allkeys]);
|
||||
allkeys.clear();
|
||||
}
|
||||
const handleKeyUp = (e) => {
|
||||
// onKeyUp 应该在 key 从集合中移除前触发,以便判断组合键
|
||||
onKeyUp(new Set(pressedKeys), e);
|
||||
pressedKeys.delete(e.code);
|
||||
};
|
||||
|
||||
target.addEventListener("keydown", handleKeydown, true);
|
||||
target.addEventListener("keyup", handleKeyup, true);
|
||||
target.addEventListener("keydown", handleKeyDown);
|
||||
target.addEventListener("keyup", handleKeyUp);
|
||||
|
||||
return () => {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
target.removeEventListener("keydown", handleKeydown);
|
||||
target.removeEventListener("keyup", handleKeyup);
|
||||
target.removeEventListener("keydown", handleKeyDown);
|
||||
target.removeEventListener("keyup", handleKeyUp);
|
||||
pressedKeys.clear();
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 注册键盘快捷键
|
||||
* @param {*} targetKeys
|
||||
* @param {*} fn
|
||||
* @param {*} target
|
||||
* @returns
|
||||
* @param {string[]} targetKeys - 目标快捷键数组
|
||||
* @param {() => void} fn - 匹配成功后执行的回调
|
||||
* @param {EventTarget} target - 监听目标
|
||||
* @returns {() => void} - 注销函数
|
||||
*/
|
||||
export const shortcutRegister = (targetKeys = [], fn, target = document) => {
|
||||
return shortcutListener((curkeys) => {
|
||||
if (
|
||||
targetKeys.length > 0 &&
|
||||
isSameSet(new Set(targetKeys), new Set(curkeys))
|
||||
) {
|
||||
if (targetKeys.length === 0) return () => {};
|
||||
|
||||
const targetKeySet = new Set(targetKeys);
|
||||
const onKeyDown = (pressedKeys, event) => {
|
||||
if (targetKeySet.size > 0 && isSameSet(targetKeySet, pressedKeys)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
fn();
|
||||
}
|
||||
}, target);
|
||||
};
|
||||
const onKeyUp = () => {};
|
||||
|
||||
return shortcutListener(onKeyDown, onKeyUp, target);
|
||||
};
|
||||
|
||||
/**
|
||||
* 高阶函数:为目标函数增加计次和超时重置功能
|
||||
* @param {() => void} fn - 需要被包装的函数
|
||||
* @param {number} step - 需要触发的次数
|
||||
* @param {number} timeout - 超时毫秒数
|
||||
* @returns {() => void} - 包装后的新函数
|
||||
*/
|
||||
const withStepCounter = (fn, step, timeout) => {
|
||||
let count = 0;
|
||||
let timer = null;
|
||||
|
||||
return () => {
|
||||
timer && clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
count = 0;
|
||||
}, timeout);
|
||||
|
||||
count++;
|
||||
if (count === step) {
|
||||
count = 0;
|
||||
clearTimeout(timer);
|
||||
fn();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 注册连续快捷键
|
||||
* @param {*} targetKeys
|
||||
* @param {*} fn
|
||||
* @param {*} step
|
||||
* @param {*} timeout
|
||||
* @param {*} target
|
||||
* @returns
|
||||
* @param {string[]} targetKeys - 目标快捷键数组
|
||||
* @param {() => void} fn - 成功回调
|
||||
* @param {number} step - 连续触发次数
|
||||
* @param {number} timeout - 每次触发的间隔超时
|
||||
* @param {EventTarget} target - 监听目标
|
||||
* @returns {() => void} - 注销函数
|
||||
*/
|
||||
export const stepShortcutRegister = (
|
||||
targetKeys = [],
|
||||
fn,
|
||||
step = 3,
|
||||
step = 2,
|
||||
timeout = 500,
|
||||
target = document
|
||||
) => {
|
||||
let count = 0;
|
||||
let pre = Date.now();
|
||||
let timer;
|
||||
return shortcutListener((curkeys, allkeys) => {
|
||||
timer && clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
clearTimeout(timer);
|
||||
count = 0;
|
||||
}, timeout);
|
||||
|
||||
if (targetKeys.length > 0 && curkeys.length === 0) {
|
||||
const now = Date.now();
|
||||
if (
|
||||
(count === 0 || now - pre < timeout) &&
|
||||
isSameSet(new Set(targetKeys), new Set(allkeys))
|
||||
) {
|
||||
count++;
|
||||
if (count === step) {
|
||||
count = 0;
|
||||
fn();
|
||||
}
|
||||
} else {
|
||||
count = 0;
|
||||
}
|
||||
pre = now;
|
||||
}
|
||||
}, target);
|
||||
const steppedFn = withStepCounter(fn, step, timeout);
|
||||
return shortcutRegister(targetKeys, steppedFn, target);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
import { isExt, isGm } from "./client";
|
||||
import { browser } from "./browser";
|
||||
import { kissLog } from "./log";
|
||||
import { debounce } from "./utils";
|
||||
|
||||
async function set(key, val) {
|
||||
if (isExt) {
|
||||
@@ -90,7 +91,7 @@ export const getSettingWithDefault = async () => ({
|
||||
...((await getSetting()) || {}),
|
||||
});
|
||||
export const setSetting = (val) => setObj(STOKEY_SETTING, val);
|
||||
export const updateSetting = (obj) => putObj(STOKEY_SETTING, obj);
|
||||
export const putSetting = (obj) => putObj(STOKEY_SETTING, obj);
|
||||
|
||||
/**
|
||||
* 规则列表
|
||||
@@ -122,14 +123,20 @@ export const setSubRules = (url, val) =>
|
||||
export const getFab = () => getObj(STOKEY_FAB);
|
||||
export const getFabWithDefault = async () => (await getFab()) || {};
|
||||
export const setFab = (obj) => setObj(STOKEY_FAB, obj);
|
||||
export const updateFab = (obj) => putObj(STOKEY_FAB, obj);
|
||||
export const putFab = (obj) => putObj(STOKEY_FAB, obj);
|
||||
|
||||
/**
|
||||
* 数据同步
|
||||
*/
|
||||
export const getSync = () => getObj(STOKEY_SYNC);
|
||||
export const getSyncWithDefault = async () => (await getSync()) || DEFAULT_SYNC;
|
||||
export const updateSync = (obj) => putObj(STOKEY_SYNC, obj);
|
||||
export const putSync = (obj) => putObj(STOKEY_SYNC, obj);
|
||||
export const putSyncMeta = async (key) => {
|
||||
const { syncMeta = {} } = await getSyncWithDefault();
|
||||
syncMeta[key] = { ...(syncMeta[key] || {}), updateAt: Date.now() };
|
||||
await putSync({ syncMeta });
|
||||
};
|
||||
export const debounceSyncMeta = debounce(putSyncMeta, 300);
|
||||
|
||||
/**
|
||||
* ms auth
|
||||
@@ -156,6 +163,6 @@ export const tryInitDefaultData = async () => {
|
||||
BUILTIN_RULES
|
||||
);
|
||||
} catch (err) {
|
||||
kissLog(err, "init default");
|
||||
kissLog("init default", err);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { GLOBAL_KEY } from "../config";
|
||||
import {
|
||||
getSyncWithDefault,
|
||||
updateSync,
|
||||
putSync,
|
||||
setSubRules,
|
||||
getSubRules,
|
||||
} from "./storage";
|
||||
@@ -17,7 +17,7 @@ import { kissLog } from "./log";
|
||||
const updateSyncDataCache = async (url) => {
|
||||
const { dataCaches = {} } = await getSyncWithDefault();
|
||||
dataCaches[url] = Date.now();
|
||||
await updateSync({ dataCaches });
|
||||
await putSync({ dataCaches });
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -47,7 +47,7 @@ export const syncAllSubRules = async (subrulesList) => {
|
||||
await syncSubRules(subrules.url);
|
||||
await updateSyncDataCache(subrules.url);
|
||||
} catch (err) {
|
||||
kissLog(err, `sync subrule error: ${subrules.url}`);
|
||||
kissLog(`sync subrule error: ${subrules.url}`, err);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -65,10 +65,10 @@ export const trySyncAllSubRules = async ({ subrulesList }) => {
|
||||
if (now - subRulesSyncAt > interval) {
|
||||
// 同步订阅规则
|
||||
await syncAllSubRules(subrulesList);
|
||||
await updateSync({ subRulesSyncAt: now });
|
||||
await putSync({ subRulesSyncAt: now });
|
||||
}
|
||||
} catch (err) {
|
||||
kissLog(err, "try sync all subrules");
|
||||
kissLog("try sync all subrules", err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
} from "../config";
|
||||
import {
|
||||
getSyncWithDefault,
|
||||
updateSync,
|
||||
putSync,
|
||||
getSettingWithDefault,
|
||||
getRulesWithDefault,
|
||||
getWordsWithDefault,
|
||||
@@ -61,7 +61,7 @@ const syncByWorker = async (data, { syncUrl, syncKey }) => {
|
||||
return await apiSyncData(`${syncUrl}/sync`, syncKey, data);
|
||||
};
|
||||
|
||||
const syncData = async (key, valueFn) => {
|
||||
export const syncData = async (key, value) => {
|
||||
const {
|
||||
syncType,
|
||||
syncUrl,
|
||||
@@ -70,13 +70,14 @@ const syncData = async (key, valueFn) => {
|
||||
syncMeta = {},
|
||||
} = await getSyncWithDefault();
|
||||
if (!syncUrl || !syncKey || (syncType === OPT_SYNCTYPE_WEBDAV && !syncUser)) {
|
||||
return;
|
||||
throw new Error("sync args err");
|
||||
}
|
||||
|
||||
let { updateAt = 0, syncAt = 0 } = syncMeta[key] || {};
|
||||
syncAt === 0 && (updateAt = 0);
|
||||
if (syncAt === 0) {
|
||||
updateAt = 0; // 没有同步过,更新时间置零
|
||||
}
|
||||
|
||||
const value = await valueFn();
|
||||
const data = {
|
||||
key,
|
||||
value: JSON.stringify(value),
|
||||
@@ -93,13 +94,20 @@ const syncData = async (key, valueFn) => {
|
||||
? await syncByWebdav(data, args)
|
||||
: await syncByWorker(data, args);
|
||||
|
||||
if (!res) {
|
||||
throw new Error("sync data got err", key);
|
||||
}
|
||||
|
||||
const newVal = JSON.parse(res.value);
|
||||
const isNew = res.updateAt > updateAt;
|
||||
|
||||
syncMeta[key] = {
|
||||
updateAt: res.updateAt,
|
||||
syncAt: Date.now(),
|
||||
};
|
||||
await updateSync({ syncMeta });
|
||||
await putSync({ syncMeta });
|
||||
|
||||
return { value: JSON.parse(res.value), isNew: res.updateAt > updateAt };
|
||||
return { value: newVal, isNew };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -107,7 +115,8 @@ const syncData = async (key, valueFn) => {
|
||||
* @returns
|
||||
*/
|
||||
const syncSetting = async () => {
|
||||
const res = await syncData(KV_SETTING_KEY, getSettingWithDefault);
|
||||
const value = await getSettingWithDefault();
|
||||
const res = await syncData(KV_SETTING_KEY, value);
|
||||
if (res?.isNew) {
|
||||
await setSetting(res.value);
|
||||
}
|
||||
@@ -117,7 +126,7 @@ export const trySyncSetting = async () => {
|
||||
try {
|
||||
await syncSetting();
|
||||
} catch (err) {
|
||||
kissLog(err, "sync setting");
|
||||
kissLog("sync setting", err.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -126,7 +135,8 @@ export const trySyncSetting = async () => {
|
||||
* @returns
|
||||
*/
|
||||
const syncRules = async () => {
|
||||
const res = await syncData(KV_RULES_KEY, getRulesWithDefault);
|
||||
const value = await getRulesWithDefault();
|
||||
const res = await syncData(KV_RULES_KEY, value);
|
||||
if (res?.isNew) {
|
||||
await setRules(res.value);
|
||||
}
|
||||
@@ -136,7 +146,7 @@ export const trySyncRules = async () => {
|
||||
try {
|
||||
await syncRules();
|
||||
} catch (err) {
|
||||
kissLog(err, "sync user rules");
|
||||
kissLog("sync user rules", err.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -145,7 +155,8 @@ export const trySyncRules = async () => {
|
||||
* @returns
|
||||
*/
|
||||
const syncWords = async () => {
|
||||
const res = await syncData(KV_WORDS_KEY, getWordsWithDefault);
|
||||
const value = await getWordsWithDefault();
|
||||
const res = await syncData(KV_WORDS_KEY, value);
|
||||
if (res?.isNew) {
|
||||
await setWords(res.value);
|
||||
}
|
||||
@@ -155,7 +166,7 @@ export const trySyncWords = async () => {
|
||||
try {
|
||||
await syncWords();
|
||||
} catch (err) {
|
||||
kissLog(err, "sync fav words");
|
||||
kissLog("sync fav words", err.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ import {
|
||||
OPT_STYLE_FUZZY,
|
||||
GLOBLA_RULE,
|
||||
DEFAULT_SETTING,
|
||||
DEFAULT_TRANS_APIS,
|
||||
DEFAULT__MOUSEHOVER_KEY,
|
||||
DEFAULT_MOUSEHOVER_KEY,
|
||||
OPT_STYLE_NONE,
|
||||
DEFAULT_API_SETTING,
|
||||
} from "../config";
|
||||
import interpreter from "./interpreter";
|
||||
import { ShadowRootMonitor } from "./shadowroot";
|
||||
@@ -356,7 +356,7 @@ export class Translator {
|
||||
this.#startObserveShadowRoot(shadowRoot);
|
||||
});
|
||||
} catch (err) {
|
||||
kissLog(err, "findAllShadowRoots");
|
||||
kissLog("findAllShadowRoots", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,7 +419,7 @@ export class Translator {
|
||||
termPatterns.push(`(${key})`);
|
||||
this.#termValues.push(value);
|
||||
} catch (err) {
|
||||
kissLog(err, `Invalid RegExp for term: "${key}"`);
|
||||
kissLog(`Invalid RegExp for term: "${key}"`, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -556,7 +556,7 @@ export class Translator {
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
kissLog(err, "无法访问某个 shadowRoot");
|
||||
kissLog("无法访问某个 shadowRoot", err);
|
||||
}
|
||||
// const end = performance.now();
|
||||
// const duration = end - start;
|
||||
@@ -839,7 +839,7 @@ export class Translator {
|
||||
nodes,
|
||||
});
|
||||
} catch (err) {
|
||||
kissLog(err, "transStartHook");
|
||||
kissLog("transStartHook", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -913,14 +913,14 @@ export class Translator {
|
||||
innerNode: inner,
|
||||
});
|
||||
} catch (err) {
|
||||
kissLog(err, "transEndHook");
|
||||
kissLog("transEndHook", err);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// inner.textContent = `[失败]...`;
|
||||
// todo: 失败重试按钮
|
||||
wrapper.remove();
|
||||
kissLog(err, "translateNodeGroup");
|
||||
kissLog("translateNodeGroup", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1037,16 +1037,13 @@ export class Translator {
|
||||
|
||||
// 发起翻译请求
|
||||
#translateFetch(text) {
|
||||
const { translator, fromLang, toLang } = this.#rule;
|
||||
// const apiSetting = this.#setting.transApis[translator];
|
||||
const apiSetting = {
|
||||
...DEFAULT_TRANS_APIS[translator],
|
||||
...(this.#setting.transApis[translator] || {}),
|
||||
};
|
||||
const { apiSlug, fromLang, toLang } = this.#rule;
|
||||
const apiSetting =
|
||||
this.#setting.transApis.find((api) => api.apiSlug === apiSlug) ||
|
||||
DEFAULT_API_SETTING;
|
||||
|
||||
return apiTranslate({
|
||||
text,
|
||||
translator,
|
||||
fromLang,
|
||||
toLang,
|
||||
apiSetting,
|
||||
@@ -1150,11 +1147,11 @@ export class Translator {
|
||||
return;
|
||||
}
|
||||
|
||||
const { translator, fromLang, toLang, hasRichText, textStyle, transOnly } =
|
||||
const { apiSlug, fromLang, toLang, hasRichText, textStyle, transOnly } =
|
||||
this.#rule;
|
||||
|
||||
const needsRefresh =
|
||||
appliedRule.translator !== translator ||
|
||||
appliedRule.apiSlug !== apiSlug ||
|
||||
appliedRule.fromLang !== fromLang ||
|
||||
appliedRule.toLang !== toLang ||
|
||||
appliedRule.hasRichText !== hasRichText;
|
||||
@@ -1162,7 +1159,7 @@ export class Translator {
|
||||
// 需要重新翻译
|
||||
if (needsRefresh) {
|
||||
Object.assign(appliedRule, {
|
||||
translator,
|
||||
apiSlug,
|
||||
fromLang,
|
||||
toLang,
|
||||
hasRichText,
|
||||
@@ -1207,7 +1204,7 @@ export class Translator {
|
||||
document.addEventListener("mousemove", this.#boundMouseMoveHandler);
|
||||
let { mouseHoverKey } = this.#setting.mouseHoverSetting;
|
||||
if (mouseHoverKey.length === 0) {
|
||||
mouseHoverKey = DEFAULT__MOUSEHOVER_KEY;
|
||||
mouseHoverKey = DEFAULT_MOUSEHOVER_KEY;
|
||||
}
|
||||
this.#removeKeydownHandler = shortcutRegister(
|
||||
mouseHoverKey,
|
||||
@@ -1273,7 +1270,7 @@ export class Translator {
|
||||
document.title = trText || title;
|
||||
})
|
||||
.catch((err) => {
|
||||
kissLog(err, "tanslate title");
|
||||
kissLog("tanslate title", err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user