Created
February 14, 2026 16:32
-
-
Save Staubgeborener/40b324225b30aef29be4131d4c325e05 to your computer and use it in GitHub Desktop.
Violentmonkey userscript – Auto-enables YouTube theater mode when the browser window is on a portrait (vertical) monitor
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 Auto Theater Mode on Portrait Monitor | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.0 | |
| // @description Automatically enables YouTube theater mode when the browser window is on a portrait (vertical) monitor | |
| // @match https://www.youtube.com/* | |
| // @grant none | |
| // @run-at document-idle | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| let lastState = null; | |
| function isPortrait() { | |
| return window.outerHeight > window.outerWidth; | |
| } | |
| function isWatchPage() { | |
| return location.pathname === '/watch'; | |
| } | |
| function isTheaterMode() { | |
| const ytdWatch = document.querySelector('ytd-watch-flexy'); | |
| if (!ytdWatch) return false; | |
| return ytdWatch.hasAttribute('theater'); | |
| } | |
| function clickTheaterButton() { | |
| const btn = document.querySelector('.ytp-size-button'); | |
| if (btn) { | |
| btn.click(); | |
| console.log('[YT Portrait Theater] Theater button clicked'); | |
| } | |
| } | |
| function update() { | |
| if (!isWatchPage()) return; | |
| const portrait = isPortrait(); | |
| const theater = isTheaterMode(); | |
| // Only react when the state actually changes | |
| if (portrait === lastState) return; | |
| lastState = portrait; | |
| if (portrait && !theater) { | |
| // Window is on portrait monitor → enable theater mode | |
| console.log('[YT Portrait Theater] Portrait detected → enabling theater mode'); | |
| clickTheaterButton(); | |
| } else if (!portrait && theater) { | |
| // Window is on landscape monitor → disable theater mode | |
| console.log('[YT Portrait Theater] Landscape detected → disabling theater mode'); | |
| clickTheaterButton(); | |
| } | |
| } | |
| // Wait until YouTube's player is fully loaded | |
| function waitForPlayer() { | |
| const observer = new MutationObserver(() => { | |
| if (document.querySelector('.ytp-size-button')) { | |
| observer.disconnect(); | |
| // Short delay to let YouTube finish initializing | |
| setTimeout(update, 1000); | |
| } | |
| }); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| } | |
| // Check when window is resized (fires when moving between monitors with different resolutions) | |
| window.addEventListener('resize', () => { | |
| clearTimeout(window._ytPortraitTimer); | |
| window._ytPortraitTimer = setTimeout(update, 500); | |
| }); | |
| // Handle YouTube SPA navigation | |
| const origPushState = history.pushState; | |
| history.pushState = function () { | |
| origPushState.apply(this, arguments); | |
| lastState = null; | |
| setTimeout(() => waitForPlayer(), 1000); | |
| }; | |
| window.addEventListener('popstate', () => { | |
| lastState = null; | |
| setTimeout(() => waitForPlayer(), 1000); | |
| }); | |
| // Periodic check in case window is dragged between monitors without triggering a resize event | |
| setInterval(update, 3000); | |
| // Initial start | |
| waitForPlayer(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment