自动翻译任何非指定语言字幕。
// ==UserScript==
// @name ACT.YouTube.DM.Auto-translate
// @name:zh-CN ACT.YouTube.DM.自动翻译
// @description Automatically translate any non-specified language Subtitles/CC.
// @description:zh-CN 自动翻译任何非指定语言字幕。
// @author ACTCD
// @version 20231108.1
// @license GPL-3.0-or-later
// @namespace ACTCD/Userscripts
// @supportURL https://github.com/ACTCD/Userscripts#contact
// @homepageURL https://github.com/ACTCD/Userscripts
// @match *://*.youtube.com/*
// @match *://www.youtube-nocookie.com/embed/*
// @grant none
// @inject-into content
// @run-at document-start
// ==/UserScript==
(function () {
"use strict";
const inline_script = () => {
const tlang = navigator.language || "zh-CN"; // Specified language // 指定语言
const cache = { req_url: null, obj_url: null };
const XMLHttpRequest_open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
const url = new URL(arguments[1], location.href);
if (url.pathname == "/api/timedtext") {
const lang = url.searchParams.get("lang");
if (lang && lang != tlang) {
const req_url = url.href;
if (req_url == cache.req_url) {
arguments[1] = cache.obj_url;
} else {
URL.revokeObjectURL(cache.obj_url);
this.addEventListener("load", (event) => {
cache.req_url = req_url;
cache.obj_url = URL.createObjectURL(
new Blob([this.responseText], { type: "application/json" }),
);
});
url.searchParams.set("tlang", tlang);
arguments[1] = url.href;
}
}
}
XMLHttpRequest_open.apply(this, arguments);
};
};
const div = document.createElement("div");
div.style.display = "none";
const shadowRoot = div.attachShadow({ mode: "closed" });
const script = document.createElement("script");
script.textContent = "(" + inline_script + ")();";
shadowRoot.append(script);
if (document.body) {
document.body.append(div);
} else {
new MutationObserver((mutationList, observer) => {
document.body && (observer.disconnect(), document.body.append(div));
}).observe(document, { subtree: true, childList: true });
}
})();