webfix setting

This commit is contained in:
Gabe Yuan
2023-09-08 16:56:00 +08:00
parent 07d457be4e
commit 117ca4e05b
9 changed files with 248 additions and 0 deletions

2
.env
View File

@@ -17,6 +17,8 @@ REACT_APP_RULESURL=https://fishjar.github.io/kiss-rules/kiss-rules.json
REACT_APP_RULESURL_ON=https://fishjar.github.io/kiss-rules/kiss-rules-on.json REACT_APP_RULESURL_ON=https://fishjar.github.io/kiss-rules/kiss-rules-on.json
REACT_APP_RULESURL_OFF=https://fishjar.github.io/kiss-rules/kiss-rules-off.json REACT_APP_RULESURL_OFF=https://fishjar.github.io/kiss-rules/kiss-rules-off.json
REACT_APP_WEBFIXURL=https://fishjar.github.io/kiss-rules/kiss-webfix.json
REACT_APP_VERSIONFILE=https://fishjar.github.io/kiss-translator/version.txt REACT_APP_VERSIONFILE=https://fishjar.github.io/kiss-translator/version.txt
REACT_APP_VERSIONFILE2=https://kiss-translator.rayjar.com/version.txt REACT_APP_VERSIONFILE2=https://kiss-translator.rayjar.com/version.txt

View File

@@ -129,6 +129,18 @@ export const I18N = {
zh: `同步设置`, zh: `同步设置`,
en: `Sync Setting`, en: `Sync Setting`,
}, },
patch_setting: {
zh: `补丁设置`,
en: `Patch Setting`,
},
patch_setting_help: {
zh: `针对一些特殊网站的修正脚本,以便翻译软件得到更好的展示效果。`,
en: `Corrected scripts for some special websites so that the translation software can get better display results.`,
},
inject_webfix: {
zh: `注入修复补丁`,
en: `Inject Webfix`,
},
about: { about: {
zh: `关于`, zh: `关于`,
en: `About`, en: `About`,

View File

@@ -25,6 +25,7 @@ export const STOKEY_RULES = `${APP_NAME}_rules`;
export const STOKEY_SYNC = `${APP_NAME}_sync`; export const STOKEY_SYNC = `${APP_NAME}_sync`;
export const STOKEY_FAB = `${APP_NAME}_fab`; export const STOKEY_FAB = `${APP_NAME}_fab`;
export const STOKEY_RULESCACHE_PREFIX = `${APP_NAME}_rulescache_`; export const STOKEY_RULESCACHE_PREFIX = `${APP_NAME}_rulescache_`;
export const STOKEY_WEBFIXCACHE_PREFIX = `${APP_NAME}_webfixcache_`;
export const CMD_TOGGLE_TRANSLATE = "toggleTranslate"; export const CMD_TOGGLE_TRANSLATE = "toggleTranslate";
export const CMD_TOGGLE_STYLE = "toggleStyle"; export const CMD_TOGGLE_STYLE = "toggleStyle";
@@ -262,6 +263,7 @@ export const DEFAULT_SETTING = {
newlineLength: TRANS_NEWLINE_LENGTH, newlineLength: TRANS_NEWLINE_LENGTH,
clearCache: false, // 是否在浏览器下次启动时清除缓存 clearCache: false, // 是否在浏览器下次启动时清除缓存
injectRules: true, // 是否注入订阅规则 injectRules: true, // 是否注入订阅规则
injectWebfix: true, // 是否注入修复补丁
subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表 subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表
owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则 owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则
transApis: DEFAULT_TRANS_APIS, // 翻译接口 transApis: DEFAULT_TRANS_APIS, // 翻译接口

View File

@@ -9,6 +9,7 @@ import { getSettingWithDefault, getRulesWithDefault } from "./libs/storage";
import { Translator } from "./libs/translator"; import { Translator } from "./libs/translator";
import { isIframe } from "./libs/iframe"; import { isIframe } from "./libs/iframe";
import { matchRule } from "./libs/rules"; import { matchRule } from "./libs/rules";
import { webfix } from "./libs/webfix";
/** /**
* 入口函数 * 入口函数
@@ -19,6 +20,7 @@ const init = async () => {
const rules = await getRulesWithDefault(); const rules = await getRulesWithDefault();
const rule = await matchRule(rules, href, setting); const rule = await matchRule(rules, href, setting);
const translator = new Translator(rule, setting); const translator = new Translator(rule, setting);
webfix(href, setting);
// 监听消息 // 监听消息
browser?.runtime.onMessage.addListener(async ({ action, args }) => { browser?.runtime.onMessage.addListener(async ({ action, args }) => {

130
src/libs/webfix.js Normal file
View File

@@ -0,0 +1,130 @@
import { isMatch } from "./utils";
/**
* 需要修复的站点列表
* - pattern 匹配网址
* - selector 需要修复的选择器
* - rootSlector 需要监听的选择器,可留空
* - fixer 修复函数,可针对不同网址,选用不同修复函数
*/
export const sites = [
{
pattern: "www.phoronix.com",
selector: ".content",
rootSlector: "",
fixer: brFixer,
},
{
pattern: "t.me/s/*",
selector: ".tgme_widget_message_text",
rootSlector: ".tgme_channel_history",
fixer: brFixer,
},
];
/**
* 修复过的标记
*/
const fixedSign = "kissfixed";
/**
* 采用 `br` 换行网站的修复函数
* 目标是将 `br` 替换成 `p`
* @param {*} node
* @returns
*/
function brFixer(node) {
if (node.hasAttribute(fixedSign)) {
return;
}
node.setAttribute(fixedSign, "true");
var gapTags = ["BR", "WBR"];
var newlineTags = [
"DIV",
"UL",
"OL",
"LI",
"H1",
"H2",
"H3",
"H4",
"H5",
"H6",
"P",
"HR",
"PRE",
"TABLE",
];
var html = "";
node.childNodes.forEach(function (child, index) {
if (index === 0) {
html += "<p>";
}
if (gapTags.indexOf(child.nodeName) !== -1) {
html += "</p><p>";
} else if (newlineTags.indexOf(child.nodeName) !== -1) {
html += "</p>" + child.outerHTML + "<p>";
} else if (child.outerHTML) {
html += child.outerHTML;
} else if (child.nodeValue) {
html += child.nodeValue;
}
if (index === node.childNodes.length - 1) {
html += "</p>";
}
});
node.innerHTML = html;
}
/**
* 查找、监听节点,并执行修复函数
* @param {*} selector
* @param {*} fixer
* @param {*} rootSlector
*/
function run(selector, fixer, rootSlector) {
var mutaObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (addNode) {
addNode.querySelectorAll(selector).forEach(fixer);
});
});
});
var rootNodes = [document];
if (rootSlector) {
rootNodes = document.querySelectorAll(rootSlector);
}
rootNodes.forEach(function (rootNode) {
rootNode.querySelectorAll(selector).forEach(fixer);
mutaObserver.observe(rootNode, {
childList: true,
});
});
}
/**
* 匹配站点
*/
export function webfix(href, { injectWebfix }) {
try {
if (!injectWebfix) {
return;
}
for (var i = 0; i < sites.length; i++) {
var site = sites[i];
if (isMatch(href, site.pattern)) {
run(site.selector, site.fixer, site.rootSlector);
break;
}
}
} catch (err) {
console.error(`[kiss-webfix]: ${err.message}`);
}
}

View File

@@ -15,6 +15,7 @@ import { isIframe } from "./libs/iframe";
import { handlePing, injectScript } from "./libs/gm"; import { handlePing, injectScript } from "./libs/gm";
import { matchRule } from "./libs/rules"; import { matchRule } from "./libs/rules";
import { genEventName } from "./libs/utils"; import { genEventName } from "./libs/utils";
import { webfix } from "./libs/webfix";
/** /**
* 入口函数 * 入口函数
@@ -50,6 +51,7 @@ const init = async () => {
const rules = await getRulesWithDefault(); const rules = await getRulesWithDefault();
const rule = await matchRule(rules, href, setting); const rule = await matchRule(rules, href, setting);
const translator = new Translator(rule, setting); const translator = new Translator(rule, setting);
webfix(href, setting);
if (isIframe) { if (isIframe) {
// iframe // iframe

View File

@@ -11,6 +11,7 @@ import DesignServicesIcon from "@mui/icons-material/DesignServices";
import { useI18n } from "../../hooks/I18n"; import { useI18n } from "../../hooks/I18n";
import SyncIcon from "@mui/icons-material/Sync"; import SyncIcon from "@mui/icons-material/Sync";
import ApiIcon from "@mui/icons-material/Api"; import ApiIcon from "@mui/icons-material/Api";
import SendTimeExtensionIcon from "@mui/icons-material/SendTimeExtension";
function LinkItem({ label, url, icon }) { function LinkItem({ label, url, icon }) {
const match = useMatch(url); const match = useMatch(url);
@@ -49,6 +50,12 @@ export default function Navigator(props) {
url: "/sync", url: "/sync",
icon: <SyncIcon />, icon: <SyncIcon />,
}, },
{
id: "webfix",
label: i18n("patch_setting"),
url: "/webfix",
icon: <SendTimeExtensionIcon />,
},
{ id: "about", label: i18n("about"), url: "/about", icon: <InfoIcon /> }, { id: "about", label: i18n("about"), url: "/about", icon: <InfoIcon /> },
]; ];
return ( return (

View File

@@ -0,0 +1,89 @@
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import { useState } from "react";
import { useI18n } from "../../hooks/I18n";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
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";
function ApiFields({ site }) {
const { selector, rootSlector } = site;
return (
<Stack spacing={3}>
<TextField
size="small"
label={"rootSlector"}
name="rootSlector"
value={rootSlector || "document"}
disabled
/>
<TextField
size="small"
label={"selector"}
name="selector"
value={selector}
disabled
/>
</Stack>
);
}
function ApiAccordion({ site }) {
const [expanded, setExpanded] = useState(false);
const handleChange = (e) => {
setExpanded((pre) => !pre);
};
return (
<Accordion expanded={expanded} onChange={handleChange}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>{site.pattern}</Typography>
</AccordionSummary>
<AccordionDetails>
{expanded && <ApiFields site={site} />}
</AccordionDetails>
</Accordion>
);
}
export default function Webfix() {
const i18n = useI18n();
const { setting, updateSetting } = useSetting();
return (
<Box>
<Stack spacing={3}>
<Alert severity="info">{i18n("patch_setting_help")}</Alert>
<FormControlLabel
control={
<Switch
size="small"
checked={!!setting.injectWebfix}
onChange={() => {
updateSetting({
injectWebfix: !setting.injectWebfix,
});
}}
/>
}
label={i18n("inject_webfix")}
/>
<Box>
{webfixSites.map((site) => (
<ApiAccordion key={site.pattern} site={site} />
))}
</Box>
</Stack>
</Box>
);
}

View File

@@ -18,6 +18,7 @@ import Stack from "@mui/material/Stack";
import { adaptScript } from "../../libs/gm"; import { adaptScript } from "../../libs/gm";
import Alert from "@mui/material/Alert"; import Alert from "@mui/material/Alert";
import Apis from "./Apis"; import Apis from "./Apis";
import Webfix from "./Webfix";
export default function Options() { export default function Options() {
const [error, setError] = useState(""); const [error, setError] = useState("");
@@ -127,6 +128,7 @@ export default function Options() {
<Route path="rules" element={<Rules />} /> <Route path="rules" element={<Rules />} />
<Route path="apis" element={<Apis />} /> <Route path="apis" element={<Apis />} />
<Route path="sync" element={<SyncSetting />} /> <Route path="sync" element={<SyncSetting />} />
<Route path="webfix" element={<Webfix />} />
<Route path="about" element={<About />} /> <Route path="about" element={<About />} />
</Route> </Route>
</Routes> </Routes>