feat: translate blacklist

This commit is contained in:
Gabe Yuan
2023-11-24 17:07:29 +08:00
parent 7bc39dd1bc
commit 22c50e7765
8 changed files with 200 additions and 193 deletions

View File

@@ -8,27 +8,83 @@ import {
MSG_TRANS_TOGGLE_STYLE,
MSG_TRANS_GETRULE,
MSG_TRANS_PUTRULE,
MSG_TRANSLATE_SELECTED,
MSG_OPEN_TRANBOX,
APP_LCNAME,
DEFAULT_TRANBOX_SETTING,
} from "./config";
import { getRulesWithDefault, getFabWithDefault } from "./libs/storage";
import { getFabWithDefault, getSettingWithDefault } from "./libs/storage";
import { Translator } from "./libs/translator";
import { sendIframeMsg, sendParentMsg } from "./libs/iframe";
import { matchRule } from "./libs/rules";
import { isIframe, sendIframeMsg, sendParentMsg } from "./libs/iframe";
import Slection from "./views/Selection";
import { touchTapListener } from "./libs/touch";
import { debounce } from "./libs/utils";
import { debounce, genEventName } from "./libs/utils";
import { handlePing, injectScript } from "./libs/gm";
import { browser } from "./libs/browser";
import { runWebfix } from "./libs/webfix";
import { matchRule } from "./libs/rules";
import { trySyncAllSubRules } from "./libs/subRules";
import { isInBlacklist } from "./libs/blacklist";
export async function runTranslator(setting) {
const href = document.location.href;
const rules = await getRulesWithDefault();
const rule = await matchRule(rules, href, setting);
const translator = new Translator(rule, setting);
return { translator, rule };
/**
* 油猴脚本设置页面
*/
function runSettingPage() {
if (GM?.info?.script?.grant?.includes("unsafeWindow")) {
unsafeWindow.GM = GM;
unsafeWindow.APP_INFO = {
name: process.env.REACT_APP_NAME,
version: process.env.REACT_APP_VERSION,
};
} else {
const ping = genEventName();
window.addEventListener(ping, handlePing);
// window.eval(`(${injectScript})("${ping}")`); // eslint-disable-line
const script = document.createElement("script");
script.textContent = `(${injectScript})("${ping}")`;
document.head.append(script);
}
}
export function runIframe(setting) {
/**
* 插件监听后端事件
* @param {*} translator
*/
function runtimeListener(translator) {
browser?.runtime.onMessage.addListener(async ({ action, args }) => {
switch (action) {
case MSG_TRANS_TOGGLE:
translator.toggle();
sendIframeMsg(MSG_TRANS_TOGGLE);
break;
case MSG_TRANS_TOGGLE_STYLE:
translator.toggleStyle();
sendIframeMsg(MSG_TRANS_TOGGLE_STYLE);
break;
case MSG_TRANS_GETRULE:
break;
case MSG_TRANS_PUTRULE:
translator.updateRule(args);
sendIframeMsg(MSG_TRANS_PUTRULE, args);
break;
case MSG_TRANSLATE_SELECTED:
window.dispatchEvent(new CustomEvent(MSG_TRANSLATE_SELECTED));
break;
case MSG_OPEN_TRANBOX:
window.dispatchEvent(new CustomEvent(MSG_OPEN_TRANBOX));
break;
default:
return { error: `message action is unavailable: ${action}` };
}
return { data: translator.rule };
});
}
/**
* iframe 页面执行
* @param {*} setting
*/
function runIframe(setting) {
let translator;
window.addEventListener("message", (e) => {
const { action, args } = e.data || {};
@@ -52,7 +108,12 @@ export function runIframe(setting) {
sendParentMsg(MSG_TRANS_GETRULE);
}
export async function showFab(translator) {
/**
* 悬浮按钮
* @param {*} translator
* @returns
*/
async function showFab(translator) {
const fab = await getFabWithDefault();
if (fab.isHide) {
return;
@@ -80,10 +141,12 @@ export async function showFab(translator) {
);
}
export function showTransbox({
tranboxSetting = DEFAULT_TRANBOX_SETTING,
transApis,
}) {
/**
* 划词翻译
* @param {*} param0
* @returns
*/
function showTransbox({ tranboxSetting = DEFAULT_TRANBOX_SETTING, transApis }) {
if (!tranboxSetting?.transOpen) {
return;
}
@@ -110,7 +173,11 @@ export function showTransbox({
);
}
export function windowListener(rule) {
/**
* 监听来自iframe页面消息
* @param {*} rule
*/
function windowListener(rule) {
window.addEventListener("message", (e) => {
const { action } = e.data || {};
switch (action) {
@@ -122,14 +189,23 @@ export function windowListener(rule) {
});
}
export function showErr(message) {
/**
* 显示错误信息到页面顶部
* @param {*} message
*/
function showErr(message) {
const $err = document.createElement("div");
$err.innerText = `KISS-Translator: ${message}`;
$err.style.cssText = "background:red; color:#fff;";
document.body.prepend($err);
}
export function touchOperation(translator) {
/**
* 监听触屏操作
* @param {*} translator
* @returns
*/
function touchOperation(translator) {
const { touchTranslate = 2 } = translator.setting;
if (touchTranslate === 0) {
return;
@@ -141,3 +217,63 @@ export function touchOperation(translator) {
});
touchTapListener(handleTap, touchTranslate);
}
/**
* 入口函数
*/
export async function run(isUserscript = false) {
try {
const href = document.location.href;
// 设置页面
if (
isUserscript &&
(href.includes(process.env.REACT_APP_OPTIONSPAGE_DEV) ||
href.includes(process.env.REACT_APP_OPTIONSPAGE) ||
href.includes(process.env.REACT_APP_OPTIONSPAGE2))
) {
runSettingPage();
return;
}
// 读取设置信息
const setting = await getSettingWithDefault();
// 黑名单
if (isInBlacklist(href, setting)) {
return;
}
// 适配iframe
if (isIframe) {
runIframe(setting);
return;
}
// 不规范网页修复
await runWebfix(setting);
// 翻译网页
const rule = await matchRule(href, setting);
const translator = new Translator(rule, setting);
// 监听消息
windowListener(rule);
!isUserscript && runtimeListener(translator);
// 划词翻译
showTransbox(setting);
// 浮球按钮
await showFab(translator);
// 触屏操作
touchOperation(translator);
// 同步订阅规则
isUserscript && (await trySyncAllSubRules(setting));
} catch (err) {
console.error("[KISS-Translator]", err);
showErr(err.message);
}
}

View File

@@ -352,8 +352,8 @@ export const I18N = {
en: `URL pattern`,
},
pattern_helper: {
zh: `1、支持星号(*)通配符。2、多个URL支持英文逗号“,”分隔。`,
en: `1. The asterisk (*) wildcard is supported. 2. Multiple URLs can be separated by English commas ",".`,
zh: `1、支持星号(*)通配符。2、多个URL英文逗号“,”分隔。`,
en: `1. The asterisk (*) wildcard is supported. 2. Multiple URLs separated by English commas ",".`,
},
selector_helper: {
zh: `1、遵循CSS选择器语法。2、留空表示采用全局设置。3、多个CSS选择器之间用“;”隔开。4、“shadow root”选择器和内部选择器用“>>>”隔开。`,
@@ -683,4 +683,8 @@ export const I18N = {
zh: `四指轻触`,
en: `Four finger tap`,
},
translate_blacklist: {
zh: `禁用翻译名单`,
en: `Translate Blacklist`,
},
};

View File

@@ -412,6 +412,13 @@ export const DEFAULT_SHORTCUTS = {
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
export const TRANS_MAX_LENGTH = 5000; // 最长翻译长度
export const TRANS_NEWLINE_LENGTH = 20; // 换行字符数
export const DEFAULT_BLACKLIST = [
"https://fishjar.github.io/kiss-translator/options.html",
"https://translate.google.com",
"https://www.deepl.com/translator",
"oapi.dingtalk.com",
"login.dingtalk.com",
]; // 禁用翻译名单
export const DEFAULT_SETTING = {
darkMode: false, // 深色模式
@@ -433,6 +440,7 @@ export const DEFAULT_SETTING = {
inputRule: DEFAULT_INPUT_RULE, // 输入框设置
tranboxSetting: DEFAULT_TRANBOX_SETTING, // 划词翻译设置
touchTranslate: 2, // 触屏翻译
blacklist: DEFAULT_BLACKLIST.join(",\n"), // 禁用翻译名单
};
export const DEFAULT_RULES = [GLOBLA_RULE];

View File

@@ -1,89 +1,3 @@
import { browser } from "./libs/browser";
import {
MSG_TRANS_TOGGLE,
MSG_TRANS_TOGGLE_STYLE,
MSG_TRANSLATE_SELECTED,
MSG_OPEN_TRANBOX,
MSG_TRANS_GETRULE,
MSG_TRANS_PUTRULE,
} from "./config";
import { getSettingWithDefault } from "./libs/storage";
import { isIframe, sendIframeMsg } from "./libs/iframe";
import { runWebfix } from "./libs/webfix";
import {
runIframe,
runTranslator,
showFab,
showTransbox,
windowListener,
showErr,
touchOperation,
} from "./common";
import { run } from "./common";
function runtimeListener(translator) {
browser?.runtime.onMessage.addListener(async ({ action, args }) => {
switch (action) {
case MSG_TRANS_TOGGLE:
translator.toggle();
sendIframeMsg(MSG_TRANS_TOGGLE);
break;
case MSG_TRANS_TOGGLE_STYLE:
translator.toggleStyle();
sendIframeMsg(MSG_TRANS_TOGGLE_STYLE);
break;
case MSG_TRANS_GETRULE:
break;
case MSG_TRANS_PUTRULE:
translator.updateRule(args);
sendIframeMsg(MSG_TRANS_PUTRULE, args);
break;
case MSG_TRANSLATE_SELECTED:
window.dispatchEvent(new CustomEvent(MSG_TRANSLATE_SELECTED));
break;
case MSG_OPEN_TRANBOX:
window.dispatchEvent(new CustomEvent(MSG_OPEN_TRANBOX));
break;
default:
return { error: `message action is unavailable: ${action}` };
}
return { data: translator.rule };
});
}
/**
* 入口函数
*/
(async () => {
try {
// 读取设置信息
const setting = await getSettingWithDefault();
// 适配iframe
if (isIframe) {
runIframe(setting);
return;
}
// 不规范网页修复
await runWebfix(setting);
// 翻译网页
const { translator, rule } = await runTranslator(setting);
// 监听消息
windowListener(rule);
runtimeListener(translator);
// 划词翻译
showTransbox(setting);
// 浮球按钮
await showFab(translator);
// 触屏操作
touchOperation(translator);
} catch (err) {
console.error("[KISS-Translator]", err);
showErr(err.message);
}
})();
run();

13
src/libs/blacklist.js Normal file
View File

@@ -0,0 +1,13 @@
import { isMatch } from "./utils";
import { DEFAULT_BLACKLIST } from "../config";
/**
* 检查是否在黑名单中
* @param {*} href
* @param {*} param1
* @returns
*/
export const isInBlacklist = (
href,
{ blacklist = DEFAULT_BLACKLIST.join(",\n") }
) => blacklist.split(",").some((url) => isMatch(href, url.trim()));

View File

@@ -21,7 +21,6 @@ import { trySyncRules } from "./sync";
* @returns
*/
export const matchRule = async (
rules,
href,
{
injectRules = true,
@@ -29,7 +28,7 @@ export const matchRule = async (
owSubrule = DEFAULT_OW_RULE,
}
) => {
rules = [...rules];
const rules = await getRulesWithDefault();
if (injectRules) {
try {
const selectedSub = subrulesList.find((item) => item.selected);

View File

@@ -1,82 +1,3 @@
import { getSettingWithDefault } from "./libs/storage";
import { trySyncAllSubRules } from "./libs/subRules";
import { isIframe } from "./libs/iframe";
import { handlePing, injectScript } from "./libs/gm";
import { genEventName } from "./libs/utils";
import { runWebfix } from "./libs/webfix";
import {
runIframe,
runTranslator,
showFab,
showTransbox,
windowListener,
showErr,
touchOperation,
} from "./common";
import { run } from "./common";
function runSettingPage() {
if (GM?.info?.script?.grant?.includes("unsafeWindow")) {
unsafeWindow.GM = GM;
unsafeWindow.APP_INFO = {
name: process.env.REACT_APP_NAME,
version: process.env.REACT_APP_VERSION,
};
} else {
const ping = genEventName();
window.addEventListener(ping, handlePing);
// window.eval(`(${injectScript})("${ping}")`); // eslint-disable-line
const script = document.createElement("script");
script.textContent = `(${injectScript})("${ping}")`;
document.head.append(script);
}
}
/**
* 入口函数
*/
(async () => {
try {
// 设置页面
if (
document.location.href.includes(process.env.REACT_APP_OPTIONSPAGE_DEV) ||
document.location.href.includes(process.env.REACT_APP_OPTIONSPAGE) ||
document.location.href.includes(process.env.REACT_APP_OPTIONSPAGE2)
) {
runSettingPage();
return;
}
// 读取设置信息
const setting = await getSettingWithDefault();
// 适配iframe
if (isIframe) {
runIframe(setting);
return;
}
// 不规范网页修复
await runWebfix(setting);
// 翻译网页
const { translator, rule } = await runTranslator(setting);
// 监听消息
windowListener(rule);
// 划词翻译
showTransbox(setting);
// 浮球按钮
await showFab(translator);
// 触屏操作
touchOperation(translator);
// 同步订阅规则
await trySyncAllSubRules(setting);
} catch (err) {
console.error("[KISS-Translator]", err);
showErr(err.message);
}
})();
run(true);

View File

@@ -23,6 +23,7 @@ import {
OPT_SHORTCUT_STYLE,
OPT_SHORTCUT_POPUP,
OPT_SHORTCUT_SETTING,
DEFAULT_BLACKLIST,
} from "../../config";
import { useShortcut } from "../../hooks/Shortcut";
import ShortcutInput from "./ShortcutInput";
@@ -90,6 +91,7 @@ export default function Settings() {
mouseKey = OPT_MOUSEKEY_DISABLE,
detectRemote = false,
touchTranslate = 2,
blacklist = DEFAULT_BLACKLIST.join(",\n"),
} = setting;
const { isHide = false } = fab || {};
@@ -268,6 +270,16 @@ export default function Settings() {
</Box>
</>
)}
<TextField
size="small"
label={i18n("translate_blacklist")}
helperText={i18n("pattern_helper")}
name="blacklist"
defaultValue={blacklist}
onChange={handleChange}
multiline
/>
</Stack>
</Box>
);