Miigon's Youtube script

useful enhancements for my own youtube enjoyments

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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);
})();