This commit is contained in:
Gabe Yuan
2023-09-08 21:41:32 +08:00
parent 1ff1b21355
commit 441a2ca2da
7 changed files with 158 additions and 36 deletions

View File

@@ -33,13 +33,12 @@ export const apiSyncData = async (url, key, data, isBg = false) =>
}); });
/** /**
* 下载订阅规则 * 下载数据
* @param {*} url * @param {*} url
* @param {*} isBg * @param {*} isBg
* @returns * @returns
*/ */
export const apiFetchRules = (url, isBg = false) => export const apiFetch = (url, isBg = false) => fetchPolyfill(url, { isBg });
fetchPolyfill(url, { isBg });
/** /**
* 谷歌翻译 * 谷歌翻译

View File

@@ -441,9 +441,9 @@ export const I18N = {
zh: `数据同步密钥`, zh: `数据同步密钥`,
en: `Data Sync Key`, en: `Data Sync Key`,
}, },
data_sync_test: { sync_now: {
zh: `数据同步测试`, zh: `立即同步`,
en: `Data Sync Test`, en: `Sync Now`,
}, },
sync_success: { sync_success: {
zh: `同步成功!`, zh: `同步成功!`,

View File

@@ -5,6 +5,7 @@ import {
STOKEY_SYNC, STOKEY_SYNC,
STOKEY_MSAUTH, STOKEY_MSAUTH,
STOKEY_RULESCACHE_PREFIX, STOKEY_RULESCACHE_PREFIX,
STOKEY_WEBFIXCACHE_PREFIX,
DEFAULT_SETTING, DEFAULT_SETTING,
DEFAULT_RULES, DEFAULT_RULES,
DEFAULT_SYNC, DEFAULT_SYNC,
@@ -104,6 +105,14 @@ export const delSubRules = (url) => del(STOKEY_RULESCACHE_PREFIX + url);
export const setSubRules = (url, val) => export const setSubRules = (url, val) =>
setObj(STOKEY_RULESCACHE_PREFIX + 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位置 * fab位置
*/ */

View File

@@ -6,7 +6,7 @@ import {
getSubRules, getSubRules,
updateSetting, updateSetting,
} from "./storage"; } from "./storage";
import { apiFetchRules } from "../apis"; import { apiFetch } from "../apis";
import { checkRules } from "./rules"; import { checkRules } from "./rules";
import { isAllchar } from "./utils"; import { isAllchar } from "./utils";
@@ -16,7 +16,7 @@ import { isAllchar } from "./utils";
* @returns * @returns
*/ */
export const syncSubRules = async (url, isBg = false) => { export const syncSubRules = async (url, isBg = false) => {
const res = await apiFetchRules(url, isBg); const res = await apiFetch(url, isBg);
const rules = checkRules(res).filter( const rules = checkRules(res).filter(
({ pattern }) => !isAllchar(pattern, GLOBAL_KEY) ({ pattern }) => !isAllchar(pattern, GLOBAL_KEY)
); );

View File

@@ -1,4 +1,11 @@
import { isMatch } from "./utils"; 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 需要监听的选择器,可留空 * - rootSlector 需要监听的选择器,可留空
* - fixer 修复函数,可针对不同网址,选用不同修复函数 * - fixer 修复函数,可针对不同网址,选用不同修复函数
*/ */
export const sites = [ const DEFAULT_SITES = [
{ {
pattern: "www.phoronix.com", pattern: "www.phoronix.com",
selector: ".content", selector: ".content",
rootSlector: "", rootSlector: "",
fixer: brFixer, fixer: WEBFIX_BR,
}, },
{ {
pattern: "t.me/s/*", pattern: "t.me/s/*",
selector: ".tgme_widget_message_text", selector: ".tgme_widget_message_text",
rootSlector: ".tgme_channel_history", rootSlector: ".tgme_channel_history",
fixer: brFixer, fixer: WEBFIX_BR,
}, },
]; ];
@@ -80,6 +87,13 @@ function brFixer(node) {
node.innerHTML = html; node.innerHTML = html;
} }
/**
* 修复程序映射
*/
const fixerMap = {
[WEBFIX_BR]: brFixer,
};
/** /**
* 查找、监听节点,并执行修复函数 * 查找、监听节点,并执行修复函数
* @param {*} selector * @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 { try {
if (!injectWebfix) { if (!injectWebfix) {
return; return;
} }
const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
for (var i = 0; i < sites.length; i++) { for (var i = 0; i < sites.length; i++) {
var site = sites[i]; var site = sites[i];
if (isMatch(href, site.pattern)) { 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; break;
} }
} }

View File

@@ -87,7 +87,7 @@ export default function SyncSetting() {
onClick={handleSyncTest} onClick={handleSyncTest}
startIcon={<SyncIcon />} startIcon={<SyncIcon />}
> >
{i18n("data_sync_test")} {i18n("sync_now")}
</Button> </Button>
{loading && <CircularProgress size={16} />} {loading && <CircularProgress size={16} />}
</Stack> </Stack>

View File

@@ -1,6 +1,6 @@
import Stack from "@mui/material/Stack"; import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import { useState } from "react"; import { useEffect, useState } from "react";
import { useI18n } from "../../hooks/I18n"; import { useI18n } from "../../hooks/I18n";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion"; import Accordion from "@mui/material/Accordion";
@@ -9,13 +9,17 @@ import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Alert from "@mui/material/Alert"; import Alert from "@mui/material/Alert";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import { sites as webfixSites } from "../../libs/webfix";
import FormControlLabel from "@mui/material/FormControlLabel"; import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch"; import Switch from "@mui/material/Switch";
import { useSetting } from "../../hooks/Setting"; 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 }) { function ApiFields({ site }) {
const { selector, rootSlector } = site; const { selector, rootSlector, fixer } = site;
return ( return (
<Stack spacing={3}> <Stack spacing={3}>
<TextField <TextField
@@ -32,6 +36,13 @@ function ApiFields({ site }) {
value={selector} value={selector}
disabled disabled
/> />
<TextField
size="small"
label={"fixer"}
name="fixer"
value={fixer}
disabled
/>
</Stack> </Stack>
); );
} }
@@ -56,33 +67,90 @@ function ApiAccordion({ site }) {
} }
export default function Webfix() { export default function Webfix() {
const [loading, setLoading] = useState(false);
const [sites, setSites] = useState([]);
const i18n = useI18n(); const i18n = useI18n();
const alert = useAlert();
const { setting, updateSetting } = useSetting(); 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 ( return (
<Box> <Box>
<Stack spacing={3}> <Stack spacing={3}>
<Alert severity="info">{i18n("patch_setting_help")}</Alert> <Alert severity="info">{i18n("patch_setting_help")}</Alert>
<FormControlLabel <Stack
control={ direction="row"
<Switch alignItems="center"
size="small" spacing={2}
checked={!!setting.injectWebfix} useFlexGap
onChange={() => { flexWrap="wrap"
updateSetting({ >
injectWebfix: !setting.injectWebfix, <Button
}); size="small"
}} variant="outlined"
/> disabled={loading}
} onClick={handleSyncTest}
label={i18n("inject_webfix")} startIcon={<SyncIcon />}
/> >
{i18n("sync_now")}
</Button>
<FormControlLabel
control={
<Switch
size="small"
checked={!!setting.injectWebfix}
onChange={() => {
updateSetting({
injectWebfix: !setting.injectWebfix,
});
}}
/>
}
label={i18n("inject_webfix")}
/>
</Stack>
<Box> {setting.injectWebfix && (
{webfixSites.map((site) => ( <Box>
<ApiAccordion key={site.pattern} site={site} /> {loading ? (
))} <center>
</Box> <CircularProgress size={16} />
</center>
) : (
sites.map((site) => (
<ApiAccordion key={site.pattern} site={site} />
))
)}
</Box>
)}
</Stack> </Stack>
</Box> </Box>
); );