YouTube: Stop Automatic Video Playback

Stop automatic video playback everywhere. Works on first page load & after navigating.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

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

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name            YouTube: Stop Automatic Video Playback
// @namespace       org.sidneys.userscripts
// @homepage        https://gist.githubusercontent.com/sidneys/02a9025ae1f23aefe1f4ea02e78b0ac8/raw/
// @version         4.7.3
// @description     Stop automatic video playback everywhere. Works on first page load & after navigating.
// @author          sidneys
// @icon            https://www.youtube.com/favicon.ico
// @noframes
// @match           http*://www.youtube.com/*
// @require         https://greatest.deepsurf.us/scripts/38888-greasemonkey-color-log/code/Greasemonkey%20%7C%20Color%20Log.js
// @run-at          document-start
// ==/UserScript==


/**
 * ESLint
 * @global
 */
/* global Debug */
Debug = false


/**
 * Applicable URL paths
 * @default
 * @constant
 */
const urlPathList = [
    '/channel',
    '/watch'
]


/**
 * YouTube API Player States
 * @constant
 * @enum
 */
const PLAYERSTATE = {
    '-1': 'UNSTARTED',
    0: 'ENDED',
    1: 'PLAYING',
    2: 'PAUSED',
    3: 'BUFFERING',
    5: 'CUED'
}


/**
 * Generate a method name for an event name using the DOM convention ("on" + Event Name)
 * @param {String} eventName - Event name (e.g. 'Click')
 * @returns {String} - Method name (e.g. 'onclick')
 */
let getHandlerMethodNameForEventName = eventName => `on${eventName.toLowerCase()}`

/**
 * Lookup the first <video> Element
 * @returns {Element} - <video> Element
 */
let getVideoElement = () => document.querySelector('video')

/**
 * Lookup YouTube Video Player through the DOM
 * @returns {Object} - YouTube Video Player
 */
let getYoutubePlayer = () => {
    console.debug('getYoutubePlayer')

    // Lookup Player element
    const playerElement = document.querySelector('ytd-player')

    // Return the property containing the Player API
    return playerElement && playerElement.player_
}

/**
 * Stop playback on YouTube via the Player API
 * @param {Object} youtubePlayer - YouTube Video Player API
 */
let stopYoutubePlayerPlayback = (youtubePlayer) => {
    console.debug('stopYoutubePlayerPlayback')

    // Get YouTube Video element
    const videoElement = getVideoElement()

    // Playback event types to watch
    const eventTypeList = [ 'play', 'playing', 'timeupdate' ]

    // Iterate playback event types
    eventTypeList.forEach((eventType, eventTypeIndex) => {

        // Playback "Stopper" method, each playback event
        let eventHandler = () => {
            console.debug(`videoElement#${eventType}`)

            // Remove all "Stopper" event handlers by deleting <video>#onplay, <video>#onplaying, <video>#ontimeupdate
            eventTypeList.forEach((eventType) => {
                const handlerMethodName = getHandlerMethodNameForEventName(eventType)

                delete videoElement[handlerMethodName]
                videoElement[handlerMethodName] = null

                // DEBUG
                console.debug('videoElement', 'removing event handler method:', handlerMethodName)
            })

            // Lookup YouTube Player state
            const playerState = youtubePlayer.getPlayerState()

            // Stop video (if it is not already paused)
            if (youtubePlayer.getPlayerState() !== 2) {
                youtubePlayer.pauseVideo()

                // Status
                console.info('Stopped automatic video playback', 'during the', PLAYERSTATE[playerState], 'phase')

                // DEBUG
                console.debug('stopYoutubePlayerPlayback', 'eventType:', eventType, 'playerState:', `${playerState} (${PLAYERSTATE[playerState]})`)
            }
        }

        // Add event handler to video element
        const handlerMethodName = getHandlerMethodNameForEventName(eventType)
        videoElement[handlerMethodName] = eventHandler
    })
}


/**
 * Init
 */
let init = () => {
    console.info('init')

    // Verify URL path
    if (!urlPathList.some(urlPath => window.location.pathname.startsWith(urlPath))) { return }

    // Initiate lookup loop
    let requestId
    let lookup = () => {
        // Lookup YouTube Player
        const youtubePlayer = getYoutubePlayer()

        // Is 1. the Player API available,  2. the Player ready?
        if (!youtubePlayer || (youtubePlayer && !youtubePlayer.isReady())) {
            // DEBUG
            console.debug('❌ YouTube Player API unavailable or Player not ready yet.')

            // Skip loop
            requestId = window.requestAnimationFrame(lookup)

            return
        }

        // Stop Playback
        stopYoutubePlayerPlayback(youtubePlayer)

        // DEBUG
        console.debug('✅ YouTube Player API available and Player ready.')

        // End loop
        window.cancelAnimationFrame(requestId)
    }

    // Initiate loop
    requestId = window.requestAnimationFrame(lookup)
}


/**
 * Handle in-page navigation (modern YouTube)
 * @listens window:Event#yt-navigate-finish
 */
window.addEventListener('yt-navigate-finish', () => {
    console.debug('window#yt-navigate-finish')

    init()
})