// ==UserScript== // @name YouTubeで自動翻訳字幕(日本語)を常にオン // @description B:再度試みる N.:次の動画 P,:前の動画 // @version 0.5 // @run-at document-idle // @match *://www.youtube.com/* // @grant none // @namespace https://greasyfork.org/users/181558 // @downloadURL none // ==/UserScript== (function() { const WAIT_PAGEOPEN_OFFSET = 0; // ミリ秒 不安定なら大きくする const ENABLE_EVENJAPANESE = 1; // 日本語タイトルの動画でも実行 const ENABLE_EVENEMBED = 1; // 埋め込み動画でも実行 const DISABLE_AUTO_GENERATED_JAPANESE = 1; // 自動生成の日本語しかなければ字幕をオフ const WAIT_EACHACTION = 300; // ミリ秒 不安定なら大きくする const verbose = 0; var per = (performance.now()) / 3; verb("performance.now:" + performance.now(), "wait_base:" + per + "ms"); var wait_pageOpen = (per > 1500 ? 1500 : per < 300 ? 300 : per) + WAIT_PAGEOPEN_OFFSET; verb("wait_pageOpen:" + wait_pageOpen + "ms"); document.addEventListener('keydown', function(e) { if (/input|textarea/i.test(e.target.tagName) == false) { var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key; if (key == "b") { toJP("forced"); e.preventDefault(); return false; } if (key == "n" || key == ".") { elecli(null, '//a[@class="ytp-next-button ytp-button" and @aria-label="次へ(SHIFT+n)"]|//a[@class="ytp-next-button ytp-button cleaned" and @role="button" and @aria-label="次へ(SHIFT+n)"]'); e.preventDefault(); return false; } if (key == "p" || key == ",") { elecli(null, '//a[@class="ytp-prev-button ytp-button" and @aria-label="前へ(SHIFT+p)"]|//a[@class="ytp-prev-button ytp-button cleaned" and @role="button" and @aria-label="前へ(SHIFT+p)"]'); e.preventDefault(); return false; } } }, false); var href = location.href; var observer = new MutationObserver(function(mutations) { if (href !== location.href) { href = location.href; run(wait_pageOpen * 3); } }); observer.observe(document, { childList: true, subtree: true }); if (window === parent) run(wait_pageOpen); for (let ele of elegeta('//div[@id="player"]/div/div/button[@aria-label="再生"]|//div[@id="player"]/div/div/button[@aria-label="Play"]')) { ele.addEventListener('click', () => { setTimeout(run, wait_pageOpen * 2) }); } return; function run(delay = 500) { verb("run"); setTimeout(function() { var title = eleget0('//h1/yt-formatted-string'); if (!(location.href.match(/\/embed/)) && (!title || !eleget0('//div[contains(@class,"ytp-right-controls")]/button[@aria-haspopup="true"]|//button[@class="ytp-button ytp-settings-button" and @data-tooltip-target-id="ytp-settings-button"]'))) { setTimeout(run, 100); return; } if (!ENABLE_EVENJAPANESE && title && title.innerText.match(/[\u30a0-\u30ff\u3040-\u309f\u3005-\u3006\u30e0-\u9fcf]+/)) return; // タイトルに日本語あるならやめる setTimeout(() => { toJP(), wait_pageOpen }); }, delay + ((window.navigator.userAgent.toLowerCase().indexOf('chrome') > -1) ? 200 : 0)); } function toJP(f = null) { if (!(location.href.match(ENABLE_EVENEMBED ? /:\/\/www\.youtube\.com\/watch\?|:\/\/www\.youtube\.com\/embed/ : /:\/\/www\.youtube\.com\/watch\?/))) return; if (eleget0('//button[@class="ytp-subtitles-button ytp-button" and @aria-pressed="true"]|//button[@class="ytp-subtitles-button ytp-button" and @aria-pressed="false"]')) { // 字幕ボタン elecli(f, '//button[@class="ytp-subtitles-button ytp-button" and @aria-label="字幕(c)" and @aria-pressed="false"]|//button[@class="ytp-subtitles-button ytp-button" and @aria-pressed="false"]', 1); // 字幕ボタン elecli(f, '//div[@class="ytp-right-controls"]/button[@aria-label="設定"]|//button[@class="ytp-button ytp-settings-button"]', 2); // 設定ボタン elecli(f, '//div[@class="ytp-menuitem-label"]/div/span[text()="字幕"]|//div[@class="ytp-menuitem-label"]/div/span[contains(text(),"Subtitles/CC")]', 3, "close", "smooth"); elecli(f, '//div[@class="ytp-menuitem-label" and text()="自動翻訳"]|//div[2]/div/div[@class="ytp-menuitem-label" and contains(text(),"Auto-translate")]', 4, "close", "instant"); elecli(f, '//div[@class="ytp-menuitem-label" and text()="日本語"]|//div[@class="ytp-menuitem-label" and text()="Japanese"]', 5, "close"); elecli(f, '//div[contains(@class,"ytp-right-controls")]/button[@aria-haspopup="true" and @aria-expanded="true"]|//button[@class="ytp-button ytp-settings-button" and @data-tooltip-target-id="ytp-settings-button" and @aria-expanded="true"]', 7, "blur"); } } function elecli(f, xpath, delay = 0, command = false, beha = null) { setTimeout(() => { if (!f && DISABLE_AUTO_GENERATED_JAPANESE) { var str = ""; for (let am of elegeta('//div[@class="ytp-menuitem-label"]')) { str += am.innerText }; verb(delay + ', //div[@class="ytp-menuitem-label"] .innerText: ' + str); if (str === 'オフ日本語 (自動生成)自動翻訳' || str === '自動再生アノテーション再生速度字幕 (1)画質字幕を追加オフ日本語 (自動生成)自動翻訳' || str === '自動再生再生速度字幕 (1)画質字幕を追加オフ日本語 (自動生成)自動翻訳' || str.match(/^(自動再生)?再生速度字幕 \(1\)画質オフ日本語 \(自動生成\)自動翻訳$|字幕を追加オフ日本語 \(自動生成\)自動翻訳$/)) { elecli(1, '//button[@class="ytp-subtitles-button ytp-button" and @aria-pressed="true"]'); return } } var ele = eleget0(xpath); verb(xpath, "...found : " + (elegeta(xpath).length)); if (ele) { for (let ele of elegeta(xpath)) { if (command == "focus") { ele.focus(); verb("...focused") } else { ele.click(); verb("...clicked") if (window != parent && beha) { let foc = eleget0('//div[@id="movie_player"]|//div[@id="player"]'); if (foc) foc.scrollIntoView({ behavior: beha, block: "center", inline: "center" }); } } } } else { verb("...not found"); if (command == "close") { elecli(f, '//div[contains(@class,"ytp-right-controls")]/button[@aria-haspopup="true" and @aria-expanded="true"]|//button[@class="ytp-button ytp-settings-button" and @data-tooltip-target-id="ytp-settings-button" and @aria-expanded="true"]'); } } if (command == "blur") elecli(f, '//div[@id="movie_player"]|//div[@id="player"]/div/div/video', 0, "focus"); }, delay * WAIT_EACHACTION); } function eleget0(xpath, node = document) { if (!xpath) return null; try { var ele = document.evaluate(xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); return ele.snapshotLength > 0 ? ele.snapshotItem(0) : ""; } catch (e) { return null; } } function elegeta(xpath, node = document) { var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); var array = []; for (var i = 0; i < ele.snapshotLength; i++) array[i] = ele.snapshotItem(i); return array; } function verb() { if (verbose) { for (let str of arguments) { console.log(str) } } } })()