// ==UserScript== // @name YouTube Playback Speed Buttons // @name:zh-CN YouTube 播放速度按钮 // @name:zh-HK YouTube 播放速度按鈕 // @description Adds playback speed buttons to youtube player control bar. // @description:zh-CN 在 YouTube 播放器控制栏中添加播放速度按钮。 // @description:zh-HK 在 YouTube 播放器控制列中加入播放速度按鈕。 // @version 1.1.2 // @license MIT // @author bowencool // @match https://www.youtube.com/* // @namespace https://www.youtube.com/ // @author bowencool // @license MIT // @homepageURL https://greasyfork.org/scripts/475864 // @supportURL https://github.com/bowencool/Tampermonkey-Scripts/issues // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @run-at document-end // @require https://cdn.jsdelivr.net/gh/bowencool/Tampermonkey-Scripts@f59cc91442dd34eb28e0d270486da5c7ac8d2d50/shared/waitForElementToExist.js // @grant GM_addStyle // ==/UserScript== "use strict"; const language = navigator.language.toLowerCase(); const isTraditionalChinese = language.startsWith("zh-hant") || /^zh-(tw|hk|mo)/.test(language); const labels = isTraditionalChinese ? { faster: "加快 10%", reset: "重設為 1 倍速", slower: "減慢 10%" } : language.startsWith("zh") ? { faster: "加快 10%", reset: "恢复为 1 倍速", slower: "减慢 10%" } : { faster: "10% faster", reset: "Reset to 1x", slower: "10% slower" }; async function main() { const menuR = await waitForElementToExist(".ytp-right-controls-left"); const video = await waitForElementToExist(".html5-main-video"); if (window.trustedTypes && window.trustedTypes.createPolicy) { window.trustedTypes.createPolicy("default", { createHTML: (string, sink) => string, }); } GM_addStyle(`.speed-button svg { padding: 0!important; }`); const storedPlaybackRate = parseFloat( sessionStorage.getItem("playback-rate"), 10 ); if (storedPlaybackRate > 0) { video.playbackRate = storedPlaybackRate; } const fasterButton = document.createElement("button"); fasterButton.setAttribute("aria-label", labels.faster); fasterButton.title = labels.faster; fasterButton.innerHTML = window.trustedTypes.defaultPolicy .createHTML``; fasterButton.classList.add("ytp-button", "speed-button"); fasterButton.onclick = () => { const speed = Math.ceil(video.playbackRate * 11) / 10; console.log(speed); video.playbackRate = speed; sessionStorage.setItem("playback-rate", speed); }; menuR.prepend(fasterButton); const resetButton = document.createElement("button"); resetButton.setAttribute("aria-label", labels.reset); resetButton.title = labels.reset; resetButton.innerHTML = window.trustedTypes.defaultPolicy .createHTML``; resetButton.classList.add("ytp-button", "speed-button"); resetButton.onclick = () => { video.playbackRate = 1; sessionStorage.removeItem("playback-rate"); }; menuR.prepend(resetButton); const slowerButton = document.createElement("button"); slowerButton.setAttribute("aria-label", labels.slower); slowerButton.title = labels.slower; slowerButton.innerHTML = window.trustedTypes.defaultPolicy .createHTML``; slowerButton.classList.add("ytp-button", "speed-button"); slowerButton.onclick = () => { const speed = Math.floor(video.playbackRate * 9) / 10; console.log(speed); if (speed === 0) return; video.playbackRate = speed; sessionStorage.setItem("playback-rate", speed); }; menuR.prepend(slowerButton); } main();