YouTube shorts seek forward/backward shortcut

Adds seek forward/backward shortcut buttons to shorts similair to how the default video player works. Additionaly also adds a shortcut to open the short in the default player.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         YouTube shorts seek forward/backward shortcut
// @namespace    https://greasyfork.org/en/users/954974-crill0
// @version      0.3
// @description  Adds seek forward/backward shortcut buttons to shorts similair to how the default video player works. Additionaly also adds a shortcut to open the short in the default player.
// @author       Crill0
// @license      MIT
// @match        *://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    /* Settings */
    const OPEN_SHORT_KEY = "o";
    const OPEN_SHORT_NEW_TAB = true;
    const FORWARD_KEY = "ArrowRight";
    const BACKWARD_KEY = "ArrowLeft";
    const SECONDS_TO_SEEK = 5;
    /* End Settings */

    waitForElm("#shorts-player").then((ytPlayer) => {
        const actions = {
            [OPEN_SHORT_KEY]: () => {ytPlayer.pauseVideo(); window.open(ytPlayer.getVideoUrl(), OPEN_SHORT_NEW_TAB ? '_blank' : '_top');},
            [FORWARD_KEY]: () => ytPlayer.seekBy(SECONDS_TO_SEEK),
            [BACKWARD_KEY]: () => ytPlayer.seekBy(-SECONDS_TO_SEEK)
        }

        const keysPressed = new Set();
        addEventListener("keydown", e => {
            const key = e.key;
            if (!ytPlayer.getVideoData().isListed // not on shorts page
                || e.target.nodeName == "INPUT" || e.target.id == "contenteditable-root" // target is input box
                || !actions[key] || keysPressed.has(key)) return;
            actions[key]();
            keysPressed.add(key);
        });
        addEventListener("keyup", e => keysPressed.delete(e.key));
        addEventListener("visibilitychange",() => keysPressed.clear()); // prevents keys not being removed when new tab is opened while key down
    });

    function waitForElm(selector) {
        return new Promise(resolve => {
            if (document.querySelector(selector)) {
                return resolve(document.querySelector(selector));
            }

            const observer = new MutationObserver(mutations => {
                if (document.querySelector(selector)) {
                    resolve(document.querySelector(selector));
                    observer.disconnect();
                }
            });

            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        });
    }
})();