YouTube 播放速度記憶

自動切換到你預先設定的播放速度。

安裝腳本?
作者推薦腳本

您可能也會喜歡 Youtube HD Premium

安裝腳本
  1. // ==UserScript==
  2. // @name Youtube Remember Speed
  3. // @name:zh-TW YouTube 播放速度記憶
  4. // @name:zh-CN YouTube 播放速度记忆
  5. // @name:ja YouTube 再生速度メモリー
  6. // @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
  7. // @author ElectroKnight22
  8. // @namespace electroknight22_youtube_remember_playback_rate_namespace
  9. // @version 1.1.1
  10. // @match *://*.youtube.com/*
  11. // @exclude *://www.youtube.com/live_chat*
  12. // @grant GM.getValue
  13. // @grant GM.setValue
  14. // @grant GM.deleteValue
  15. // @grant GM.listValues
  16. // @grant GM_registerMenuCommand
  17. // @grant GM_unregisterMenuCommand
  18. // @license MIT
  19. // @description Automcatically switches to your pre-selected speed.
  20. // @description:zh-TW 自動切換到你預先設定的播放速度。
  21. // @description:zh-CN 自动切换到你预先设定的播放速度。
  22. // @description:ja 自動的に設定した再生速度に替わります。
  23. // ==/UserScript==
  24.  
  25. /*jshint esversion: 11 */
  26.  
  27. (function() {
  28. "use strict";
  29.  
  30. const DEBUG = false;
  31.  
  32. const DEFAULT_SETTINGS = {
  33. useNativeController: true,
  34. targetSpeed: 1
  35. };
  36.  
  37. const speeds = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
  38.  
  39. let userSettings = { ...DEFAULT_SETTINGS };
  40. let menuCommandIds = []; // To store main menu commands
  41. let menuOptionIds = []; // To store speed options
  42.  
  43. let doc = document, win = window;
  44.  
  45. function debugLog(message, shouldShow = true) {
  46. if (DEBUG && shouldShow) {
  47. console.log("YTRS DEBUG | " + message);
  48. }
  49. }
  50.  
  51. // Functions to set the playbackRate
  52. function setSpeed(targetSpeed) {
  53. debugLog("Mode: " + userSettings.useNativeController);
  54. debugLog("Trying to set speed to: " + targetSpeed + "x");
  55. userSettings.useNativeController? setSpeedNative(targetSpeed) : setSpeedHtml(targetSpeed);
  56. }
  57.  
  58. function setSpeedNative(targetSpeed) {
  59. let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
  60. if (!isValidVideo(ytPlayer)) return;
  61. ytPlayer.setPlaybackRate(targetSpeed);
  62.  
  63. }
  64.  
  65. function setSpeedHtml(targetSpeed) {
  66. try {
  67. let video = doc.querySelector('video');
  68. video.playbackRate = targetSpeed;
  69. } catch (error) {
  70. debugLog("[HTML MODE] Error when trying to set speed. Error: " + error);
  71. }
  72. }
  73.  
  74. function isValidVideo(ytPlayer) {
  75.  
  76. if (win.location.href.startsWith("https://www.youtube.com/shorts/")) {
  77. debugLog("Skipping Youtube Shorts");
  78. return false;
  79. }
  80.  
  81. if (!ytPlayer?.getAvailableQualityLabels()[0]) {
  82. debugLog("Video data missing");
  83. return false;
  84. }
  85.  
  86. return true;
  87. }
  88.  
  89. // functions to create the option menu
  90. function createSpeedMenu() {
  91. // Register the speed menu command
  92. menuCommandIds.push(GM_registerMenuCommand("Set Speed (show/hide)", () => {
  93. menuOptionIds.length ? removeSpeedMenuItems() : showSpeedMenuItems();
  94. }, {
  95. autoClose: false
  96. }));
  97.  
  98. // Register the dynamic controller command
  99. registerNativeSpeedControllerCommand();
  100. }
  101.  
  102. function registerNativeSpeedControllerCommand() {
  103. // Remove the old controller command if it exists
  104. if (menuCommandIds.length > 1) {
  105. GM_unregisterMenuCommand(menuCommandIds.pop());
  106. }
  107.  
  108. // Register the new controller command with the updated label
  109. const controllerCommandId = GM_registerMenuCommand(userSettings.useNativeController ? "Using Native Speed Controller (toggle)" : "Bypassing Native Speed Controller (toggle)", () => {
  110. userSettings.useNativeController = !userSettings.useNativeController;
  111. GM.setValue('useNativeController', userSettings.useNativeController);
  112. registerNativeSpeedControllerCommand(); // Update the menu item label
  113. }, {
  114. autoClose: false
  115. });
  116.  
  117. // Add the updated command ID to the list
  118. menuCommandIds.push(controllerCommandId);
  119.  
  120. if (menuOptionIds.length) {
  121. removeSpeedMenuItems();
  122. showSpeedMenuItems();
  123. }
  124. }
  125.  
  126. function showSpeedMenuItems() {
  127. removeSpeedMenuItems();
  128. let speedList = speeds;
  129. if (!userSettings.useNativeController) {
  130. speedList = [];
  131. for (let i = 0; i <= 16; i += 0.125) {
  132. speedList.push(i);
  133. }
  134. }
  135.  
  136. speedList.forEach((speed) => {
  137. let speedText = speed + "x";
  138. if (speed === userSettings.targetSpeed) {
  139. speedText += " (selected)";
  140. }
  141. const speedCommandId = GM_registerMenuCommand(speedText, () => {
  142. setSelectedSpeed(speed);
  143. }, {
  144. autoClose: false,
  145. });
  146. menuOptionIds.push(speedCommandId);
  147. });
  148. }
  149.  
  150. function removeSpeedMenuItems() {
  151. while (menuOptionIds.length) {
  152. GM_unregisterMenuCommand(menuOptionIds.pop());
  153. }
  154. }
  155.  
  156. function setSelectedSpeed(speed) {
  157. if (userSettings.targetSpeed == speed) return;
  158. userSettings.targetSpeed = speed;
  159. GM.setValue('targetSpeed', speed);
  160. removeSpeedMenuItems();
  161. showSpeedMenuItems();
  162. setSpeed(speed);
  163. }
  164.  
  165. // syncs the user's settings on load
  166. async function applySettings() {
  167. try {
  168. const storedValues = await GM.listValues();
  169.  
  170. await Promise.all(Object.entries(DEFAULT_SETTINGS).map(async ([key, value]) => {
  171. if (!storedValues.includes(key)) {
  172. await GM.setValue(key, value);
  173. }
  174. }));
  175.  
  176. await Promise.all(storedValues.map(async key => {
  177. if (!(key in DEFAULT_SETTINGS)) {
  178. await GM.deleteValue(key);
  179. }
  180. }));
  181.  
  182. await Promise.all(
  183. storedValues.map(key => GM.getValue(key).then(value => [key, value]))
  184. ).then(keyValuePairs => keyValuePairs.forEach(([newKey, newValue]) => {
  185. userSettings[newKey] = newValue;
  186. }));
  187.  
  188. debugLog(Object.entries(userSettings).map(([key, value]) => key + ": " + value).join(", "));
  189. } catch (error) {
  190. debugLog("Error when applying settings: " + error.message);
  191. }
  192. }
  193.  
  194. function main() {
  195. if (win.self == win.top) { createSpeedMenu(); }
  196. setSpeed(userSettings.targetSpeed);
  197. win.addEventListener("loadstart", () => { setSpeed(userSettings.targetSpeed); }, true);
  198. }
  199.  
  200. applySettings().then(main);
  201. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址