自动切换到你预先设定的播放速度。
当前为
// ==UserScript==
// @name Youtube Remember Speed
// @name:zh-TW YouTube 播放速度記憶
// @name:zh-CN YouTube 播放速度记忆
// @name:ja YouTube 再生速度メモリー
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAqhJREFUaEPtmc9rE0EUxz+DjSh6UAQRxP4F9uhBRKjipef+FwqtoZdYEk3U4jGn0FJ6KrQnj6X0EKVKKIi9tAotPZSCYilFoq0/sK1Z92V329XGENiZSRZ2LtllZ9+8z/e9ncy8UcS8qZj7TwLQ7ggmEUgiEFGB/6aQAxeBq8Al4GxonDPAydD9+dB1qkFfefy9iZ9fgRrwC/jh96v6vz+Bj8B7BduNbBwDcOA6UABuAyciCqTr9d/ACxf0oYI3YaOHAA71KfWpq8QDF6BTP27H9/GRArk+ctSBZ0BGl2SG7YwoyB4COF66lDtY+X/1EPVvKXhVTxUHKsANw6rpNl9RcFM50A1sxEj9QAiJQrcA9LvT5XPd8liy1y8Ad4GSpQF1D3NPAO4DRd2WLdlL6wUYH4dKBSYnLfmPZoDZWejrg/l5GByE5WXTIIYAxO1aDaamYGgIthsuY3TAGQQI3KtWoVCAUgkODnQ4HbZhASAYbnUV0mmYm9MJYREgcHtmxvs+1td1gLQBQNze24OxMchmYXc3CkibAOQDl6k2k4GtrZgBLC56KbSwEMXx4F2LEdjchHweJia8KVZPswCwvw+jo5DLwc6OHrePrBgGKJdhYABWVnQ7bjiF1ta8OV+WFmab5ghMT8PSEhSL3lRpvmkGSKVAct5eqwPEfkMT+y3lZeBDbDf1kq6xLqv4AL3AyxhFQUoqvQpeh2ujI+46cdjeBBJppL9Li34UBCYP5Do4ErKIeiLV82PF3UAPB64Bj4E7biW4K5JO+l6WvajUbqW8/jZsttkBxwWgB7gCnPZfCg4z5P6UH6lzTfyUgxGp7ctBRdBkBxNsjiWXv4Seyd93+DDkG/AJeKfgc6NxOvUcoOXYJQAtS2WoYxIBQ8K2bDaJQMtSGer4B8aT1sve/dr7AAAAAElFTkSuQmCC
// @author ElectroKnight22
// @namespace electroknight22_youtube_remember_playback_rate_namespace
// @version 1.1.1
// @match *://*.youtube.com/*
// @exclude *://www.youtube.com/live_chat*
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.deleteValue
// @grant GM.listValues
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @license MIT
// @description Automcatically switches to your pre-selected speed.
// @description:zh-TW 自動切換到你預先設定的播放速度。
// @description:zh-CN 自动切换到你预先设定的播放速度。
// @description:ja 自動的に設定した再生速度に替わります。
// ==/UserScript==
/*jshint esversion: 11 */
(function() {
"use strict";
const DEBUG = false;
const DEFAULT_SETTINGS = {
useNativeController: true,
targetSpeed: 1
};
const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
let userSettings = { ...DEFAULT_SETTINGS };
let menuCommandIds = []; // To store main menu commands
let menuOptionIds = []; // To store speed options
let doc = document, win = window;
function debugLog(message, shouldShow = true) {
if (DEBUG && shouldShow) {
console.log("YTRS DEBUG | " + message);
}
}
// Functions to set the playbackRate
function setSpeed(targetSpeed) {
debugLog("Mode: " + userSettings.useNativeController);
debugLog("Trying to set speed to: " + targetSpeed + "x");
userSettings.useNativeController? setSpeedNative(targetSpeed) : setSpeedHtml(targetSpeed);
}
function setSpeedNative(targetSpeed) {
let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
if (!isValidVideo(ytPlayer)) return;
ytPlayer.setPlaybackRate(targetSpeed);
}
function setSpeedHtml(targetSpeed) {
try {
let video = doc.querySelector('video');
video.playbackRate = targetSpeed;
} catch (error) {
debugLog("[HTML MODE] Error when trying to set speed. Error: " + error);
}
}
function isValidVideo(ytPlayer) {
if (win.location.href.startsWith("https://www.youtube.com/shorts/")) {
debugLog("Skipping Youtube Shorts");
return false;
}
if (!ytPlayer?.getAvailableQualityLabels()[0]) {
debugLog("Video data missing");
return false;
}
return true;
}
// functions to create the option menu
function createSpeedMenu() {
// Register the speed menu command
menuCommandIds.push(GM_registerMenuCommand("Set Speed (show/hide)", () => {
menuOptionIds.length ? removeSpeedMenuItems() : showSpeedMenuItems();
}, {
autoClose: false
}));
// Register the dynamic controller command
registerNativeSpeedControllerCommand();
}
function registerNativeSpeedControllerCommand() {
// Remove the old controller command if it exists
if (menuCommandIds.length > 1) {
GM_unregisterMenuCommand(menuCommandIds.pop());
}
// Register the new controller command with the updated label
const controllerCommandId = GM_registerMenuCommand(userSettings.useNativeController ? "Using Native Speed Controller (toggle)" : "Bypassing Native Speed Controller (toggle)", () => {
userSettings.useNativeController = !userSettings.useNativeController;
GM.setValue('useNativeController', userSettings.useNativeController);
registerNativeSpeedControllerCommand(); // Update the menu item label
}, {
autoClose: false
});
// Add the updated command ID to the list
menuCommandIds.push(controllerCommandId);
if (menuOptionIds.length) {
removeSpeedMenuItems();
showSpeedMenuItems();
}
}
function showSpeedMenuItems() {
removeSpeedMenuItems();
let speedList = speeds;
if (!userSettings.useNativeController) {
speedList = [];
for (let i = 0; i <= 16; i += 0.125) {
speedList.push(i);
}
}
speedList.forEach((speed) => {
let speedText = speed + "x";
if (speed === userSettings.targetSpeed) {
speedText += " (selected)";
}
const speedCommandId = GM_registerMenuCommand(speedText, () => {
setSelectedSpeed(speed);
}, {
autoClose: false,
});
menuOptionIds.push(speedCommandId);
});
}
function removeSpeedMenuItems() {
while (menuOptionIds.length) {
GM_unregisterMenuCommand(menuOptionIds.pop());
}
}
function setSelectedSpeed(speed) {
if (userSettings.targetSpeed == speed) return;
userSettings.targetSpeed = speed;
GM.setValue('targetSpeed', speed);
removeSpeedMenuItems();
showSpeedMenuItems();
setSpeed(speed);
}
// syncs the user's settings on load
async function applySettings() {
try {
const storedValues = await GM.listValues();
await Promise.all(Object.entries(DEFAULT_SETTINGS).map(async ([key, value]) => {
if (!storedValues.includes(key)) {
await GM.setValue(key, value);
}
}));
await Promise.all(storedValues.map(async key => {
if (!(key in DEFAULT_SETTINGS)) {
await GM.deleteValue(key);
}
}));
await Promise.all(
storedValues.map(key => GM.getValue(key).then(value => [key, value]))
).then(keyValuePairs => keyValuePairs.forEach(([newKey, newValue]) => {
userSettings[newKey] = newValue;
}));
debugLog(Object.entries(userSettings).map(([key, value]) => key + ": " + value).join(", "));
} catch (error) {
debugLog("Error when applying settings: " + error.message);
}
}
function main() {
if (win.self == win.top) { createSpeedMenu(); }
setSpeed(userSettings.targetSpeed);
win.addEventListener("loadstart", () => { setSpeed(userSettings.targetSpeed); }, true);
}
applySettings().then(main);
})();