feat: add shadowroot injector
This commit is contained in:
@@ -32,7 +32,8 @@ const extWebpack = (config, env) => {
|
|||||||
options: paths.appSrc + "/options.js",
|
options: paths.appSrc + "/options.js",
|
||||||
background: paths.appSrc + "/background.js",
|
background: paths.appSrc + "/background.js",
|
||||||
content: paths.appSrc + "/content.js",
|
content: paths.appSrc + "/content.js",
|
||||||
injector: paths.appSrc + "/injector.js",
|
"injector-subtitle": paths.appSrc + "/injector-subtitle.js",
|
||||||
|
"injector-shadowroot": paths.appSrc + "/injector-shadowroot.js",
|
||||||
};
|
};
|
||||||
|
|
||||||
config.output.filename = "[name].js";
|
config.output.filename = "[name].js";
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"web_accessible_resources": [
|
"web_accessible_resources": [
|
||||||
"injector.js"
|
"injector-subtitle.js",
|
||||||
|
"injector-shadowroot.js"
|
||||||
],
|
],
|
||||||
"commands": {
|
"commands": {
|
||||||
"_execute_browser_action": {
|
"_execute_browser_action": {
|
||||||
|
|||||||
@@ -19,8 +19,12 @@
|
|||||||
],
|
],
|
||||||
"web_accessible_resources": [
|
"web_accessible_resources": [
|
||||||
{
|
{
|
||||||
"resources": ["injector.js"],
|
"resources": ["injector-subtitle.js"],
|
||||||
"matches": ["https://www.youtube.com/*"]
|
"matches": ["https://www.youtube.com/*"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resources": ["injector-shadowroot.js"],
|
||||||
|
"matches": ["<all_urls>"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"commands": {
|
"commands": {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"web_accessible_resources": [
|
"web_accessible_resources": [
|
||||||
"injector.js"
|
"injector-subtitle.js",
|
||||||
|
"injector-shadowroot.js"
|
||||||
],
|
],
|
||||||
"commands": {
|
"commands": {
|
||||||
"_execute_browser_action": {
|
"_execute_browser_action": {
|
||||||
|
|||||||
3
src/injector-shadowroot.js
Normal file
3
src/injector-shadowroot.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { shadowRootInjector } from "./injectors/shadowroot";
|
||||||
|
|
||||||
|
shadowRootInjector();
|
||||||
3
src/injector-subtitle.js
Normal file
3
src/injector-subtitle.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { XMLHttpRequestInjector } from "./injectors/xmlhttp";
|
||||||
|
|
||||||
|
XMLHttpRequestInjector();
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
import { XMLHttpRequestInjector } from "./subtitle/XMLHttpRequestInjector";
|
|
||||||
|
|
||||||
XMLHttpRequestInjector();
|
|
||||||
27
src/injectors/index.js
Normal file
27
src/injectors/index.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { browser } from "../libs/browser";
|
||||||
|
import { isExt } from "../libs/client";
|
||||||
|
import { injectExternalJs, injectInlineJs } from "../libs/injector";
|
||||||
|
import { shadowRootInjector } from "./shadowroot";
|
||||||
|
import { XMLHttpRequestInjector } from "./xmlhttp";
|
||||||
|
|
||||||
|
export const INJECTOR = {
|
||||||
|
subtitle: "injector-subtitle.js",
|
||||||
|
shadowroot: "injector-shadowroot.js",
|
||||||
|
};
|
||||||
|
|
||||||
|
const injectorMap = {
|
||||||
|
[INJECTOR.subtitle]: XMLHttpRequestInjector,
|
||||||
|
[INJECTOR.shadowroot]: shadowRootInjector,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function injectJs(name, id = "kiss-translator-inject-js") {
|
||||||
|
const injector = injectorMap[name];
|
||||||
|
if (!injector) return;
|
||||||
|
|
||||||
|
if (isExt) {
|
||||||
|
const src = browser.runtime.getURL(name);
|
||||||
|
injectExternalJs(src, id);
|
||||||
|
} else {
|
||||||
|
injectInlineJs(`(${injector})()`, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/injectors/shadowroot.js
Normal file
12
src/injectors/shadowroot.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
export const shadowRootInjector = () => {
|
||||||
|
try {
|
||||||
|
const orig = Element.prototype.attachShadow;
|
||||||
|
Element.prototype.attachShadow = function (...args) {
|
||||||
|
const root = orig.apply(this, args);
|
||||||
|
window.postMessage({ type: "KISS_SHADOW_ROOT_CREATED" }, "*");
|
||||||
|
return root;
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.log("shadowRootInjector", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
23
src/injectors/xmlhttp.js
Normal file
23
src/injectors/xmlhttp.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export const XMLHttpRequestInjector = () => {
|
||||||
|
try {
|
||||||
|
const originalOpen = XMLHttpRequest.prototype.open;
|
||||||
|
XMLHttpRequest.prototype.open = function (...args) {
|
||||||
|
const url = args[1];
|
||||||
|
if (typeof url === "string" && url.includes("timedtext")) {
|
||||||
|
this.addEventListener("load", function () {
|
||||||
|
window.postMessage(
|
||||||
|
{
|
||||||
|
type: "KISS_XHR_DATA_YOUTUBE",
|
||||||
|
url: this.responseURL,
|
||||||
|
response: this.responseText,
|
||||||
|
},
|
||||||
|
window.location.origin
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return originalOpen.apply(this, args);
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.log("XMLHttpRequestInjector", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
import { kissLog } from "./log";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class ShadowRootMonitor
|
|
||||||
* @description 通过覆写 Element.prototype.attachShadow 来监控页面上所有新创建的 Shadow DOM
|
|
||||||
*/
|
|
||||||
export default class ShadowRootMonitor {
|
|
||||||
/**
|
|
||||||
* @param {function(ShadowRoot): void} callback - 当一个新的 shadowRoot 被创建时调用的回调函数。
|
|
||||||
*/
|
|
||||||
constructor(callback) {
|
|
||||||
if (typeof callback !== "function") {
|
|
||||||
throw new Error("Callback must be a function.");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.callback = callback;
|
|
||||||
this.isMonitoring = false;
|
|
||||||
this.originalAttachShadow = Element.prototype.attachShadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始监控 shadowRoot 的创建。
|
|
||||||
*/
|
|
||||||
start() {
|
|
||||||
if (this.isMonitoring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const monitorInstance = this;
|
|
||||||
|
|
||||||
Element.prototype.attachShadow = function (...args) {
|
|
||||||
const shadowRoot = monitorInstance.originalAttachShadow.apply(this, args);
|
|
||||||
if (shadowRoot) {
|
|
||||||
try {
|
|
||||||
monitorInstance.callback(shadowRoot);
|
|
||||||
} catch (error) {
|
|
||||||
kissLog("Error in ShadowRootMonitor callback", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return shadowRoot;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.isMonitoring = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止监控,并恢复原始的 attachShadow 方法。
|
|
||||||
*/
|
|
||||||
stop() {
|
|
||||||
if (!this.isMonitoring) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Element.prototype.attachShadow = this.originalAttachShadow;
|
|
||||||
this.isMonitoring = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,6 @@ import {
|
|||||||
OPT_SPLIT_PARAGRAPH_TEXTLENGTH,
|
OPT_SPLIT_PARAGRAPH_TEXTLENGTH,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import interpreter from "./interpreter";
|
import interpreter from "./interpreter";
|
||||||
import ShadowRootMonitor from "./shadowRootMonitor";
|
|
||||||
import { clearFetchPool } from "./pool";
|
import { clearFetchPool } from "./pool";
|
||||||
import { debounce, scheduleIdle, genEventName, truncateWords } from "./utils";
|
import { debounce, scheduleIdle, genEventName, truncateWords } from "./utils";
|
||||||
import { apiTranslate } from "../apis";
|
import { apiTranslate } from "../apis";
|
||||||
@@ -31,6 +30,7 @@ import { createLoadingSVG } from "./svg";
|
|||||||
import { shortcutRegister } from "./shortcut";
|
import { shortcutRegister } from "./shortcut";
|
||||||
import { tryDetectLang } from "./detect";
|
import { tryDetectLang } from "./detect";
|
||||||
import { trustedTypesHelper } from "./trustedTypes";
|
import { trustedTypesHelper } from "./trustedTypes";
|
||||||
|
import { injectJs, INJECTOR } from "../injectors";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Translator
|
* @class Translator
|
||||||
@@ -278,6 +278,7 @@ export class Translator {
|
|||||||
#rule; // 规则
|
#rule; // 规则
|
||||||
#isInitialized = false; // 初始化状态
|
#isInitialized = false; // 初始化状态
|
||||||
#isJsInjected = false; // 注入用户JS
|
#isJsInjected = false; // 注入用户JS
|
||||||
|
#isShadowRootJsInjected = false; //
|
||||||
#mouseHoverEnabled = false; // 鼠标悬停翻译
|
#mouseHoverEnabled = false; // 鼠标悬停翻译
|
||||||
#enabled = false; // 全局默认状态
|
#enabled = false; // 全局默认状态
|
||||||
#runId = 0; // 用于中止过期的异步请求
|
#runId = 0; // 用于中止过期的异步请求
|
||||||
@@ -305,11 +306,13 @@ export class Translator {
|
|||||||
#hoveredNode = null; // 存储当前悬停的可翻译节点
|
#hoveredNode = null; // 存储当前悬停的可翻译节点
|
||||||
#boundMouseMoveHandler; // 鼠标事件
|
#boundMouseMoveHandler; // 鼠标事件
|
||||||
#boundKeyDownHandler; // 键盘事件
|
#boundKeyDownHandler; // 键盘事件
|
||||||
|
#windowMessageHandler = null;
|
||||||
|
|
||||||
|
#debouncedFindShadowRoot = null;
|
||||||
|
|
||||||
#io; // IntersectionObserver
|
#io; // IntersectionObserver
|
||||||
#mo; // MutationObserver
|
#mo; // MutationObserver
|
||||||
#dmm; // DebounceMouseMover
|
#dmm; // DebounceMouseMover
|
||||||
#srm; // ShadowRootMonitor
|
|
||||||
|
|
||||||
#rescanQueue = new Set(); // “脏容器”队列
|
#rescanQueue = new Set(); // “脏容器”队列
|
||||||
#isQueueProcessing = false; // 队列处理状态标志
|
#isQueueProcessing = false; // 队列处理状态标志
|
||||||
@@ -368,12 +371,12 @@ export class Translator {
|
|||||||
this.#io = this.#createIntersectionObserver();
|
this.#io = this.#createIntersectionObserver();
|
||||||
this.#mo = this.#createMutationObserver();
|
this.#mo = this.#createMutationObserver();
|
||||||
this.#dmm = this.#createDebounceMouseMover();
|
this.#dmm = this.#createDebounceMouseMover();
|
||||||
this.#srm = this.#createShadowRootMonitor();
|
|
||||||
|
|
||||||
// 监控shadowroot
|
this.#windowMessageHandler = this.#handleWindowMessage.bind(this);
|
||||||
if (this.#rule.hasShadowroot === "true") {
|
this.#debouncedFindShadowRoot = debounce(
|
||||||
this.#srm.start();
|
this.#findAndObserveShadowRoot.bind(this),
|
||||||
}
|
300
|
||||||
|
);
|
||||||
|
|
||||||
// 鼠标悬停翻译
|
// 鼠标悬停翻译
|
||||||
if (this.#setting.mouseHoverSetting.useMouseHover) {
|
if (this.#setting.mouseHoverSetting.useMouseHover) {
|
||||||
@@ -410,15 +413,41 @@ export class Translator {
|
|||||||
this.#startObserveRoot(root);
|
this.#startObserveRoot(root);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 查找现有的所有shadowroot
|
|
||||||
if (this.#rule.hasShadowroot === "true") {
|
if (this.#rule.hasShadowroot === "true") {
|
||||||
try {
|
this.#attachShadowRootListener();
|
||||||
this.#findAllShadowRoots().forEach((shadowRoot) => {
|
this.#findAndObserveShadowRoot();
|
||||||
this.#startObserveShadowRoot(shadowRoot);
|
}
|
||||||
});
|
}
|
||||||
} catch (err) {
|
|
||||||
kissLog("findAllShadowRoots", err);
|
#handleWindowMessage(event) {
|
||||||
}
|
if (event.data?.type === "KISS_SHADOW_ROOT_CREATED") {
|
||||||
|
this.#debouncedFindShadowRoot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachShadowRootListener() {
|
||||||
|
if (!this.#isShadowRootJsInjected) {
|
||||||
|
const id = "kiss-translator-inject-shadowroot-js";
|
||||||
|
injectJs(INJECTOR.shadowroot, id);
|
||||||
|
|
||||||
|
this.#isShadowRootJsInjected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("message", this.#windowMessageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
#removeShadowRootListener() {
|
||||||
|
window.removeEventListener("message", this.#windowMessageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找现有的所有shadowroot
|
||||||
|
#findAndObserveShadowRoot() {
|
||||||
|
try {
|
||||||
|
this.#findAllShadowRoots().forEach((shadowRoot) => {
|
||||||
|
this.#startObserveShadowRoot(shadowRoot);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
kissLog("findAllShadowRoots", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -611,13 +640,6 @@ export class Translator {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建shadowroot的回调
|
|
||||||
#createShadowRootMonitor() {
|
|
||||||
return new ShadowRootMonitor((shadowRoot) => {
|
|
||||||
this.#startObserveShadowRoot(shadowRoot);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 跟踪鼠标下的可翻译节点
|
// 跟踪鼠标下的可翻译节点
|
||||||
#handleMouseMove(event) {
|
#handleMouseMove(event) {
|
||||||
let targetNode = event.composedPath()[0];
|
let targetNode = event.composedPath()[0];
|
||||||
@@ -1527,6 +1549,8 @@ export class Translator {
|
|||||||
|
|
||||||
// 停止监听,重置参数
|
// 停止监听,重置参数
|
||||||
#resetOptions() {
|
#resetOptions() {
|
||||||
|
this.#removeShadowRootListener();
|
||||||
|
|
||||||
this.#io.disconnect();
|
this.#io.disconnect();
|
||||||
this.#mo.disconnect();
|
this.#mo.disconnect();
|
||||||
this.#viewNodes.clear();
|
this.#viewNodes.clear();
|
||||||
@@ -1697,7 +1721,6 @@ export class Translator {
|
|||||||
stop() {
|
stop() {
|
||||||
this.disable();
|
this.disable();
|
||||||
this.#resetOptions();
|
this.#resetOptions();
|
||||||
this.#srm.stop();
|
|
||||||
this.#disableMouseHover();
|
this.#disableMouseHover();
|
||||||
this.#removeInjector();
|
this.#removeInjector();
|
||||||
this.#isInitialized = false;
|
this.#isInitialized = false;
|
||||||
|
|||||||
@@ -1,158 +0,0 @@
|
|||||||
/**
|
|
||||||
* 修复程序类型
|
|
||||||
*/
|
|
||||||
export const FIXER_NONE = "-";
|
|
||||||
export const FIXER_BR = "br";
|
|
||||||
export const FIXER_BN = "bn";
|
|
||||||
export const FIXER_BR_DIV = "brToDiv";
|
|
||||||
export const FIXER_BN_DIV = "bnToDiv";
|
|
||||||
|
|
||||||
export const FIXER_ALL = [
|
|
||||||
FIXER_NONE,
|
|
||||||
FIXER_BR,
|
|
||||||
FIXER_BN,
|
|
||||||
FIXER_BR_DIV,
|
|
||||||
FIXER_BN_DIV,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复过的标记
|
|
||||||
*/
|
|
||||||
const fixedSign = "kiss-fixed";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 采用 `br` 换行网站的修复函数
|
|
||||||
* 目标是将 `br` 替换成 `p`
|
|
||||||
* @param {*} node
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function brFixer(node, tag = "p") {
|
|
||||||
if (node.hasAttribute(fixedSign)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
node.setAttribute(fixedSign, "true");
|
|
||||||
|
|
||||||
const gapTags = ["BR", "WBR"];
|
|
||||||
const newlineTags = [
|
|
||||||
"DIV",
|
|
||||||
"UL",
|
|
||||||
"OL",
|
|
||||||
"LI",
|
|
||||||
"H1",
|
|
||||||
"H2",
|
|
||||||
"H3",
|
|
||||||
"H4",
|
|
||||||
"H5",
|
|
||||||
"H6",
|
|
||||||
"P",
|
|
||||||
"HR",
|
|
||||||
"PRE",
|
|
||||||
"TABLE",
|
|
||||||
"BLOCKQUOTE",
|
|
||||||
];
|
|
||||||
|
|
||||||
let html = "";
|
|
||||||
node.childNodes.forEach(function (child, index) {
|
|
||||||
if (index === 0) {
|
|
||||||
html += `<${tag} class="kiss-p">`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gapTags.indexOf(child.nodeName) !== -1) {
|
|
||||||
html += `</${tag}><${tag} class="kiss-p">`;
|
|
||||||
} else if (newlineTags.indexOf(child.nodeName) !== -1) {
|
|
||||||
html += `</${tag}>${child.outerHTML}<${tag} class="kiss-p">`;
|
|
||||||
} else if (child.outerHTML) {
|
|
||||||
html += child.outerHTML;
|
|
||||||
} else if (child.textContent) {
|
|
||||||
html += child.textContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index === node.childNodes.length - 1) {
|
|
||||||
html += `</${tag}>`;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
node.innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function brDivFixer(node) {
|
|
||||||
return brFixer(node, "div");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 目标是将 `\n` 替换成 `p`
|
|
||||||
* @param {*} node
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function bnFixer(node, tag = "p") {
|
|
||||||
if (node.hasAttribute(fixedSign)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
node.setAttribute(fixedSign, "true");
|
|
||||||
node.innerHTML = node.innerHTML
|
|
||||||
.split("\n")
|
|
||||||
.map((item) => `<${tag} class="kiss-p">${item || " "}</${tag}>`)
|
|
||||||
.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
function bnDivFixer(node) {
|
|
||||||
return bnFixer(node, "div");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找、监听节点,并执行修复函数
|
|
||||||
* @param {*} selector
|
|
||||||
* @param {*} fixer
|
|
||||||
* @param {*} rootSelector
|
|
||||||
*/
|
|
||||||
function run(selector, fixer, rootSelector) {
|
|
||||||
const mutaObserver = new MutationObserver(function (mutations) {
|
|
||||||
mutations.forEach(function (mutation) {
|
|
||||||
mutation.addedNodes.forEach(function (addNode) {
|
|
||||||
if (addNode && addNode.querySelectorAll) {
|
|
||||||
addNode.querySelectorAll(selector).forEach(function (node) {
|
|
||||||
fixer(node);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let rootNodes = [document];
|
|
||||||
if (rootSelector) {
|
|
||||||
rootNodes = document.querySelectorAll(rootSelector);
|
|
||||||
}
|
|
||||||
|
|
||||||
rootNodes.forEach(function (rootNode) {
|
|
||||||
rootNode.querySelectorAll(selector).forEach(function (node) {
|
|
||||||
fixer(node);
|
|
||||||
});
|
|
||||||
mutaObserver.observe(rootNode, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复程序映射
|
|
||||||
*/
|
|
||||||
const fixerMap = {
|
|
||||||
[FIXER_BR]: brFixer,
|
|
||||||
[FIXER_BN]: bnFixer,
|
|
||||||
[FIXER_BR_DIV]: brDivFixer,
|
|
||||||
[FIXER_BN_DIV]: bnDivFixer,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行fixer
|
|
||||||
* @param {*} param0
|
|
||||||
*/
|
|
||||||
export function runFixer(selector, fixer = "-", rootSelector) {
|
|
||||||
try {
|
|
||||||
if (Object.keys(fixerMap).includes(fixer)) {
|
|
||||||
run(selector, fixerMap[fixer], rootSelector);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error(`[kiss-webfix run]: ${err.message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export const XMLHttpRequestInjector = () => {
|
|
||||||
const originalOpen = XMLHttpRequest.prototype.open;
|
|
||||||
XMLHttpRequest.prototype.open = function (...args) {
|
|
||||||
const url = args[1];
|
|
||||||
if (typeof url === "string" && url.includes("timedtext")) {
|
|
||||||
this.addEventListener("load", function () {
|
|
||||||
window.postMessage(
|
|
||||||
{
|
|
||||||
type: "KISS_XHR_DATA_YOUTUBE",
|
|
||||||
url: this.responseURL,
|
|
||||||
response: this.responseText,
|
|
||||||
},
|
|
||||||
window.location.origin
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return originalOpen.apply(this, args);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,18 +1,15 @@
|
|||||||
import { YouTubeInitializer } from "./YouTubeCaptionProvider.js";
|
import { YouTubeInitializer } from "./YouTubeCaptionProvider.js";
|
||||||
import { browser } from "../libs/browser.js";
|
|
||||||
import { isMatch } from "../libs/utils.js";
|
import { isMatch } from "../libs/utils.js";
|
||||||
import { DEFAULT_API_SETTING } from "../config/api.js";
|
import { DEFAULT_API_SETTING } from "../config/api.js";
|
||||||
import { DEFAULT_SUBTITLE_SETTING } from "../config/setting.js";
|
import { DEFAULT_SUBTITLE_SETTING } from "../config/setting.js";
|
||||||
import { injectExternalJs } from "../libs/injector.js";
|
|
||||||
import { logger } from "../libs/log.js";
|
import { logger } from "../libs/log.js";
|
||||||
import { XMLHttpRequestInjector } from "./XMLHttpRequestInjector.js";
|
import { injectJs, INJECTOR } from "../injectors/index.js";
|
||||||
import { injectInlineJs } from "../libs/injector.js";
|
|
||||||
|
|
||||||
const providers = [
|
const providers = [
|
||||||
{ pattern: "https://www.youtube.com", start: YouTubeInitializer },
|
{ pattern: "https://www.youtube.com", start: YouTubeInitializer },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function runSubtitle({ href, setting, isUserscript }) {
|
export function runSubtitle({ href, setting }) {
|
||||||
try {
|
try {
|
||||||
const subtitleSetting = setting.subtitleSetting || DEFAULT_SUBTITLE_SETTING;
|
const subtitleSetting = setting.subtitleSetting || DEFAULT_SUBTITLE_SETTING;
|
||||||
if (!subtitleSetting.enabled) {
|
if (!subtitleSetting.enabled) {
|
||||||
@@ -21,13 +18,8 @@ export function runSubtitle({ href, setting, isUserscript }) {
|
|||||||
|
|
||||||
const provider = providers.find((item) => isMatch(href, item.pattern));
|
const provider = providers.find((item) => isMatch(href, item.pattern));
|
||||||
if (provider) {
|
if (provider) {
|
||||||
const id = "kiss-translator-xmlHttp-injector";
|
const id = "kiss-translator-inject-subtitle-js";
|
||||||
if (isUserscript) {
|
injectJs(INJECTOR.subtitle, id);
|
||||||
injectInlineJs(`(${XMLHttpRequestInjector})()`, id);
|
|
||||||
} else {
|
|
||||||
const src = browser.runtime.getURL("injector.js");
|
|
||||||
injectExternalJs(src, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
const apiSetting =
|
const apiSetting =
|
||||||
setting.transApis.find(
|
setting.transApis.find(
|
||||||
|
|||||||
Reference in New Issue
Block a user