您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
useful enhancements for my own youtube enjoyments
// ==UserScript== // @name Miigon's Youtube script // @namespace https://blog.miigon.net/ // @version 0.6 // @description useful enhancements for my own youtube enjoyments // @author Miigon // @match https://www.youtube.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @grant none // @license MIT // ==/UserScript== /* Long press right arrow key to speed up video playback */ const RIGHT_ARROW_SPEEDUP_PRESS_TIME_MS = 500; // key hold time before speeding up const SPEED_UP_PLAYBACK_RATE = 3; /* Seeking in youtube shorts */ const SHORTS_SEEK_SECS = 5; (function() { 'use strict'; let mlog = (...args)=>{console.log("miigon's ytb script:", ...args)} let right_pressed = false; let is_speeding_up = false; let speeding_timeout = -1; // timeout waiting before starting speeding up let last_playback_rate = 1; let is_shorts = () => window.location.href.includes("/shorts/"); let is_editing = () => document.activeElement.contentEditable == "true"; // youtube uses javascript to navigate around. // so cached_player is only valid if the page is still the same. let cached_player_href = null; let cached_player = null; let getPlayerElement = () => { if(window.location.href == cached_player_href && cached_player) { return cached_player; } mlog("invalidate player element cache") cached_player = null; let ytd_player = [...document.getElementsByTagName("ytd-player")]; if(is_shorts()) { cached_player = ytd_player.find(v=>v.className.indexOf("ytd-shorts")!=-1); } else { // normal full-length video cached_player = ytd_player.find(v=> v.className.indexOf("preview") == -1 && v.className.indexOf("ytd-shorts") == -1 ); } if(cached_player != null) { cached_player_href = window.location.href; } return cached_player; } let getPlayer = () => getPlayerElement().getPlayer(); let getPlayerVideoTag = () => getPlayerElement().getElementsByTagName("video")[0]; document.addEventListener("keydown", (e)=>{ let used = false; // skip hotkeys when editing comment etc. if(is_editing()) return; if(e.key === "ArrowLeft") { // enables left seeking in shorts // ArrowRight is handled in keyup instead of keydown. if(is_shorts()){ getPlayer().seekBy(-SHORTS_SEEK_SECS); } } if(e.miigon_ignore) { return; } if(e.key === "ArrowRight") { if(right_pressed == false){ right_pressed = true; mlog("right pressed"); speeding_timeout = setTimeout(()=>{ speeding_timeout = -1; is_speeding_up = true; let v = getPlayerVideoTag(); last_playback_rate = v.playbackRate; v.playbackRate = SPEED_UP_PLAYBACK_RATE; mlog("speeding up"); used = true; }, RIGHT_ARROW_SPEEDUP_PRESS_TIME_MS); } used = true; } if(used){ e.stopPropagation(); e.preventDefault(); } }, /*useCapture*/true); document.addEventListener("keyup", (e)=>{ let used = false; // skip hotkeys when editing comment etc. if(is_editing()) return; if(e.key === "ArrowRight") { right_pressed = false; if(speeding_timeout != -1) { // keyup before speeding up begins clearTimeout(speeding_timeout); speeding_timeout = -1; if(is_shorts()){ // shorts, so simulating a right arrow keypress wont work // tell the player to seek directly. // this enables right seeking in shorts getPlayer().seekBy(SHORTS_SEEK_SECS); } else { // normal video // dispatch a normal right arrow keypress event. let event = new KeyboardEvent("keydown", {keyCode: 39}) event.miigon_ignore = true; // the script should not process this event document.dispatchEvent(event); } } if(is_speeding_up) { // keyup after speeding up begins is_speeding_up = false; mlog("stop speeding up"); getPlayerVideoTag().playbackRate = last_playback_rate; used = true; } } if(used){ e.stopPropagation(); e.preventDefault(); } }, /*useCapture*/true); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址