diff --git a/src/apis/index.js b/src/apis/index.js index eef30e5..55ac733 100644 --- a/src/apis/index.js +++ b/src/apis/index.js @@ -33,13 +33,12 @@ export const apiSyncData = async (url, key, data, isBg = false) => }); /** - * 下载订阅规则 + * 下载数据 * @param {*} url * @param {*} isBg * @returns */ -export const apiFetchRules = (url, isBg = false) => - fetchPolyfill(url, { isBg }); +export const apiFetch = (url, isBg = false) => fetchPolyfill(url, { isBg }); /** * 谷歌翻译 diff --git a/src/config/i18n.js b/src/config/i18n.js index 802634d..94c3b32 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -441,9 +441,9 @@ export const I18N = { zh: `数据同步密钥`, en: `Data Sync Key`, }, - data_sync_test: { - zh: `数据同步测试`, - en: `Data Sync Test`, + sync_now: { + zh: `立即同步`, + en: `Sync Now`, }, sync_success: { zh: `同步成功!`, diff --git a/src/libs/storage.js b/src/libs/storage.js index abdc6e5..5a42c58 100644 --- a/src/libs/storage.js +++ b/src/libs/storage.js @@ -5,6 +5,7 @@ import { STOKEY_SYNC, STOKEY_MSAUTH, STOKEY_RULESCACHE_PREFIX, + STOKEY_WEBFIXCACHE_PREFIX, DEFAULT_SETTING, DEFAULT_RULES, DEFAULT_SYNC, @@ -104,6 +105,14 @@ export const delSubRules = (url) => del(STOKEY_RULESCACHE_PREFIX + url); export const setSubRules = (url, val) => setObj(STOKEY_RULESCACHE_PREFIX + url, val); +/** + * 修复站点 + */ +export const getWebfix = (url) => getObj(STOKEY_WEBFIXCACHE_PREFIX + url); +export const getWebfixWithDefault = async () => (await getWebfix()) || []; +export const setWebfix = (url, val) => + setObj(STOKEY_WEBFIXCACHE_PREFIX + url, val); + /** * fab位置 */ diff --git a/src/libs/subRules.js b/src/libs/subRules.js index b537edb..6dc5bef 100644 --- a/src/libs/subRules.js +++ b/src/libs/subRules.js @@ -6,7 +6,7 @@ import { getSubRules, updateSetting, } from "./storage"; -import { apiFetchRules } from "../apis"; +import { apiFetch } from "../apis"; import { checkRules } from "./rules"; import { isAllchar } from "./utils"; @@ -16,7 +16,7 @@ import { isAllchar } from "./utils"; * @returns */ export const syncSubRules = async (url, isBg = false) => { - const res = await apiFetchRules(url, isBg); + const res = await apiFetch(url, isBg); const rules = checkRules(res).filter( ({ pattern }) => !isAllchar(pattern, GLOBAL_KEY) ); diff --git a/src/libs/webfix.js b/src/libs/webfix.js index d629615..26c0ccd 100644 --- a/src/libs/webfix.js +++ b/src/libs/webfix.js @@ -1,4 +1,11 @@ import { isMatch } from "./utils"; +import { getWebfix, setWebfix } from "./storage"; +import { apiFetch } from "../apis"; + +/** + * 修复程序类型 + */ +const WEBFIX_BR = "br"; /** * 需要修复的站点列表 @@ -7,18 +14,18 @@ import { isMatch } from "./utils"; * - rootSlector 需要监听的选择器,可留空 * - fixer 修复函数,可针对不同网址,选用不同修复函数 */ -export const sites = [ +const DEFAULT_SITES = [ { pattern: "www.phoronix.com", selector: ".content", rootSlector: "", - fixer: brFixer, + fixer: WEBFIX_BR, }, { pattern: "t.me/s/*", selector: ".tgme_widget_message_text", rootSlector: ".tgme_channel_history", - fixer: brFixer, + fixer: WEBFIX_BR, }, ]; @@ -80,6 +87,13 @@ function brFixer(node) { node.innerHTML = html; } +/** + * 修复程序映射 + */ +const fixerMap = { + [WEBFIX_BR]: brFixer, +}; + /** * 查找、监听节点,并执行修复函数 * @param {*} selector @@ -108,19 +122,51 @@ function run(selector, fixer, rootSlector) { }); } +/** + * 同步远程数据 + * @param {*} url + * @returns + */ +export const syncWebfix = async (url) => { + const sites = await apiFetch(url); + await setWebfix(url, sites); + return sites; +}; + +/** + * 从缓存或远程加载修复站点 + * @param {*} url + * @returns + */ +export const loadOrFetchWebfix = async (url) => { + try { + let sites = await getWebfix(url); + if (sites?.length) { + return sites; + } + return syncWebfix(url); + } catch (err) { + console.log("[load webfix]", err.message); + return DEFAULT_SITES; + } +}; + /** * 匹配站点 */ -export function webfix(href, { injectWebfix }) { +export async function webfix(href, { injectWebfix }) { try { if (!injectWebfix) { return; } + const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL); for (var i = 0; i < sites.length; i++) { var site = sites[i]; if (isMatch(href, site.pattern)) { - run(site.selector, site.fixer, site.rootSlector); + if (fixerMap[site.fixer]) { + run(site.selector, fixerMap[site.fixer], site.rootSlector); + } break; } } diff --git a/src/views/Options/SyncSetting.js b/src/views/Options/SyncSetting.js index 0ffefbe..a028fec 100644 --- a/src/views/Options/SyncSetting.js +++ b/src/views/Options/SyncSetting.js @@ -87,7 +87,7 @@ export default function SyncSetting() { onClick={handleSyncTest} startIcon={} > - {i18n("data_sync_test")} + {i18n("sync_now")} {loading && } diff --git a/src/views/Options/Webfix.js b/src/views/Options/Webfix.js index 6f2ce3d..c715a2a 100644 --- a/src/views/Options/Webfix.js +++ b/src/views/Options/Webfix.js @@ -1,6 +1,6 @@ import Stack from "@mui/material/Stack"; import TextField from "@mui/material/TextField"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useI18n } from "../../hooks/I18n"; import Typography from "@mui/material/Typography"; import Accordion from "@mui/material/Accordion"; @@ -9,13 +9,17 @@ import AccordionDetails from "@mui/material/AccordionDetails"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import Alert from "@mui/material/Alert"; import Box from "@mui/material/Box"; -import { sites as webfixSites } from "../../libs/webfix"; import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; import { useSetting } from "../../hooks/Setting"; +import CircularProgress from "@mui/material/CircularProgress"; +import { syncWebfix, loadOrFetchWebfix } from "../../libs/webfix"; +import Button from "@mui/material/Button"; +import SyncIcon from "@mui/icons-material/Sync"; +import { useAlert } from "../../hooks/Alert"; function ApiFields({ site }) { - const { selector, rootSlector } = site; + const { selector, rootSlector, fixer } = site; return ( + ); } @@ -56,33 +67,90 @@ function ApiAccordion({ site }) { } export default function Webfix() { + const [loading, setLoading] = useState(false); + const [sites, setSites] = useState([]); const i18n = useI18n(); + const alert = useAlert(); const { setting, updateSetting } = useSetting(); + + const handleSyncTest = async (e) => { + e.preventDefault(); + try { + setLoading(true); + await syncWebfix(process.env.REACT_APP_WEBFIXURL); + alert.success(i18n("sync_success")); + } catch (err) { + console.log("[sync webfix]", err); + alert.error(i18n("sync_failed")); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + (async () => { + try { + setLoading(true); + const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL); + setSites(sites); + } catch (err) { + console.log("[load webfix]", err.message); + } finally { + setLoading(false); + } + })(); + }, []); + return ( {i18n("patch_setting_help")} - { - updateSetting({ - injectWebfix: !setting.injectWebfix, - }); - }} - /> - } - label={i18n("inject_webfix")} - /> + + + { + updateSetting({ + injectWebfix: !setting.injectWebfix, + }); + }} + /> + } + label={i18n("inject_webfix")} + /> + - - {webfixSites.map((site) => ( - - ))} - + {setting.injectWebfix && ( + + {loading ? ( +
+ +
+ ) : ( + sites.map((site) => ( + + )) + )} +
+ )}
);