// ==UserScript== // @name Youtube Subtitle // @namespace https://greasyfork.org // @version 2.0.0 // @description 打开中文字幕和解说词,效果等同于双语字幕。 // @author szdailei@gmail.com // @source https://github.com/szdailei/GM-scripts // @match https://www.youtube.com/* // @run-at document-start // @downloadURL none // ==/UserScript== 'use strict'; /** require: Trigger the event yt-navigate-finish. That's a special event in www.youtube.com, happens when open link in an exsit tab. ensure: Meet one of the conditions as the following order: 1. If the video is not played, exit. 2. If there isn't subtitles menu, exit. 3. If there isn't subtitle, exit. 4. If Chinese subtitle is turned on, exit. 5. If there is Chinese subtitle, turn on it, and open transcript. 6. If there is non-Chinese subtitle and auto-translation, turn on the first subtitle and translate to Simp Chinese, and open transcript. 7. If there is non-Chinese subtitle without auto-translation, turn on the first subtitle, and open transcript. */ function onYtNavigateFinish() { var videoLoadCount, subtitleMenuLoadCount, translateToSimpChineseCount, moreActionsMenuLoadCount, openTranscriptCount; videoLoadCount = subtitleMenuLoadCount = translateToSimpChineseCount = moreActionsMenuLoadCount = openTranscriptCount = 0; const MAX_VIDEO_LOAD_COUNT = 10; const MAX_SUBTITLE_MENU_LOAD_COUNT = 10; const MAX_TRANS_TO_SIMP_CHINESE_COUNT = 5; const MAX_MORE_ACTIONS_MENU_LOAD_COUNT = 10; const MAX_OPEN_TRANSCRIPT_COUNT = 10; const CHINESE_SUBTITLE = 'Chinese Subtitle'; const NO_SUBTITLE = 'No Subtitle'; const NON_CHINESE_SUBTITLE = 'Non Chinese Subtitle'; const ON_SUBTITLE_MENU = 'On Subtitle Menu'; function turnOnSubtitle() { if (videoLoadCount === MAX_VIDEO_LOAD_COUNT) { return; } var videos = document.getElementsByTagName('video'); if (videos !== null) { var video = videos.item(0); if (video !== null) { video.play(); onVideoPlayed(); return; } } videoLoadCount++; setTimeout(onYtNavigateFinish, 1000); } function onVideoPlayed() { if (subtitleMenuLoadCount === MAX_SUBTITLE_MENU_LOAD_COUNT) { return; } var subtitlesButtons = document.getElementsByClassName('ytp-subtitles-button'); if (subtitlesButtons !== null) { var subtitlesButton = subtitlesButtons[0]; if ( subtitlesButton !== undefined && subtitlesButton !== null && subtitlesButton.getAttribute('aria-pressed') !== null ) { if (subtitlesButton.getAttribute('aria-pressed') === false) { subtitlesButton.click(); } onSubtitlesMenuLoaded(); return; } } subtitleMenuLoadCount++; setTimeout(onVideoPlayed, 1000); } function onSubtitlesMenuLoaded() { clickSettingsButton(); var turnOnChineseSubtitleResult = turnOnChineseSubtitle(); clickSettingsButton(); if (turnOnChineseSubtitleResult === NON_CHINESE_SUBTITLE) { translateToSimpChinese(); } if (turnOnChineseSubtitleResult !== NO_SUBTITLE) { openTranscript(); } } function clickSettingsButton() { var settingsButtons = document.getElementsByClassName('ytp-settings-button'); var settingsButton = settingsButtons[0]; settingsButton.click(); } function enterSubtitleMenu() { var menuItems = document.querySelectorAll('[role="menuitem"]'); var length = menuItems.length; for (var i = 0; i < length; i++) { var innerText = menuItems[i].innerText; if (innerText.indexOf('字幕') !== -1) { if (innerText.indexOf('中文') !== -1) { return CHINESE_SUBTITLE; } else { menuItems[i].click(); return ON_SUBTITLE_MENU; } } } } function turnOnChineseSubtitle() { var enterSubtitleMenuResult = enterSubtitleMenu(); if (enterSubtitleMenuResult === CHINESE_SUBTITLE) { return; } var menuItemRadios = document.querySelectorAll('[role="menuitemradio"]'); var length = menuItemRadios.length; var firstSubtitleIndex = 0; for (var i = 0; i < length; i++) { var innerText = menuItemRadios[i].innerText; if (innerText.indexOf('添加字幕') !== -1 || innerText.indexOf('关闭') !== -1) { continue; } firstSubtitleIndex = i; if (innerText.indexOf('中文') !== -1) { menuItemRadios[i].click(); return CHINESE_SUBTITLE; } } if (firstSubtitleIndex === 0) { return NO_SUBTITLE; } menuItemRadios[firstSubtitleIndex].click(); return NON_CHINESE_SUBTITLE; } function translateToSimpChinese() { if (translateToSimpChineseCount === MAX_TRANS_TO_SIMP_CHINESE_COUNT) { return; } clickSettingsButton(); enterSubtitleMenu(); var menuItemRadios = document.querySelectorAll('[role="menuitemradio"]'); var length = menuItemRadios.length; if (menuItemRadios[length - 1].innerText === '自动翻译') { menuItemRadios[length - 1].click(); menuItemRadios = document.querySelectorAll('[role="menuitemradio"]'); length = menuItemRadios.length; for (var i = length - 1; i > -1; i--) { var innerText = menuItemRadios[i].innerText; if (innerText.indexOf('中文(简体)') !== -1) { menuItemRadios[i].click(); return; } } clickSettingsButton(); return; } clickSettingsButton(); translateToSimpChineseCount++; setTimeout(translateToSimpChinese, 1000); } function openTranscript() { if (moreActionsMenuLoadCount === MAX_MORE_ACTIONS_MENU_LOAD_COUNT) { return; } var result = clickMoreActionsMenuButton(); if (result === true) { clickOpenTranscriptButton(); return; } moreActionsMenuLoadCount++; setTimeout(openTranscript, 1000); } function clickMoreActionsMenuButton() { var dropdownTriggers = document.getElementsByClassName('dropdown-trigger'); if (dropdownTriggers !== null) { var length = dropdownTriggers.length; for (var i = 0; i < length; i++) { var button = dropdownTriggers[i].children[0]; if (button !== null && button.getAttribute('aria-label') === '其他操作') { button.click(); return true; } } } } function clickOpenTranscriptButton() { if (openTranscriptCount === MAX_OPEN_TRANSCRIPT_COUNT) { return; } var menuItems = document.querySelectorAll('[role="option"]'); if (menuItems !== null && menuItems.length >= 2) { var length = menuItems.length; if (menuItems[1].innerText.indexOf('打开解说词') !== -1) { menuItems[1].click(); return; } else { // Timeout, the more actions menu closed automaticly. Turn on again. clickMoreActionsMenuButton(); } } openTranscriptCount++; setTimeout(clickOpenTranscriptButton, 1000); } if (window.location.pathname.indexOf('/watch') === -1) { return; } // Turn on subtitle on https://www.youtube.com/watch?* turnOnSubtitle(); } /** require: The document is still loading ensure: addEventListener on yt-navigate-finish event. */ (function () { window.addEventListener('yt-navigate-finish', onYtNavigateFinish); })();