Last active
April 16, 2026 04:02
-
-
Save sidneys/02a9025ae1f23aefe1f4ea02e78b0ac8 to your computer and use it in GitHub Desktop.
Userscript | YouTube: Stop Automatic Video Playback
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==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://greasyfork.org/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() | |
| }) |
it doesn't block autoplay current video on chrome
Still seems to work for me
This doesn't seem to block autoplay in playlists, remove the pp param from url sometimes works, but breaks after any action (pause/resume, etc.). Probably gotta disable ended, progress, resize, waiting event listeners too
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
do you by any chance have a version that doesn't automatically pause the video every time? It does that on mine for some reason.