Compare commits

..

4 Commits

Author SHA1 Message Date
Gabe Yuan
c57a0a11fa v1.7.0 2023-09-11 23:21:15 +08:00
Gabe Yuan
fa244b2097 subrules sync time 2023-09-11 22:53:04 +08:00
Gabe Yuan
79612f8a1b subrules sync time 2023-09-11 17:56:31 +08:00
Gabe Yuan
2bf79dbc51 rootSlector -> rootSelector 2023-09-11 16:12:37 +08:00
13 changed files with 96 additions and 34 deletions

2
.env
View File

@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
REACT_APP_NAME=KISS Translator REACT_APP_NAME=KISS Translator
REACT_APP_NAME_CN=简约翻译 REACT_APP_NAME_CN=简约翻译
REACT_APP_VERSION=1.6.12 REACT_APP_VERSION=1.7.0
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator

View File

@@ -1,7 +1,7 @@
{ {
"name": "kiss-translator", "name": "kiss-translator",
"description": "A minimalist bilingual translation Extension & Greasemonkey Script", "description": "A minimalist bilingual translation Extension & Greasemonkey Script",
"version": "1.6.12", "version": "1.7.0",
"author": "Gabe<yugang2002@gmail.com>", "author": "Gabe<yugang2002@gmail.com>",
"private": true, "private": true,
"dependencies": { "dependencies": {

View File

@@ -2,7 +2,7 @@
"manifest_version": 2, "manifest_version": 2,
"name": "__MSG_app_name__", "name": "__MSG_app_name__",
"description": "__MSG_app_description__", "description": "__MSG_app_description__",
"version": "1.6.12", "version": "1.7.0",
"default_locale": "en", "default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>", "author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator", "homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "__MSG_app_name__", "name": "__MSG_app_name__",
"description": "__MSG_app_description__", "description": "__MSG_app_description__",
"version": "1.6.12", "version": "1.7.0",
"default_locale": "en", "default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>", "author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator", "homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -285,4 +285,5 @@ export const DEFAULT_SYNC = {
rulesUpdateAt: 0, rulesUpdateAt: 0,
rulesSyncAt: 0, rulesSyncAt: 0,
subRulesSyncAt: 0, // 订阅规则同步时间 subRulesSyncAt: 0, // 订阅规则同步时间
dataCaches: {}, // 缓存同步时间
}; };

View File

@@ -31,6 +31,7 @@ export function useStorage(key, defaultVal = null) {
if (val) { if (val) {
setData(val); setData(val);
} else if (defaultVal) { } else if (defaultVal) {
setData(defaultVal);
await storage.setObj(key, defaultVal); await storage.setObj(key, defaultVal);
} }
}, [key, defaultVal]); }, [key, defaultVal]);

View File

@@ -48,7 +48,7 @@ export function useSubRules() {
const addSub = useCallback( const addSub = useCallback(
async (url) => { async (url) => {
const subrulesList = [...list]; const subrulesList = [...list];
subrulesList.push({ url, selected: false, syncAt: Date.now() }); subrulesList.push({ url, selected: false });
await updateSetting({ subrulesList }); await updateSetting({ subrulesList });
}, },
[list, updateSetting] [list, updateSetting]

View File

@@ -1,3 +1,4 @@
import { useCallback } from "react";
import { STOKEY_SYNC, DEFAULT_SYNC } from "../config"; import { STOKEY_SYNC, DEFAULT_SYNC } from "../config";
import { useStorage } from "./Storage"; import { useStorage } from "./Storage";
@@ -6,6 +7,40 @@ import { useStorage } from "./Storage";
* @returns * @returns
*/ */
export function useSync() { export function useSync() {
const { data, update } = useStorage(STOKEY_SYNC, DEFAULT_SYNC); const { data, update, reload } = useStorage(STOKEY_SYNC, DEFAULT_SYNC);
return { sync: data, updateSync: update }; return { sync: data, updateSync: update, reloadSync: reload };
}
/**
* caches sync hook
* @param {*} url
* @returns
*/
export function useSyncCaches() {
const { sync, updateSync, reloadSync } = useSync();
const updateDataCache = useCallback(
async (url) => {
const dataCaches = sync.dataCaches || {};
dataCaches[url] = Date.now();
await updateSync({ dataCaches });
},
[sync, updateSync]
);
const deleteDataCache = useCallback(
async (url) => {
const dataCaches = sync.dataCaches || {};
delete dataCaches[url];
await updateSync({ dataCaches });
},
[sync, updateSync]
);
return {
dataCaches: sync.dataCaches || {},
updateDataCache,
deleteDataCache,
reloadSync,
};
} }

View File

@@ -49,9 +49,8 @@ export const matchRule = async (
mixRule[key] = val; mixRule[key] = val;
}); });
const subRules = (await loadOrFetchSubRules(selectedSub.url)).map( let subRules = await loadOrFetchSubRules(selectedSub.url);
(item) => ({ ...item, ...mixRule }) subRules = subRules.map((item) => ({ ...item, ...mixRule }));
);
rules.splice(-1, 0, ...subRules); rules.splice(-1, 0, ...subRules);
} }
} catch (err) { } catch (err) {

View File

@@ -10,6 +10,16 @@ import { apiFetch } from "../apis";
import { checkRules } from "./rules"; import { checkRules } from "./rules";
import { isAllchar } from "./utils"; import { isAllchar } from "./utils";
/**
* 更新缓存同步时间
* @param {*} url
*/
const updateSyncDataCache = async (url) => {
const { dataCaches = {} } = await getSyncWithDefault();
dataCaches[url] = Date.now();
await updateSync({ dataCaches });
};
/** /**
* 同步订阅规则 * 同步订阅规则
* @param {*} url * @param {*} url
@@ -35,6 +45,7 @@ export const syncAllSubRules = async (subrulesList, isBg = false) => {
for (let subrules of subrulesList) { for (let subrules of subrulesList) {
try { try {
await syncSubRules(subrules.url, isBg); await syncSubRules(subrules.url, isBg);
await updateSyncDataCache(subrules.url);
} catch (err) { } catch (err) {
console.log(`[sync subrule error]: ${subrules.url}`, err); console.log(`[sync subrule error]: ${subrules.url}`, err);
} }
@@ -70,9 +81,10 @@ export const trySyncAllSubRules = async ({ subrulesList }, isBg = false) => {
* @returns * @returns
*/ */
export const loadOrFetchSubRules = async (url) => { export const loadOrFetchSubRules = async (url) => {
const rules = await getSubRules(url); let rules = await getSubRules(url);
if (rules?.length) { if (!rules || rules.length === 0) {
return rules; rules = await syncSubRules(url);
await updateSyncDataCache(url);
} }
return syncSubRules(url); return rules || [];
}; };

View File

@@ -12,26 +12,26 @@ const FIXER_FONTSIZE = "fontSize";
* 需要修复的站点列表 * 需要修复的站点列表
* - pattern 匹配网址 * - pattern 匹配网址
* - selector 需要修复的选择器 * - selector 需要修复的选择器
* - rootSlector 需要监听的选择器,可留空 * - rootSelector 需要监听的选择器,可留空
* - fixer 修复函数,可针对不同网址,选用不同修复函数 * - fixer 修复函数,可针对不同网址,选用不同修复函数
*/ */
const DEFAULT_SITES = [ const DEFAULT_SITES = [
{ {
pattern: "www.phoronix.com", pattern: "www.phoronix.com",
selector: ".content", selector: ".content",
rootSlector: "", rootSelector: "",
fixer: FIXER_BR, fixer: FIXER_BR,
}, },
{ {
pattern: "t.me/s/", pattern: "t.me/s/",
selector: ".tgme_widget_message_text", selector: ".tgme_widget_message_text",
rootSlector: ".tgme_channel_history", rootSelector: ".tgme_channel_history",
fixer: FIXER_BR, fixer: FIXER_BR,
}, },
{ {
pattern: "baidu.com", pattern: "baidu.com",
selector: "html", selector: "html",
rootSlector: "", rootSelector: "",
fixer: FIXER_FONTSIZE, fixer: FIXER_FONTSIZE,
}, },
]; ];
@@ -114,9 +114,9 @@ const fixerMap = {
* 查找、监听节点,并执行修复函数 * 查找、监听节点,并执行修复函数
* @param {*} selector * @param {*} selector
* @param {*} fixer * @param {*} fixer
* @param {*} rootSlector * @param {*} rootSelector
*/ */
function run(selector, fixer, rootSlector) { function run(selector, fixer, rootSelector) {
var mutaObserver = new MutationObserver(function (mutations) { var mutaObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) { mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (addNode) { mutation.addedNodes.forEach(function (addNode) {
@@ -126,8 +126,8 @@ function run(selector, fixer, rootSlector) {
}); });
var rootNodes = [document]; var rootNodes = [document];
if (rootSlector) { if (rootSelector) {
rootNodes = document.querySelectorAll(rootSlector); rootNodes = document.querySelectorAll(rootSelector);
} }
rootNodes.forEach(function (rootNode) { rootNodes.forEach(function (rootNode) {
@@ -181,7 +181,7 @@ export async function webfix(href, { injectWebfix }) {
var site = sites[i]; var site = sites[i];
if (isMatch(href, site.pattern)) { if (isMatch(href, site.pattern)) {
if (fixerMap[site.fixer]) { if (fixerMap[site.fixer]) {
run(site.selector, fixerMap[site.fixer], site.rootSlector); run(site.selector, fixerMap[site.fixer], site.rootSelector);
} }
break; break;
} }

View File

@@ -48,6 +48,7 @@ import { delSubRules, getSyncWithDefault } from "../../libs/storage";
import OwSubRule from "./OwSubRule"; import OwSubRule from "./OwSubRule";
import ClearAllIcon from "@mui/icons-material/ClearAll"; import ClearAllIcon from "@mui/icons-material/ClearAll";
import HelpButton from "./HelpButton"; import HelpButton from "./HelpButton";
import { useSyncCaches } from "../../hooks/Sync";
function RuleFields({ rule, rules, setShow, setKeyword }) { function RuleFields({ rule, rules, setShow, setKeyword }) {
const initFormValues = rule || { const initFormValues = rule || {
@@ -624,8 +625,9 @@ function SubRulesItem({
syncAt, syncAt,
selectedUrl, selectedUrl,
delSub, delSub,
updateSub,
setSelectedRules, setSelectedRules,
updateDataCache,
deleteDataCache,
}) { }) {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -633,6 +635,7 @@ function SubRulesItem({
try { try {
await delSub(url); await delSub(url);
await delSubRules(url); await delSubRules(url);
await deleteDataCache(url);
} catch (err) { } catch (err) {
console.log("[del subrules]", err); console.log("[del subrules]", err);
} }
@@ -645,7 +648,7 @@ function SubRulesItem({
if (rules.length > 0 && url === selectedUrl) { if (rules.length > 0 && url === selectedUrl) {
setSelectedRules(rules); setSelectedRules(rules);
} }
await updateSub(url, { syncAt: Date.now() }); await updateDataCache(url);
} catch (err) { } catch (err) {
console.log("[sync sub rules]", err); console.log("[sync sub rules]", err);
} finally { } finally {
@@ -680,7 +683,7 @@ function SubRulesItem({
); );
} }
function SubRulesEdit({ subList, addSub }) { function SubRulesEdit({ subList, addSub, updateDataCache }) {
const i18n = useI18n(); const i18n = useI18n();
const [inputText, setInputText] = useState(""); const [inputText, setInputText] = useState("");
const [inputError, setInputError] = useState(""); const [inputError, setInputError] = useState("");
@@ -715,6 +718,7 @@ function SubRulesEdit({ subList, addSub }) {
throw new Error("empty rules"); throw new Error("empty rules");
} }
await addSub(url); await addSub(url);
await updateDataCache(url);
setShowInput(false); setShowInput(false);
setInputText(""); setInputText("");
} catch (err) { } catch (err) {
@@ -787,7 +791,6 @@ function SubRules({ subRules }) {
const { const {
subList, subList,
selectSub, selectSub,
updateSub,
addSub, addSub,
delSub, delSub,
selectedUrl, selectedUrl,
@@ -795,27 +798,38 @@ function SubRules({ subRules }) {
setSelectedRules, setSelectedRules,
loading, loading,
} = subRules; } = subRules;
const { dataCaches, updateDataCache, deleteDataCache, reloadSync } =
useSyncCaches();
const handleSelect = (e) => { const handleSelect = (e) => {
const url = e.target.value; const url = e.target.value;
selectSub(url); selectSub(url);
}; };
useEffect(() => {
reloadSync();
}, [selectedRules, reloadSync]);
return ( return (
<Stack spacing={3}> <Stack spacing={3}>
<SubRulesEdit subList={subList} addSub={addSub} /> <SubRulesEdit
subList={subList}
addSub={addSub}
updateDataCache={updateDataCache}
/>
<RadioGroup value={selectedUrl} onChange={handleSelect}> <RadioGroup value={selectedUrl} onChange={handleSelect}>
{subList.map((item, index) => ( {subList.map((item, index) => (
<SubRulesItem <SubRulesItem
key={item.url} key={item.url}
url={item.url} url={item.url}
syncAt={item.syncAt} syncAt={dataCaches[item.url]}
index={index} index={index}
selectedUrl={selectedUrl} selectedUrl={selectedUrl}
delSub={delSub} delSub={delSub}
updateSub={updateSub}
setSelectedRules={setSelectedRules} setSelectedRules={setSelectedRules}
updateDataCache={updateDataCache}
deleteDataCache={deleteDataCache}
/> />
))} ))}
</RadioGroup> </RadioGroup>

View File

@@ -21,14 +21,14 @@ import HelpButton from "./HelpButton";
import { URL_KISS_RULES_NEW_ISSUE } from "../../config"; import { URL_KISS_RULES_NEW_ISSUE } from "../../config";
function ApiFields({ site }) { function ApiFields({ site }) {
const { selector, rootSlector, fixer } = site; const { selector, rootSelector, fixer } = site;
return ( return (
<Stack spacing={3}> <Stack spacing={3}>
<TextField <TextField
size="small" size="small"
label={"rootSlector"} label={"rootSelector"}
name="rootSlector" name="rootSelector"
value={rootSlector || "document"} value={rootSelector || "document"}
disabled disabled
/> />
<TextField <TextField