Skip to content

Instantly share code, notes, and snippets.

@adityatelange
Forked from adisib/youtube_hd.user.js
Created June 3, 2021 17:23
Show Gist options
  • Select an option

  • Save adityatelange/f88b4f79f45b6d5c282073a16b6c0b2a to your computer and use it in GitHub Desktop.

Select an option

Save adityatelange/f88b4f79f45b6d5c282073a16b6c0b2a to your computer and use it in GitHub Desktop.

Revisions

  1. @adisib adisib revised this gist Jan 2, 2021. 1 changed file with 348 additions and 392 deletions.
    740 changes: 348 additions & 392 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,13 +3,8 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2020.09.26
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    // @include https://www.youtube.com/*
    // @include http://gaming.youtube.com/*
    // @include https://gaming.youtube.com/*
    // @version 2021.01.02
    // @match https://www.youtube.com/*
    // @noframes
    // @grant none
    // ==/UserScript==
    @@ -20,417 +15,378 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // Code supporting old layout will be removed only after the old layout stops existing entirely.

    // 2020.09.24
    // - Add a (hopefully temporary) workaround for a rare issue where users aren't given the option to sign in to view videos flagged as inappropriate.

    // 2020.09.26
    // - Fix potential script breakage from youtube's theater mode change function throwing exceptions.

    // 2021.01.02
    // - Script cleanup. Removes support for old version of youtube, since it seems to unfortunately be gone. This significantly reduces script size.


    (function() {
    "use strict";

    // --- SETTINGS -------

    // Target Resolution to always set to. If not available, the next best resolution will be used.
    const changeResolution = true;
    const targetRes = "hd1080";
    // Choices for targetRes are currently:
    // "highres" >= ( 8K / 4320p / QUHD )
    // "hd2880" = ( 5K / 2880p / UHD+ )
    // "hd2160" = ( 4K / 2160p / UHD )
    // "hd1440" = ( 1440p / QHD )
    // "hd1080" = ( 1080p / FHD )
    // "hd720" = ( 720p / HD )
    // "large" = ( 480p )
    // "medium" = ( 360p )
    // "small" = ( 240p )
    // "tiny" = ( 144p )

    // If changePlayerSize is true, then the video's size will be changed on the page
    // instead of using youtube's default (if theater mode is enabled).
    // If useCustomSize is false, then the player will be resized to try to match the target resolution.
    // If true, then it will use the customHeight variables (theater mode is always full page width).
    const changePlayerSize = false;
    const useCustomSize = false;
    const customHeight = 600;

    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded before theater can be set.
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    const flushBuffer = true;

    // Setting cookies can allow some operations to perform faster or without a delay (e.g. theater mode)
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    const allowCookies = false;

    // Tries to set the resolution as early as possible.
    // This might cause issues on youtube polymer layout, so disable if videos fail to load.
    // If videos load fine, leave as true or resolution may fail to set.
    const setResolutionEarly = true;

    // Enables a temporary work around for an issue where users can get the wrong youtube error screen
    // (Youtube has two of them for some reason and changing to theater mode moves the wrong one to the front)
    // Try disabling if you can't interact with the video or you think you are missing an error message.
    const enableErrorScreenWorkaround = true;

    // --------------------




    // --- GLOBALS --------


    const DEBUG = false;

    // Possible resolution choices (in decreasing order, i.e. highres is the best):
    const resolutions = ['highres', 'hd2880', 'hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny'];
    // youtube has to be at least 480x270 for the player UI
    const heights = [4320, 2880, 2160, 1440, 1080, 720, 480, 360, 270, 270];

    let doc = document, win = window;

    // ID of the most recently played video
    let recentVideo = "";

    let setHeight = 0;


    // --------------------


    function debugLog(message)
    {
    if (DEBUG)
    {
    console.log("YTHD | " + message);
    }
    }


    // --------------------


    // Used only for compatability with webextensions version of greasemonkey
    function unwrapElement(el)
    {
    if (el && el.wrappedJSObject)
    {
    return el.wrappedJSObject;
    }
    return el;
    }


    // --------------------


    // Get video ID from the currently loaded video (which might be different than currently loaded page)
    function getVideoIDFromURL(ytPlayer)
    {
    const idMatch = /(?:v=)([\w\-]+)/;
    let videoURL = ytPlayer.getVideoUrl();
    let id = idMatch.exec(videoURL)[1] || "ERROR: idMatch failed; youtube changed something";

    return id;
    }


    // --------------------


    // Attempt to set the video resolution to desired quality or the next best quality
    function setResolution(ytPlayer, resolutionList)
    {
    debugLog("Setting Resolution...");

    // Youtube doesn't return "auto" for auto, so set to make sure that auto is not set by setting
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes);
    }
    ytPlayer.setPlaybackQuality(targetRes);
    debugLog("Resolution Set To: " + targetRes);
    return;
    }

    "use strict";
    const end = resolutionList.length - 1;
    let nextBestIndex = Math.max(resolutionList.indexOf(targetRes), 0);
    let ytResolutions = ytPlayer.getAvailableQualityLevels();
    debugLog("Available Resolutions: " + ytResolutions.join(", "));

    // --- SETTINGS -------
    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < end )
    {
    ++nextBestIndex;
    }

    // Target Resolution to always set to. If not available, the next best resolution will be used.
    const changeResolution = true;
    const targetRes = "hd1080";
    // Choices for targetRes are currently:
    // "highres" >= ( 8K / 4320p / QUHD )
    // "hd2880" = ( 5K / 2880p / UHD+ )
    // "hd2160" = ( 4K / 2160p / UHD )
    // "hd1440" = ( 1440p / QHD )
    // "hd1080" = ( 1080p / FHD )
    // "hd720" = ( 720p / HD )
    // "large" = ( 480p )
    // "medium" = ( 360p )
    // "small" = ( 240p )
    // "tiny" = ( 144p )
    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromURL(ytPlayer);
    if (id.indexOf("ERROR: ") === -1)
    {
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }

    debugLog("ID: " + id);
    }
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    // If changePlayerSize is true, then the video's size will be changed on the page
    // instead of using youtube's default (if theater mode is enabled).
    // If useCustomSize is false, then the player will be resized to try to match the target resolution.
    // If true, then it will use the customHeight and customWidth variables.
    const changePlayerSize = false;
    const useCustomSize = false;
    const customHeight = 600, customWidth = 1280;
    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
    }

    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded before theater can be set.
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    // NOTE: This was disabled by default to to issues with new youtube layout. This has been changed in 2020.02.18
    // since the issues no longer seem to occur. Set to false for previous behavior.
    const flushBuffer = true;
    // --------------------

    // Setting cookies can allow some operations to perform faster or without a delay (e.g. theater mode)
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    const allowCookies = false;

    // Tries to set the resolution as early as possible.
    // This might cause issues on youtube polymer layout, so disable if videos fail to load.
    // If videos load fine, leave as true or resolution may fail to set.
    const setResolutionEarly = true;

    // Enables a temporary work around for an issue where users can get the wrong youtube error screen
    // (Youtube has two of them for some reason and changing to theater mode moves the wrong one to the front)
    // Try disabling if you can't interact with the video or you think you are missing an error message.
    const enableErrorScreenWorkaround = true;
    // Set resolution, but only when API is ready (it should normally already be ready)
    function setResOnReady(ytPlayer, resolutionList)
    {
    if (ytPlayer.getPlaybackQuality === undefined)
    {
    win.setTimeout(setResOnReady, 100, ytPlayer, resolutionList);
    }
    else
    {
    let curVid = getVideoIDFromURL(ytPlayer);
    if (curVid !== recentVideo)
    {
    recentVideo = curVid;
    setResolution(ytPlayer, resolutionList);

    let storedQuality = localStorage.getItem("yt-player-quality");
    if (!storedQuality || storedQuality.indexOf(targetRes) === -1)
    {
    let tc = Date.now(), te = tc + 2592000000;
    localStorage.setItem("yt-player-quality","{\"data\":\"" + targetRes + "\",\"expiration\":" + te + ",\"creation\":" + tc + "}");
    }
    }
    }
    }

    // --------------------

    // --------------------


    function setTheaterMode(ytPlayer)
    {
    debugLog("Setting Theater Mode");

    if (win.location.href.indexOf("/watch") !== -1)
    {
    let pageManager = unwrapElement(doc.getElementsByTagName("ytd-watch-flexy")[0]);

    if (pageManager)
    {
    if (enableErrorScreenWorkaround)
    {
    const styleContent = "#error-screen { z-index: 42 !important } .ytp-error { display: none !important }";

    let errorStyle = doc.getElementById("ythdErrorWorkaroundStyleSheet");
    if (!errorStyle)
    {
    errorStyle = doc.createElement("style");
    errorStyle.type = "text/css";
    errorStyle.id = "ythdStyleSheet";
    errorStyle.innerHTML = styleContent;
    doc.head.appendChild(errorStyle);
    }
    else
    {
    errorStyle.innerHTML = styleContent;
    }
    }

    try
    {
    pageManager.theaterModeChanged_(true);
    }
    catch (e)
    { /* Ignore internal youtube exceptions. */ }
    }
    }
    }

    // --- GLOBALS --------

    // --------------------

    const DEBUG = false;

    // Possible resolution choices (in decreasing order, i.e. highres is the best):
    const resolutions = ['highres', 'hd2880', 'hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny'];
    // youtube is always 16:9 right now, but has to be at least 480x270 for the player UI
    const heights = [4320, 2880, 2160, 1440, 1080, 720, 480, 360, 270, 270];
    const widths = [7680, 5120, 3840, 2560, 1920, 1280, 854, 640, 480, 480];

    let doc = document, win = window;
    function computeAndSetPlayerSize()
    {
    let height = customHeight;
    if (!useCustomSize)
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead");
    let mastheadContainerEl = doc.getElementById("masthead-container");
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    }

    resizePlayer(height);
    }

    // ID of the most recently played video
    let recentVideo = "";

    let setHeight = 0;
    let setWidth = 0;

    // --------------------

    // --------------------

    // resize the player
    function resizePlayer(height)
    {
    debugLog("Setting video player size");

    function debugLog(message)
    {
    if (DEBUG)
    {
    console.log("YTHD | " + message);
    }
    }


    // --------------------


    // Used only for compatability with webextensions version of greasemonkey
    function unwrapElement(el)
    {
    if (el && el.wrappedJSObject)
    {
    return el.wrappedJSObject;
    }
    return el;
    }


    // --------------------


    // Get video ID from the currently loaded video (which might be different than currently loaded page)
    function getVideoIDFromURL(ytPlayer)
    {
    const idMatch = /(?:v=)([\w\-]+)/;
    let videoURL = ytPlayer.getVideoUrl();
    let id = idMatch.exec(videoURL)[1] || "ERROR: idMatch failed; youtube changed something";

    return id;
    }


    // --------------------


    // Attempt to set the video resolution to desired quality or the next best quality
    function setResolution(ytPlayer, resolutionList)
    {
    debugLog("Setting Resolution...");

    // Youtube doesn't return "auto" for auto, so set to make sure that auto is not set by setting
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes);
    }
    ytPlayer.setPlaybackQuality(targetRes);
    debugLog("Resolution Set To: " + targetRes);
    return;
    }

    const end = resolutionList.length - 1;
    let nextBestIndex = Math.max(resolutionList.indexOf(targetRes), 0);
    let ytResolutions = ytPlayer.getAvailableQualityLevels();
    debugLog("Available Resolutions: " + ytResolutions.join(", "));

    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < end )
    {
    ++nextBestIndex;
    }

    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromURL(ytPlayer);
    if (id.indexOf("ERROR: ") === -1)
    {
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }

    debugLog("ID: " + id);
    }
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
    }


    // --------------------


    // Set resolution, but only when API is ready (it should normally already be ready)
    function setResOnReady(ytPlayer, resolutionList)
    {
    if (ytPlayer.getPlaybackQuality === undefined)
    {
    win.setTimeout(setResOnReady, 100, ytPlayer, resolutionList);
    }
    else
    {
    let curVid = getVideoIDFromURL(ytPlayer);
    if (curVid !== recentVideo)
    {
    recentVideo = curVid;
    setResolution(ytPlayer, resolutionList);

    let storedQuality = localStorage.getItem("yt-player-quality");
    if (!storedQuality || storedQuality.indexOf(targetRes) === -1)
    {
    let tc = Date.now(), te = tc + 2592000000;
    localStorage.setItem("yt-player-quality","{\"data\":\"" + targetRes + "\",\"expiration\":" + te + ",\"creation\":" + tc + "}");
    }
    }
    }
    }


    // --------------------


    function setTheaterMode(ytPlayer)
    {
    debugLog("Setting Theater Mode");

    if (win.location.href.indexOf("/watch") !== -1)
    {
    let page = unwrapElement(doc.getElementById("page"));
    let pageManager = unwrapElement(doc.getElementsByTagName("ytd-watch-flexy")[0]);

    if (ytPlayer && page)
    {
    // Wait until youtube has already set the page class, so it doesn't overwrite the theater mode change
    let isLoaded = doc.body.classList.contains("page-loaded");
    if (page.className.indexOf(getVideoIDFromURL(ytPlayer)) === -1 || !isLoaded)
    {
    win.setTimeout(setTheaterMode, 250, ytPlayer);
    }
    if (isLoaded)
    {
    page.classList.remove("watch-non-stage-mode");
    page.classList.add("watch-stage-mode", "watch-wide");
    win.dispatchEvent(new Event("resize"));
    }
    }
    else if (pageManager)
    {
    if (enableErrorScreenWorkaround)
    {
    let styleContent = "#error-screen { z-index: 42 !important } .ytp-error { display: none !important }";

    let errorStyle = doc.getElementById("ythdErrorWorkaroundStyleSheet");
    if (!errorStyle)
    {
    errorStyle = doc.createElement("style");
    errorStyle.type = "text/css";
    errorStyle.id = "ythdStyleSheet";
    errorStyle.innerHTML = styleContent;
    doc.head.appendChild(errorStyle);
    }
    else
    {
    errorStyle.innerHTML = styleContent;
    }
    }

    try
    if (setHeight === height)
    {
    pageManager.theaterModeChanged_(true);
    debugLog("Player size already set");
    return;
    }
    catch (e)
    { /* Ignore internal youtube exceptions. */ }
    }
    }
    }


    // --------------------


    function computeAndSetPlayerSize()
    {
    let width, height;
    if (useCustomSize)
    {
    height = customHeight;
    width = customWidth;
    }
    else
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset") || doc.getElementById("masthead");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container") || doc.getElementById("masthead-container");
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(width, height);
    }


    // --------------------


    // resize the player
    function resizePlayer(width, height)
    {
    debugLog("Setting video player size");

    if (setHeight === height && setWidth === width)
    {
    debugLog("Player size already set");
    return;
    }

    let left, playlistTop, playlistHeight;
    left = (-width / 2);
    playlistTop = (height - 360);
    playlistHeight = (height - 100);

    let styleContent = "\
    #page.watch-stage-mode .player-height { min-height: " + height + "px !important } \
    #page.watch-stage-mode .player-width { min-width: " + width + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list { max-height: " + playlistHeight + "px !important; } \
    ytd-watch-flexy[theater]:not([fullscreen]) #player-theater-container.style-scope { \
    min-height: " + height + "px !important; max-height: none !important; height: " + height + "px !important } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    if (!ythdStyle)
    {
    ythdStyle = doc.createElement("style");
    ythdStyle.type = "text/css";
    ythdStyle.id = "ythdStyleSheet";
    ythdStyle.innerHTML = styleContent;
    doc.head.appendChild(ythdStyle);
    }
    else
    {
    ythdStyle.innerHTML = styleContent;
    }

    setHeight = height;
    setWidth = width;

    win.dispatchEvent(new Event("resize"));
    }


    // --- MAIN -----------


    function main()
    {
    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    let ytPlayerUnwrapped = unwrapElement(ytPlayer);

    if (autoTheater && ytPlayerUnwrapped)
    {
    if (allowCookies && doc.cookie.indexOf("wide=1") === -1)
    {
    doc.cookie = "wide=1; domain=.youtube.com";
    }

    setTheaterMode(ytPlayerUnwrapped);
    }

    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    {
    computeAndSetPlayerSize();
    window.addEventListener("resize", computeAndSetPlayerSize, true);
    }

    if (changeResolution && setResolutionEarly && ytPlayerUnwrapped)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }

    if (changeResolution || autoTheater)
    {
    win.addEventListener("loadstart", function(e) {
    if (!(e.target instanceof win.HTMLMediaElement))
    {
    return;
    }

    ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    ytPlayerUnwrapped = unwrapElement(ytPlayer);
    if (ytPlayerUnwrapped)
    {
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode(ytPlayerUnwrapped);
    }
    }
    }, true );
    }

    // This will eventually be changed to use the "once" option, but I want to keep a large range of browser support.
    win.removeEventListener("yt-navigate-finish", main, true );
    }

    main();
    // Youtube doesn't load the page immediately in new version so you can watch before waiting for page load
    // But we can only set resolution until the page finishes loading
    win.addEventListener("yt-navigate-finish", main, true );

    let styleContent = "\
    ytd-watch-flexy[theater]:not([fullscreen]) #player-theater-container.style-scope { \
    min-height: " + height + "px !important; max-height: none !important; height: " + height + "px !important } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    if (!ythdStyle)
    {
    ythdStyle = doc.createElement("style");
    ythdStyle.type = "text/css";
    ythdStyle.id = "ythdStyleSheet";
    ythdStyle.innerHTML = styleContent;
    doc.head.appendChild(ythdStyle);
    }
    else
    {
    ythdStyle.innerHTML = styleContent;
    }

    setHeight = height;

    win.dispatchEvent(new Event("resize"));
    }


    // --- MAIN -----------


    function main()
    {
    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    let ytPlayerUnwrapped = unwrapElement(ytPlayer);

    if (autoTheater && ytPlayerUnwrapped)
    {
    if (allowCookies && doc.cookie.indexOf("wide=1") === -1)
    {
    doc.cookie = "wide=1; domain=.youtube.com";
    }

    setTheaterMode(ytPlayerUnwrapped);
    }

    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    {
    computeAndSetPlayerSize();
    window.addEventListener("resize", computeAndSetPlayerSize, true);
    }

    if (changeResolution && setResolutionEarly && ytPlayerUnwrapped)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }

    if (changeResolution || autoTheater)
    {
    win.addEventListener("loadstart", function(e) {
    if (!(e.target instanceof win.HTMLMediaElement))
    {
    return;
    }

    ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    ytPlayerUnwrapped = unwrapElement(ytPlayer);
    if (ytPlayerUnwrapped)
    {
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode(ytPlayerUnwrapped);
    }
    }
    }, true );
    }

    // This will eventually be changed to use the "once" option, but I want to keep a large range of browser support.
    win.removeEventListener("yt-navigate-finish", main, true);
    }

    main();
    // Youtube doesn't load the page immediately in new version so you can watch before waiting for page load
    // But we can only set resolution until the page finishes loading
    win.addEventListener("yt-navigate-finish", main, true);

    })();
  2. @adisib adisib revised this gist Sep 26, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -279,7 +279,7 @@

    try
    {
    pageManager.theaterModeChanged_(true);
    pageManager.theaterModeChanged_(true);
    }
    catch (e)
    { /* Ignore internal youtube exceptions. */ }
  3. @adisib adisib revised this gist Sep 26, 2020. 1 changed file with 9 additions and 5 deletions.
    14 changes: 9 additions & 5 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2020.09.24
    // @version 2020.09.26
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -22,12 +22,11 @@

    // Code supporting old layout will be removed only after the old layout stops existing entirely.

    // 2020.07.19
    // - Theater mode now resizes its max height with window

    // 2020.09.24
    // - Add a (hopefully temporary) workaround for a rare issue where users aren't given the option to sign in to view videos flagged as inappropriate.

    // 2020.09.26
    // - Fix potential script breakage from youtube's theater mode change function throwing exceptions.

    (function() {

    @@ -278,7 +277,12 @@
    }
    }

    pageManager.theaterModeChanged_(true);
    try
    {
    pageManager.theaterModeChanged_(true);
    }
    catch (e)
    { /* Ignore internal youtube exceptions. */ }
    }
    }
    }
  4. @adisib adisib revised this gist Sep 25, 2020. 1 changed file with 29 additions and 8 deletions.
    37 changes: 29 additions & 8 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2020.07.19
    // @version 2020.09.24
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -22,13 +22,12 @@

    // Code supporting old layout will be removed only after the old layout stops existing entirely.

    // 2020.02.18
    // - Fix issue on new layout where fullscreening doesn't work correctly with changePlayerSize setting
    // - Changed flushBuffer default value to true

    // 2020.07.19
    // - Theater mode now resizes its max height with window

    // 2020.09.24
    // - Add a (hopefully temporary) workaround for a rare issue where users aren't given the option to sign in to view videos flagged as inappropriate.


    (function() {

    @@ -79,6 +78,11 @@
    // This might cause issues on youtube polymer layout, so disable if videos fail to load.
    // If videos load fine, leave as true or resolution may fail to set.
    const setResolutionEarly = true;

    // Enables a temporary work around for an issue where users can get the wrong youtube error screen
    // (Youtube has two of them for some reason and changing to theater mode moves the wrong one to the front)
    // Try disabling if you can't interact with the video or you think you are missing an error message.
    const enableErrorScreenWorkaround = true;

    // --------------------

    @@ -255,9 +259,26 @@
    }
    else if (pageManager)
    {
    pageManager.setAttribute("theater", "true");
    pageManager.setAttribute("theater-requested_", "true");
    win.dispatchEvent(new Event("resize"));
    if (enableErrorScreenWorkaround)
    {
    let styleContent = "#error-screen { z-index: 42 !important } .ytp-error { display: none !important }";

    let errorStyle = doc.getElementById("ythdErrorWorkaroundStyleSheet");
    if (!errorStyle)
    {
    errorStyle = doc.createElement("style");
    errorStyle.type = "text/css";
    errorStyle.id = "ythdStyleSheet";
    errorStyle.innerHTML = styleContent;
    doc.head.appendChild(errorStyle);
    }
    else
    {
    errorStyle.innerHTML = styleContent;
    }
    }

    pageManager.theaterModeChanged_(true);
    }
    }
    }
  5. @adisib adisib revised this gist Jul 19, 2020. 1 changed file with 52 additions and 28 deletions.
    80 changes: 52 additions & 28 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2020.02.18
    // @version 2020.07.19
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,13 +20,15 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2019.08.21
    // - Fix an issue where videos could fail to load on the new youtube layout
    // Code supporting old layout will be removed only after the old layout stops existing entirely.

    // 2020.02.18
    // - Fix issue on new layout where fullscreening doesn't work correctly with changePlayerSize setting
    // - Changed flushBuffer default value to true

    // 2020.07.19
    // - Theater mode now resizes its max height with window


    (function() {

    @@ -98,6 +100,9 @@

    // ID of the most recently played video
    let recentVideo = "";

    let setHeight = 0;
    let setWidth = 0;


    // --------------------
    @@ -261,17 +266,55 @@
    // --------------------


    function computeAndSetPlayerSize()
    {
    let width, height;
    if (useCustomSize)
    {
    height = customHeight;
    width = customWidth;
    }
    else
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset") || doc.getElementById("masthead");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container") || doc.getElementById("masthead-container");
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(width, height);
    }


    // --------------------


    // resize the player
    function resizePlayer(width, height)
    {
    debugLog("Setting video player size");

    if (setHeight === height && setWidth === width)
    {
    debugLog("Player size already set");
    return;
    }

    let left, playlistTop, playlistHeight;
    left = (-width / 2);
    playlistTop = (height - 360);
    playlistHeight = (height - 100);

    let styleContent = " \
    let styleContent = "\
    #page.watch-stage-mode .player-height { min-height: " + height + "px !important } \
    #page.watch-stage-mode .player-width { min-width: " + width + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; } \
    @@ -294,6 +337,9 @@
    {
    ythdStyle.innerHTML = styleContent;
    }

    setHeight = height;
    setWidth = width;

    win.dispatchEvent(new Event("resize"));
    }
    @@ -319,30 +365,8 @@

    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    {
    let width, height;
    if (useCustomSize)
    {
    height = customHeight;
    width = customWidth;
    }
    else
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset") || doc.getElementById("masthead");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container") || doc.getElementById("masthead-container");
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(width, height);
    computeAndSetPlayerSize();
    window.addEventListener("resize", computeAndSetPlayerSize, true);
    }

    if (changeResolution && setResolutionEarly && ytPlayerUnwrapped)
  6. @adisib adisib revised this gist Feb 18, 2020. 1 changed file with 10 additions and 8 deletions.
    18 changes: 10 additions & 8 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2019.08.27
    // @version 2020.02.18
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,12 +20,13 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2019.08.27
    // - Revert previous fix and make it an option, as the problem it fixes seems to be gone and it creates a new one

    // 2019.08.21
    // - Fix an issue where videos could fail to load on the new youtube layout

    // 2020.02.18
    // - Fix issue on new layout where fullscreening doesn't work correctly with changePlayerSize setting
    // - Changed flushBuffer default value to true


    (function() {

    @@ -64,9 +65,9 @@
    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    // NOTE: This is disabled by default because it doesn't work correctly with the new youtube layout
    // If you are using the old layout, it is recommended to enable this.
    const flushBuffer = false;
    // NOTE: This was disabled by default to to issues with new youtube layout. This has been changed in 2020.02.18
    // since the issues no longer seem to occur. Set to false for previous behavior.
    const flushBuffer = true;

    // Setting cookies can allow some operations to perform faster or without a delay (e.g. theater mode)
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    @@ -276,7 +277,8 @@
    #page.watch-stage-mode .player-width { left: " + left + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list { max-height: " + playlistHeight + "px !important; } \
    ytd-watch-flexy[theater] #player-theater-container.style-scope { min-height: " + height + "px !important; max-height: none !important; height: " + height + "px !important } \
    ytd-watch-flexy[theater]:not([fullscreen]) #player-theater-container.style-scope { \
    min-height: " + height + "px !important; max-height: none !important; height: " + height + "px !important } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
  7. @adisib adisib revised this gist Aug 27, 2019. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -72,10 +72,10 @@
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    const allowCookies = false;

    // Tries to set the resolution as early as possible.
    // This might cause issues on youtube polymer layout, so disable if videos fail to load.
    // If videos load fine, leave as true or resolution may fail to set.
    const setResolutionEarly = true;
    // Tries to set the resolution as early as possible.
    // This might cause issues on youtube polymer layout, so disable if videos fail to load.
    // If videos load fine, leave as true or resolution may fail to set.
    const setResolutionEarly = true;

    // --------------------

  8. @adisib adisib revised this gist Aug 27, 2019. 1 changed file with 10 additions and 5 deletions.
    15 changes: 10 additions & 5 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2019.08.21
    // @version 2019.08.27
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,12 +20,12 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2019.08.27
    // - Revert previous fix and make it an option, as the problem it fixes seems to be gone and it creates a new one

    // 2019.08.21
    // - Fix an issue where videos could fail to load on the new youtube layout

    // 2018.08.13
    // - Fix setting player size not working on the new layout after youtube changes


    (function() {

    @@ -72,6 +72,11 @@
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    const allowCookies = false;

    // Tries to set the resolution as early as possible.
    // This might cause issues on youtube polymer layout, so disable if videos fail to load.
    // If videos load fine, leave as true or resolution may fail to set.
    const setResolutionEarly = true;

    // --------------------


    @@ -338,7 +343,7 @@
    resizePlayer(width, height);
    }

    if (changeResolution && ytPlayerUnwrapped && doc.getElementById("page"))
    if (changeResolution && setResolutionEarly && ytPlayerUnwrapped)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
  9. @adisib adisib revised this gist Aug 21, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -338,7 +338,7 @@
    resizePlayer(width, height);
    }

    if (changeResolution && ytPlayerUnwrapped)
    if (changeResolution && ytPlayerUnwrapped && doc.getElementById("page"))
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
  10. @adisib adisib revised this gist Aug 21, 2019. 1 changed file with 7 additions and 7 deletions.
    14 changes: 7 additions & 7 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2018.08.13
    // @version 2019.08.21
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,12 +20,12 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2019.08.21
    // - Fix an issue where videos could fail to load on the new youtube layout

    // 2018.08.13
    // - Fix setting player size not working on the new layout after youtube changes

    // 2018.07.28
    // - Fix auto theater mode not working on the new layout after youtube changes.


    (function() {

    @@ -64,7 +64,7 @@
    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    // NOTE: This is disabled by default because it has unfixable visual issues with the new youtube layout, though it still works.
    // NOTE: This is disabled by default because it doesn't work correctly with the new youtube layout
    // If you are using the old layout, it is recommended to enable this.
    const flushBuffer = false;

    @@ -148,7 +148,7 @@
    {
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes, targetRes);
    ytPlayer.setPlaybackQualityRange(targetRes);
    }
    ytPlayer.setPlaybackQuality(targetRes);
    debugLog("Resolution Set To: " + targetRes);
    @@ -178,7 +178,7 @@
    }
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex], resolutionList[nextBestIndex]);
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

  11. @adisib adisib revised this gist Oct 16, 2018. 1 changed file with 7 additions and 7 deletions.
    14 changes: 7 additions & 7 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2018.07.28
    // @version 2018.08.13
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,13 +20,12 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2018.08.13
    // - Fix setting player size not working on the new layout after youtube changes

    // 2018.07.28
    // - Fix auto theater mode not working on the new layout after youtube changes.

    // 2018.04.25
    // - Fix possibility that setting manual resolution requires setting it twice in some circumstances.
    // - Disable buffer flushing code by default because youtube is currently already flushing itself by default now.


    (function() {

    @@ -267,11 +266,12 @@
    playlistHeight = (height - 100);

    let styleContent = " \
    #page.watch-stage-mode .player-height, ytd-watch[theater] #player.style-scope { min-height: " + height + "px !important; } \
    #page.watch-stage-mode .player-width, ytd-watch[theater] #player.style-scope { min-width: " + width + "px !important; } \
    #page.watch-stage-mode .player-height { min-height: " + height + "px !important } \
    #page.watch-stage-mode .player-width { min-width: " + width + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list { max-height: " + playlistHeight + "px !important; } \
    ytd-watch-flexy[theater] #player-theater-container.style-scope { min-height: " + height + "px !important; max-height: none !important; height: " + height + "px !important } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
  12. @adisib adisib revised this gist Jul 29, 2018. 1 changed file with 8 additions and 6 deletions.
    14 changes: 8 additions & 6 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2018.04.25
    // @version 2018.07.28
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,13 +20,13 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2018.07.28
    // - Fix auto theater mode not working on the new layout after youtube changes.

    // 2018.04.25
    // - Fix possibility that setting manual resolution requires setting it twice in some circumstances.
    // - Disable buffer flushing code by default because youtube is currently already flushing itself by default now.

    // 2018.03.30
    // - Quick fix for youtube change today making script prevent manual resolution setting by freezing the video and causing some or all multi-process browsers to hang.


    (function() {

    @@ -59,12 +59,14 @@

    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded first.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded before theater can be set.
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    // NOTE: This is disabled by default because it has unfixable visual issues with the new youtube layout, though it still works.
    // If you are using the old layout, it is recommended to enable this.
    const flushBuffer = false;

    // Setting cookies can allow some operations to perform faster or without a delay (e.g. theater mode)
    @@ -224,7 +226,7 @@
    if (win.location.href.indexOf("/watch") !== -1)
    {
    let page = unwrapElement(doc.getElementById("page"));
    let pageManager = unwrapElement(doc.getElementsByTagName("ytd-watch")[0]);
    let pageManager = unwrapElement(doc.getElementsByTagName("ytd-watch-flexy")[0]);

    if (ytPlayer && page)
    {
  13. @adisib adisib revised this gist Apr 25, 2018. 1 changed file with 28 additions and 24 deletions.
    52 changes: 28 additions & 24 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2018.03.30
    // @version 2018.04.25
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,12 +20,13 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2018.04.25
    // - Fix possibility that setting manual resolution requires setting it twice in some circumstances.
    // - Disable buffer flushing code by default because youtube is currently already flushing itself by default now.

    // 2018.03.30
    // - Quick fix for youtube change today making script prevent manual resolution setting by freezing the video and causing some or all multi-process browsers to hang.

    // 2017.12.09
    // - Fixed Resolution not setting because Youtube broke its API


    (function() {

    @@ -64,7 +65,7 @@
    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    const flushBuffer = true;
    const flushBuffer = false;

    // Setting cookies can allow some operations to perform faster or without a delay (e.g. theater mode)
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    @@ -88,6 +89,9 @@

    let doc = document, win = window;

    // ID of the most recently played video
    let recentVideo = "";


    // --------------------

    @@ -193,13 +197,18 @@
    }
    else
    {
    setResolution(ytPlayer, resolutionList);

    let storedQuality = localStorage.getItem("yt-player-quality");
    if (!storedQuality || storedQuality.indexOf(targetRes) === -1)
    let curVid = getVideoIDFromURL(ytPlayer);
    if (curVid !== recentVideo)
    {
    let tc = Date.now(), te = tc + 2592000000;
    localStorage.setItem("yt-player-quality","{\"data\":\"" + targetRes + "\",\"expiration\":" + te + ",\"creation\":" + tc + "}");
    recentVideo = curVid;
    setResolution(ytPlayer, resolutionList);

    let storedQuality = localStorage.getItem("yt-player-quality");
    if (!storedQuality || storedQuality.indexOf(targetRes) === -1)
    {
    let tc = Date.now(), te = tc + 2592000000;
    localStorage.setItem("yt-player-quality","{\"data\":\"" + targetRes + "\",\"expiration\":" + te + ",\"creation\":" + tc + "}");
    }
    }
    }
    }
    @@ -334,7 +343,6 @@

    if (changeResolution || autoTheater)
    {
    let curVid = "";
    win.addEventListener("loadstart", function(e) {
    if (!(e.target instanceof win.HTMLMediaElement))
    {
    @@ -345,24 +353,20 @@
    ytPlayerUnwrapped = unwrapElement(ytPlayer);
    if (ytPlayerUnwrapped)
    {
    let oldVid = curVid;
    curVid = getVideoIDFromURL(ytPlayerUnwrapped);
    if (curVid != oldVid)
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    {
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode(ytPlayerUnwrapped);
    }
    setTheaterMode(ytPlayerUnwrapped);
    }
    }
    }, true );
    }

    // This will eventually be changed to use the "once" option, but I want to keep a large range of browser support.
    win.removeEventListener("yt-navigate-finish", main, true );
    }

  14. @adisib adisib revised this gist Mar 30, 2018. 1 changed file with 20 additions and 14 deletions.
    34 changes: 20 additions & 14 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.12.09
    // @version 2018.03.30
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -20,13 +20,12 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2018.03.30
    // - Quick fix for youtube change today making script prevent manual resolution setting by freezing the video and causing some or all multi-process browsers to hang.

    // 2017.12.09
    // - Fixed Resolution not setting because Youtube broke its API

    // 2017.11.18
    // - Fixed Greasemonkey 4 WebExtension breaking things in Firefox 57
    // - Added option to allow the script to set cookies to speed up theater mode


    (function() {

    @@ -105,6 +104,7 @@
    // --------------------


    // Used only for compatability with webextensions version of greasemonkey
    function unwrapElement(el)
    {
    if (el && el.wrappedJSObject)
    @@ -141,7 +141,7 @@
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes, targetRes);
    }
    @@ -171,7 +171,7 @@

    debugLog("ID: " + id);
    }
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    if (ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex], resolutionList[nextBestIndex]);
    }
    @@ -334,6 +334,7 @@

    if (changeResolution || autoTheater)
    {
    let curVid = "";
    win.addEventListener("loadstart", function(e) {
    if (!(e.target instanceof win.HTMLMediaElement))
    {
    @@ -344,14 +345,19 @@
    ytPlayerUnwrapped = unwrapElement(ytPlayer);
    if (ytPlayerUnwrapped)
    {
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    let oldVid = curVid;
    curVid = getVideoIDFromURL(ytPlayerUnwrapped);
    if (curVid != oldVid)
    {
    setTheaterMode(ytPlayerUnwrapped);
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode(ytPlayerUnwrapped);
    }
    }
    }
    }, true );
  15. @adisib adisib revised this gist Dec 9, 2017. 1 changed file with 8 additions and 8 deletions.
    16 changes: 8 additions & 8 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -141,10 +141,10 @@
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes, targetRes);
    }
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes, targetRes);
    }
    ytPlayer.setPlaybackQuality(targetRes);
    debugLog("Resolution Set To: " + targetRes);
    return;
    @@ -171,10 +171,10 @@

    debugLog("ID: " + id);
    }
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex], resolutionList[nextBestIndex]);
    }
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex], resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
  16. @adisib adisib revised this gist Dec 9, 2017. 1 changed file with 12 additions and 4 deletions.
    16 changes: 12 additions & 4 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.11.18
    // @version 2017.12.09
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -14,19 +14,19 @@
    // @grant none
    // ==/UserScript==

    // Only the html5 player is supported.
    // The video will only resize when in theater mode on the main youtube website.
    // By default only runs on youtube website, not players embeded on other websites, but there is experimental support for embeds.
    // To enable experimental support for embedded players outside of YouTube website, do the following steps:
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.12.09
    // - Fixed Resolution not setting because Youtube broke its API

    // 2017.11.18
    // - Fixed Greasemonkey 4 WebExtension breaking things in Firefox 57
    // - Added option to allow the script to set cookies to speed up theater mode

    // 2017.08.05
    // - Fix tiny mistake that broke playlist positioning when resizing

    (function() {

    @@ -141,6 +141,10 @@
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(targetRes, targetRes);
    }
    ytPlayer.setPlaybackQuality(targetRes);
    debugLog("Resolution Set To: " + targetRes);
    return;
    @@ -167,6 +171,10 @@

    debugLog("ID: " + id);
    }
    if(ytPlayer.setPlaybackQualityRange !== undefined)
    {
    ytPlayer.setPlaybackQualityRange(resolutionList[nextBestIndex], resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
  17. @adisib adisib revised this gist Nov 18, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -60,7 +60,7 @@
    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded first.
    const autoTheater = true;
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
  18. @adisib adisib revised this gist Nov 18, 2017. 1 changed file with 39 additions and 14 deletions.
    53 changes: 39 additions & 14 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.08.05
    // @version 2017.11.18
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -21,12 +21,13 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.11.18
    // - Fixed Greasemonkey 4 WebExtension breaking things in Firefox 57
    // - Added option to allow the script to set cookies to speed up theater mode

    // 2017.08.05
    // - Fix tiny mistake that broke playlist positioning when resizing

    // 2017.08.03
    // - Updated to be compatible with upcoming youtube layout, so should work on both layouts now.

    (function() {

    "use strict";
    @@ -59,13 +60,17 @@
    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded first.
    const autoTheater = false;
    const autoTheater = true;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    const flushBuffer = true;

    // Setting cookies can allow some operations to perform faster or without a delay (e.g. theater mode)
    // Some people don't like setting cookies, so this is false by default (which is the same as old behavior)
    const allowCookies = false;

    // --------------------


    @@ -100,6 +105,19 @@
    // --------------------


    function unwrapElement(el)
    {
    if (el && el.wrappedJSObject)
    {
    return el.wrappedJSObject;
    }
    return el;
    }


    // --------------------


    // Get video ID from the currently loaded video (which might be different than currently loaded page)
    function getVideoIDFromURL(ytPlayer)
    {
    @@ -188,8 +206,8 @@

    if (win.location.href.indexOf("/watch") !== -1)
    {
    let page = doc.getElementById("page");
    let pageManager = doc.getElementsByTagName("ytd-watch")[0];
    let page = unwrapElement(doc.getElementById("page"));
    let pageManager = unwrapElement(doc.getElementsByTagName("ytd-watch")[0]);

    if (ytPlayer && page)
    {
    @@ -261,10 +279,16 @@
    function main()
    {
    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    let ytPlayerUnwrapped = unwrapElement(ytPlayer);

    if (autoTheater && ytPlayer)
    if (autoTheater && ytPlayerUnwrapped)
    {
    setTheaterMode(ytPlayer);
    if (allowCookies && doc.cookie.indexOf("wide=1") === -1)
    {
    doc.cookie = "wide=1; domain=.youtube.com";
    }

    setTheaterMode(ytPlayerUnwrapped);
    }

    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    @@ -295,9 +319,9 @@
    resizePlayer(width, height);
    }

    if (changeResolution && ytPlayer)
    if (changeResolution && ytPlayerUnwrapped)
    {
    setResOnReady(ytPlayer, resolutions);
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }

    if (changeResolution || autoTheater)
    @@ -309,16 +333,17 @@
    }

    ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer)
    ytPlayerUnwrapped = unwrapElement(ytPlayer);
    if (ytPlayerUnwrapped)
    {
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    setResOnReady(ytPlayerUnwrapped, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode(ytPlayer);
    setTheaterMode(ytPlayerUnwrapped);
    }
    }
    }, true );
  19. @adisib adisib revised this gist Aug 5, 2017. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.08.03
    // @version 2017.08.05
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -21,12 +21,12 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.08.05
    // - Fix tiny mistake that broke playlist positioning when resizing

    // 2017.08.03
    // - Updated to be compatible with upcoming youtube layout, so should work on both layouts now.

    // 2017.05.19
    // - Fixed very rare issue where Auto HD and Auto Theater wouldn't run.

    (function() {

    "use strict";
    @@ -233,8 +233,8 @@
    #page.watch-stage-mode .player-height, ytd-watch[theater] #player.style-scope { min-height: " + height + "px !important; } \
    #page.watch-stage-mode .player-width, ytd-watch[theater] #player.style-scope { min-width: " + width + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist, { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list, { max-height: " + playlistHeight + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list { max-height: " + playlistHeight + "px !important; } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
  20. @adisib adisib revised this gist Aug 3, 2017. 1 changed file with 114 additions and 87 deletions.
    201 changes: 114 additions & 87 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.05.19
    // @version 2017.08.03
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -16,19 +16,16 @@

    // Only the html5 player is supported.
    // The video will only resize when in theater mode on the main youtube website.
    // By default only runs on youtube website, not players embeded on other websites.
    // YouTube players embeded on other websites should work if enabled, but this feature is not supported.

    // By default only runs on youtube website, not players embeded on other websites, but there is experimental support for embeds.
    // To enable experimental support for embedded players outside of YouTube website, do the following steps:
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.05.19
    // - Fixed very rare issue where Auto HD and Auto Theater wouldn't run
    // 2017.08.03
    // - Updated to be compatible with upcoming youtube layout, so should work on both layouts now.

    // 2017.05.09
    // - Fixed problems with the auto theater feature, should work perfectly now
    // - Various minor improvements
    // 2017.05.19
    // - Fixed very rare issue where Auto HD and Auto Theater wouldn't run.

    (function() {

    @@ -127,38 +124,34 @@
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    ytPlayer.setPlaybackQuality(targetRes);

    debugLog("Resolution Set To: " + targetRes);
    return;
    }
    else
    {
    const end = resolutionList.length - 1;
    let nextBestIndex = Math.max(resolutionList.indexOf(targetRes), 0);
    let ytResolutions = ytPlayer.getAvailableQualityLevels();

    debugLog("Available Resolutions: " + ytResolutions.join(", "));
    const end = resolutionList.length - 1;
    let nextBestIndex = Math.max(resolutionList.indexOf(targetRes), 0);
    let ytResolutions = ytPlayer.getAvailableQualityLevels();
    debugLog("Available Resolutions: " + ytResolutions.join(", "));

    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < end )
    {
    ++nextBestIndex;
    }
    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < end )
    {
    ++nextBestIndex;
    }

    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromURL(ytPlayer);
    if (id.indexOf("ERROR: ") === -1)
    {
    let id = getVideoIDFromURL(ytPlayer);
    if (id.indexOf("ERROR: ") === -1)
    {
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }

    debugLog("ID: " + id);
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
    debugLog("ID: " + id);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
    }


    @@ -175,6 +168,13 @@
    else
    {
    setResolution(ytPlayer, resolutionList);

    let storedQuality = localStorage.getItem("yt-player-quality");
    if (!storedQuality || storedQuality.indexOf(targetRes) === -1)
    {
    let tc = Date.now(), te = tc + 2592000000;
    localStorage.setItem("yt-player-quality","{\"data\":\"" + targetRes + "\",\"expiration\":" + te + ",\"creation\":" + tc + "}");
    }
    }
    }

    @@ -186,19 +186,30 @@
    {
    debugLog("Setting Theater Mode");

    let page = doc.getElementById("page");
    if (ytPlayer && page && win.location.href.indexOf("/watch") !== -1)
    if (win.location.href.indexOf("/watch") !== -1)
    {
    // Wait until youtube has already set the page class, so it doesn't overwrite the theater mode change
    let isLoaded = doc.body.classList.contains("page-loaded");
    if (page.className.indexOf(getVideoIDFromURL(ytPlayer)) === -1 || !isLoaded)
    let page = doc.getElementById("page");
    let pageManager = doc.getElementsByTagName("ytd-watch")[0];

    if (ytPlayer && page)
    {
    win.setTimeout(setTheaterMode, 400, ytPlayer);
    // Wait until youtube has already set the page class, so it doesn't overwrite the theater mode change
    let isLoaded = doc.body.classList.contains("page-loaded");
    if (page.className.indexOf(getVideoIDFromURL(ytPlayer)) === -1 || !isLoaded)
    {
    win.setTimeout(setTheaterMode, 250, ytPlayer);
    }
    if (isLoaded)
    {
    page.classList.remove("watch-non-stage-mode");
    page.classList.add("watch-stage-mode", "watch-wide");
    win.dispatchEvent(new Event("resize"));
    }
    }
    if (isLoaded)
    else if (pageManager)
    {
    page.classList.remove("watch-non-stage-mode");
    page.classList.add("watch-stage-mode", "watch-wide");
    pageManager.setAttribute("theater", "true");
    pageManager.setAttribute("theater-requested_", "true");
    win.dispatchEvent(new Event("resize"));
    }
    }
    @@ -219,10 +230,11 @@
    playlistHeight = (height - 100);

    let styleContent = " \
    #page.watch-stage-mode .player-height { min-height: " + height + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; min-width: " + width + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list { max-height: " + playlistHeight + "px !important; } \
    #page.watch-stage-mode .player-height, ytd-watch[theater] #player.style-scope { min-height: " + height + "px !important; } \
    #page.watch-stage-mode .player-width, ytd-watch[theater] #player.style-scope { min-width: " + width + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist, { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list, { max-height: " + playlistHeight + "px !important; } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    @@ -239,70 +251,85 @@
    ythdStyle.innerHTML = styleContent;
    }

    // Youtube's video player wont resize itself until resize event is fired
    win.dispatchEvent(new Event("resize"));
    }


    // --- MAIN -----------

    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (autoTheater && ytPlayer)
    function main()
    {
    setTheaterMode(ytPlayer);
    }
    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    {
    let width, height;
    if (useCustomSize)
    if (autoTheater && ytPlayer)
    {
    height = customHeight;
    width = customWidth;
    setTheaterMode(ytPlayer);
    }
    else

    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container");
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    let width, height;
    if (useCustomSize)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    height = customHeight;
    width = customWidth;
    }
    else
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset") || doc.getElementById("masthead");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container") || doc.getElementById("masthead-container");
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }
    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(width, height);
    }
    resizePlayer(width, height);
    }

    if (changeResolution && ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    if (changeResolution && ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }

    if (changeResolution || autoTheater)
    {
    win.addEventListener("loadstart", function(e) {
    ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer && (e.target instanceof win.HTMLMediaElement))
    {
    debugLog("Loaded new video");
    if (changeResolution)
    if (changeResolution || autoTheater)
    {
    win.addEventListener("loadstart", function(e) {
    if (!(e.target instanceof win.HTMLMediaElement))
    {
    setResOnReady(ytPlayer, resolutions);
    return;
    }
    if (autoTheater)

    ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer)
    {
    setTheaterMode(ytPlayer);
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode(ytPlayer);
    }
    }
    }
    }, true );
    }, true );
    }

    win.removeEventListener("yt-navigate-finish", main, true );
    }

    })();
    main();
    // Youtube doesn't load the page immediately in new version so you can watch before waiting for page load
    // But we can only set resolution until the page finishes loading
    win.addEventListener("yt-navigate-finish", main, true );

    })();
  21. @adisib adisib revised this gist May 19, 2017. 1 changed file with 12 additions and 12 deletions.
    24 changes: 12 additions & 12 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.05.09
    // @version 2017.05.19
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -23,14 +23,13 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.05.19
    // - Fixed very rare issue where Auto HD and Auto Theater wouldn't run

    // 2017.05.09
    // - Fixed problems with the auto theater feature, should work perfectly now
    // - Various minor improvements

    // 2017.05.04
    // - Added optional feature to automatically open videos in theater mode
    // - Added fix for a change in Firefox 52+ causing undesired resolution changes

    (function() {

    "use strict";
    @@ -169,7 +168,7 @@
    // Set resolution, but only when API is ready (it should normally already be ready)
    function setResOnReady(ytPlayer, resolutionList)
    {
    if (ytPlayer.getPlayerState === undefined)
    if (ytPlayer.getPlaybackQuality === undefined)
    {
    win.setTimeout(setResOnReady, 100, ytPlayer, resolutionList);
    }
    @@ -191,11 +190,12 @@
    if (ytPlayer && page && win.location.href.indexOf("/watch") !== -1)
    {
    // Wait until youtube has already set the page class, so it doesn't overwrite the theater mode change
    if (page.className.indexOf(getVideoIDFromURL(ytPlayer)) === -1 || !doc.body.classList.contains("page-loaded"))
    let isLoaded = doc.body.classList.contains("page-loaded");
    if (page.className.indexOf(getVideoIDFromURL(ytPlayer)) === -1 || !isLoaded)
    {
    win.setTimeout(setTheaterMode, 500, ytPlayer);
    win.setTimeout(setTheaterMode, 400, ytPlayer);
    }
    if (doc.body.classList.contains("page-loaded"))
    if (isLoaded)
    {
    page.classList.remove("watch-non-stage-mode");
    page.classList.add("watch-stage-mode", "watch-wide");
    @@ -209,7 +209,7 @@


    // resize the player
    function resizePlayer(ytPlayer, width, height)
    function resizePlayer(width, height)
    {
    debugLog("Setting video player size");

    @@ -278,7 +278,7 @@
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(ytPlayer, width, height);
    resizePlayer(width, height);
    }

    if (changeResolution && ytPlayer)
    @@ -289,7 +289,7 @@
    if (changeResolution || autoTheater)
    {
    win.addEventListener("loadstart", function(e) {
    ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer && (e.target instanceof win.HTMLMediaElement))
    {
    debugLog("Loaded new video");
  22. @adisib adisib revised this gist May 9, 2017. 1 changed file with 47 additions and 47 deletions.
    94 changes: 47 additions & 47 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.05.06
    // @version 2017.05.09
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -23,15 +23,14 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.05.09
    // - Fixed problems with the auto theater feature, should work perfectly now
    // - Various minor improvements

    // 2017.05.04
    // - Added optional feature to automatically open videos in theater mode
    // - Added fix for a change in Firefox 52+ causing undesired resolution changes

    // 2017.03.28
    // - Fixed playlist height issue when resized
    // - Resolution will now set for gaming.youtube.com by default as well
    // - Various minor improvements

    (function() {

    "use strict";
    @@ -63,6 +62,7 @@

    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    // NOTE: YouTube will not always allow theater mode immediately, the page must be fully loaded first.
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    @@ -96,7 +96,7 @@
    {
    if (DEBUG)
    {
    console.log(message);
    console.log("YTHD | " + message);
    }
    }

    @@ -109,7 +109,7 @@
    {
    const idMatch = /(?:v=)([\w\-]+)/;
    let videoURL = ytPlayer.getVideoUrl();
    let id = idMatch.exec(videoURL)[1] || "YTHD | ERROR: idMatch failed; youtube changed something";
    let id = idMatch.exec(videoURL)[1] || "ERROR: idMatch failed; youtube changed something";

    return id;
    }
    @@ -121,23 +121,23 @@
    // Attempt to set the video resolution to desired quality or the next best quality
    function setResolution(ytPlayer, resolutionList)
    {
    debugLog("YTHD | Setting Resolution...");
    debugLog("Setting Resolution...");

    // Youtube doesn't return "auto" for auto, so set to make sure that auto is not set by setting
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    ytPlayer.setPlaybackQuality(targetRes);

    debugLog("YTHD | Resolution Set To: " + targetRes);
    debugLog("Resolution Set To: " + targetRes);
    }
    else
    {
    const end = resolutionList.length - 1;
    let nextBestIndex = Math.max(resolutionList.indexOf(targetRes), 0);
    let ytResolutions = ytPlayer.getAvailableQualityLevels();

    debugLog("YTHD | Available Resolutions: " + ytResolutions.join(", "));
    debugLog("Available Resolutions: " + ytResolutions.join(", "));

    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < end )
    {
    @@ -147,17 +147,17 @@
    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromURL(ytPlayer);
    if (id.indexOf("YTHD |") === -1)
    if (id.indexOf("ERROR: ") === -1)
    {
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }

    debugLog("YTHD | ID: " + id);
    debugLog("ID: " + id);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    debugLog("YTHD | Resolution Set To: " + resolutionList[nextBestIndex]);
    debugLog("Resolution Set To: " + resolutionList[nextBestIndex]);
    }

    }
    @@ -183,16 +183,24 @@
    // --------------------


    function setTheaterMode()
    function setTheaterMode(ytPlayer)
    {
    debugLog("YTHD | Setting Theater Mode");
    debugLog("Setting Theater Mode");

    let page = doc.getElementById("page");
    if (page && page.className.indexOf("watch-stage-mode") === -1)
    if (ytPlayer && page && win.location.href.indexOf("/watch") !== -1)
    {
    page.className = page.className.replace("watch-non-stage-mode", "") + " watch-stage-mode watch-wide";
    // If youtube loads too slowly, it will overwrite this change here. Working around this for now by doing again later.
    win.setTimeout(setTheaterMode, 500);
    // Wait until youtube has already set the page class, so it doesn't overwrite the theater mode change
    if (page.className.indexOf(getVideoIDFromURL(ytPlayer)) === -1 || !doc.body.classList.contains("page-loaded"))
    {
    win.setTimeout(setTheaterMode, 500, ytPlayer);
    }
    if (doc.body.classList.contains("page-loaded"))
    {
    page.classList.remove("watch-non-stage-mode");
    page.classList.add("watch-stage-mode", "watch-wide");
    win.dispatchEvent(new Event("resize"));
    }
    }
    }

    @@ -203,7 +211,7 @@
    // resize the player
    function resizePlayer(ytPlayer, width, height)
    {
    debugLog("YTHD | Setting video player size");
    debugLog("Setting video player size");

    let left, playlistTop, playlistHeight;
    left = (-width / 2);
    @@ -213,8 +221,8 @@
    let styleContent = " \
    #page.watch-stage-mode .player-height { min-height: " + height + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; min-width: " + width + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist {top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list {max-height: " + playlistHeight + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist { top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list { max-height: " + playlistHeight + "px !important; } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    @@ -231,24 +239,21 @@
    ythdStyle.innerHTML = styleContent;
    }

    // Youtube's video player wont resize itself until interacted with so remind it to resize on video page
    if (ytPlayer)
    {
    ytPlayer.setSize(width, height);
    }
    // Youtube's video player wont resize itself until resize event is fired
    win.dispatchEvent(new Event("resize"));
    }


    // --- MAIN -----------

    if (autoTheater)
    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (autoTheater && ytPlayer)
    {
    setTheaterMode();
    setTheaterMode(ytPlayer);
    }

    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (changePlayerSize && win.location.href.indexOf("youtube.com") !== -1 && win.location.href.indexOf("gaming.") === -1)
    if (changePlayerSize && win.location.host.indexOf("youtube.com") !== -1 && win.location.host.indexOf("gaming.") === -1)
    {
    let width, height;
    if (useCustomSize)
    @@ -261,45 +266,40 @@
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container");
    let mastheadHeight = 0, mastheadPadding = 0;
    let mastheadHeight = 50, mastheadPadding = 16;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10) || 50;
    mastheadPadding = (parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2) || 16;
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10);
    mastheadPadding = parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(ytPlayer, width, height);
    }

    if (changeResolution)
    if (changeResolution && ytPlayer)
    {
    if (ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    setResOnReady(ytPlayer, resolutions);
    }

    if (changeResolution || autoTheater)
    {
    win.addEventListener("loadstart", function(e) {
    debugLog("YTHD | Load event fired");

    ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer && (e.target instanceof HTMLMediaElement))
    if (ytPlayer && (e.target instanceof win.HTMLMediaElement))
    {
    debugLog("Loaded new video");
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    if (autoTheater)
    {
    setTheaterMode();
    ytPlayer.setSize(-1, -1);
    setTheaterMode(ytPlayer);
    }
    }
    }, true );
  23. @adisib adisib revised this gist May 6, 2017. 1 changed file with 29 additions and 37 deletions.
    66 changes: 29 additions & 37 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.05.04
    // @version 2017.05.06
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -25,7 +25,7 @@

    // 2017.05.04
    // - Added optional feature to automatically open videos in theater mode
    // - Added work-around for a bug in newer versions of Firefox causing undesired resolution changes
    // - Added fix for a change in Firefox 52+ causing undesired resolution changes

    // 2017.03.28
    // - Fixed playlist height issue when resized
    @@ -61,12 +61,13 @@
    const useCustomSize = false;
    const customHeight = 600, customWidth = 1280;

    // If autoTheater is true, each video page opened will default to stage mode.
    // If autoTheater is true, each video page opened will default to theater mode.
    // This means the video will always be resized immediately if you are changing the size.
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution
    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution.
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed
    // a very small additional delay before the video starts if the buffer needs to be flushed.
    const flushBuffer = true;

    // --------------------
    @@ -86,7 +87,6 @@
    const widths = [7680, 5120, 3840, 2560, 1920, 1280, 854, 640, 480, 480];

    let doc = document, win = window;
    let currentVid = "";


    // --------------------
    @@ -147,13 +147,13 @@
    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromURL(ytPlayer);
    if (id.indexOf('YTHD |') === -1)
    if (id.indexOf("YTHD |") === -1)
    {
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }

    debugLog(id);
    debugLog("YTHD | ID: " + id);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    @@ -169,9 +169,7 @@
    // Set resolution, but only when API is ready (it should normally already be ready)
    function setResOnReady(ytPlayer, resolutionList)
    {
    if ( (ytPlayer.getPlayerState === undefined)
    || (ytPlayer.getPlayerState() === -1) // This prevents a youtube bug where the video buffer gets stuck
    )
    if (ytPlayer.getPlayerState === undefined)
    {
    win.setTimeout(setResOnReady, 100, ytPlayer, resolutionList);
    }
    @@ -185,14 +183,16 @@
    // --------------------


    function setTheaterMode(ytPlayer)
    function setTheaterMode()
    {
    debugLog("YTHD | Setting Theater Mode");

    let page = document.getElementById("page");
    if (page && page.className.indexOf("stage-mode") === -1)
    let page = doc.getElementById("page");
    if (page && page.className.indexOf("watch-stage-mode") === -1)
    {
    page.className = page.className + " watch-stage-mode watch-wide";
    page.className = page.className.replace("watch-non-stage-mode", "") + " watch-stage-mode watch-wide";
    // If youtube loads too slowly, it will overwrite this change here. Working around this for now by doing again later.
    win.setTimeout(setTheaterMode, 500);
    }
    }

    @@ -205,13 +205,8 @@
    {
    debugLog("YTHD | Setting video player size");

    if (autoTheater)
    {
    setTheaterMode(ytPlayer);
    }

    let left, playlistTop, playlistHeight;
    left = (-width/2);
    left = (-width / 2);
    playlistTop = (height - 360);
    playlistHeight = (height - 100);

    @@ -246,6 +241,10 @@

    // --- MAIN -----------

    if (autoTheater)
    {
    setTheaterMode();
    }

    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    @@ -287,27 +286,20 @@

    if (changeResolution || autoTheater)
    {
    window.addEventListener("loadstart", function() {
    win.addEventListener("loadstart", function(e) {
    debugLog("YTHD | Load event fired");

    ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer)
    if (ytPlayer && (e.target instanceof HTMLMediaElement))
    {
    let loadedVid = getVideoIDFromURL(ytPlayer);
    if (currentVid !== loadedVid)
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    if (autoTheater)
    {
    debugLog("YTHD | A new video has loaded");

    if (autoTheater)
    {
    setTheaterMode(ytPlayer);
    }
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }

    currentVid = loadedVid;
    setTheaterMode();
    ytPlayer.setSize(-1, -1);
    }
    }
    }, true );
  24. @adisib adisib revised this gist May 4, 2017. 1 changed file with 51 additions and 11 deletions.
    62 changes: 51 additions & 11 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -23,17 +23,15 @@
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.05.04
    // - Added optional feature to automatically open videos in theater mode
    // - Added work-around for a bug in newer versions of Firefox causing undesired resolution changes

    // 2017.03.28
    // - Fixed playlist height issue when resized
    // - Resolution will now set for gaming.youtube.com by default as well
    // - Various minor improvements

    // 2017.03.23
    // - Fixed resolution not being set when changing videos while in fullscreen
    // - Probably a video loading speed improvement when buffer is flushed
    // - As a side effect, should now work for embedded youtube players (but will always be disabled by default)
    // - Various minor improvements

    (function() {

    "use strict";
    @@ -63,6 +61,9 @@
    const useCustomSize = false;
    const customHeight = 600, customWidth = 1280;

    // If autoTheater is true, each video page opened will default to stage mode.
    const autoTheater = false;

    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed
    @@ -85,7 +86,7 @@
    const widths = [7680, 5120, 3840, 2560, 1920, 1280, 854, 640, 480, 480];

    let doc = document, win = window;
    let curURL = win.location.href;
    let currentVid = "";


    // --------------------
    @@ -184,11 +185,31 @@
    // --------------------


    function setTheaterMode(ytPlayer)
    {
    debugLog("YTHD | Setting Theater Mode");

    let page = document.getElementById("page");
    if (page && page.className.indexOf("stage-mode") === -1)
    {
    page.className = page.className + " watch-stage-mode watch-wide";
    }
    }


    // --------------------


    // resize the player
    function resizePlayer(ytPlayer, width, height)
    {
    debugLog("YTHD | Setting video player size");

    if (autoTheater)
    {
    setTheaterMode(ytPlayer);
    }

    let left, playlistTop, playlistHeight;
    left = (-width/2);
    playlistTop = (height - 360);
    @@ -228,7 +249,7 @@

    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (changePlayerSize && curURL.indexOf("youtube.com") !== -1 && curURL.indexOf("gaming.") === -1)
    if (changePlayerSize && win.location.href.indexOf("youtube.com") !== -1 && win.location.href.indexOf("gaming.") === -1)
    {
    let width, height;
    if (useCustomSize)
    @@ -262,13 +283,32 @@
    {
    setResOnReady(ytPlayer, resolutions);
    }
    }

    if (changeResolution || autoTheater)
    {
    window.addEventListener("loadstart", function() {
    debugLog("YTHD | Load event fired");

    ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer && curURL !== window.location.href)
    if (ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    curURL = win.location.href;
    let loadedVid = getVideoIDFromURL(ytPlayer);
    if (currentVid !== loadedVid)
    {
    debugLog("YTHD | A new video has loaded");

    if (autoTheater)
    {
    setTheaterMode(ytPlayer);
    }
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }

    currentVid = loadedVid;
    }
    }
    }, true );
    }
  25. @adisib adisib revised this gist May 4, 2017. 1 changed file with 5 additions and 3 deletions.
    8 changes: 5 additions & 3 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.04.02
    // @version 2017.05.04
    // @include http://youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    @@ -85,6 +85,7 @@
    const widths = [7680, 5120, 3840, 2560, 1920, 1280, 854, 640, 480, 480];

    let doc = document, win = window;
    let curURL = win.location.href;


    // --------------------
    @@ -227,7 +228,7 @@

    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (changePlayerSize && win.location.href.indexOf("youtube.com") !== -1 && win.location.href.indexOf("gaming.") === -1)
    if (changePlayerSize && curURL.indexOf("youtube.com") !== -1 && curURL.indexOf("gaming.") === -1)
    {
    let width, height;
    if (useCustomSize)
    @@ -264,9 +265,10 @@

    window.addEventListener("loadstart", function() {
    ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer)
    if (ytPlayer && curURL !== window.location.href)
    {
    setResOnReady(ytPlayer, resolutions);
    curURL = win.location.href;
    }
    }, true );
    }
  26. @adisib adisib revised this gist Apr 3, 2017. 1 changed file with 63 additions and 49 deletions.
    112 changes: 63 additions & 49 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,29 +3,36 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.03.23
    // @version 2017.04.02
    // @include http://youtube.com/*
    // @include http://www.youtube.com/*
    // @include https://youtube.com/*
    // @include http://www.youtube.com/*
    // @include https://www.youtube.com/*
    // @include http://gaming.youtube.com/*
    // @include https://gaming.youtube.com/*
    // @noframes
    // @grant none
    // ==/UserScript==

    // Only the html5 player is supported.
    // The video will only resize when in theater mode.
    // By default only runs youtube website, not players embeded on other websites.
    // The video will only resize when in theater mode on the main youtube website.
    // By default only runs on youtube website, not players embeded on other websites.
    // YouTube players embeded on other websites should work if enabled, but this feature is not supported.

    // To enable for embedded players outside of YouTube website, do the following steps:
    // To enable experimental support for embedded players outside of YouTube website, do the following steps:
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.03.28
    // - Fixed playlist height issue when resized
    // - Resolution will now set for gaming.youtube.com by default as well
    // - Various minor improvements

    // 2017.03.23
    // - Fixed resolution not being set when changing videos while in fullscreen
    // - Probably a video loading speed improvement when buffer is flushed
    // - As a side effect, should now work for embedded youtube players (but will always be disabled by default)
    // - various minor improvements
    // - Various minor improvements

    (function() {

    @@ -56,9 +63,9 @@
    const useCustomSize = false;
    const customHeight = 600, customWidth = 1280;

    // If flushBuffer is false, then the very beginning of the video may not be the desired resolution
    // If true, then the entire video will be guaranteed to be target resolution, but there may be
    // a small additional delay before the video starts
    // If flushBuffer is false, then the first second or so of the video may not always be the desired resolution
    // If true, then the entire video will be guaranteed to be the target resolution, but there may be
    // a very small additional delay before the video starts if the buffer needs to be flushed
    const flushBuffer = true;

    // --------------------
    @@ -77,20 +84,18 @@
    const heights = [4320, 2880, 2160, 1440, 1080, 720, 480, 360, 270, 270];
    const widths = [7680, 5120, 3840, 2560, 1920, 1280, 854, 640, 480, 480];

    let doc = document; let win = window;
    let doc = document, win = window;


    // --------------------


    function debugLog(message)
    {
    if (!DEBUG)
    if (DEBUG)
    {
    return;
    console.log(message);
    }

    console.log(message);
    }


    @@ -126,22 +131,25 @@
    }
    else
    {
    const len = resolutionList.length;
    let nextBestIndex = resolutionList.indexOf(targetRes) || 0;
    const end = resolutionList.length - 1;
    let nextBestIndex = Math.max(resolutionList.indexOf(targetRes), 0);
    let ytResolutions = ytPlayer.getAvailableQualityLevels();

    debugLog("YTHD | Available Resolutions: " + ytResolutions.join(", "));

    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < (len-1) )
    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < end )
    {
    ++nextBestIndex;
    }

    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromURL(ytPlayer);
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    if (id.indexOf('YTHD |') === -1)
    {
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }

    debugLog(id);
    }
    @@ -159,8 +167,8 @@
    // Set resolution, but only when API is ready (it should normally already be ready)
    function setResOnReady(ytPlayer, resolutionList)
    {
    if ( (ytPlayer.getPlayerState === undefined)
    // || (ytPlayer.getPlayerState() === -1) // This prevents a youtube bug where the video buffer gets stuck
    if ( (ytPlayer.getPlayerState === undefined)
    || (ytPlayer.getPlayerState() === -1) // This prevents a youtube bug where the video buffer gets stuck
    )
    {
    win.setTimeout(setResOnReady, 100, ytPlayer, resolutionList);
    @@ -180,17 +188,17 @@
    {
    debugLog("YTHD | Setting video player size");

    let heightStr, widthStr, leftStr, playlistTop;
    heightStr = height.toString() + "px !important";
    widthStr = width.toString() + "px !important";
    leftStr = (-width/2).toString() + "px !important";
    // TODO: Do more research on this
    playlistTop = (height - 360).toString() + "px !important";
    let left, playlistTop, playlistHeight;
    left = (-width/2);
    playlistTop = (height - 360);
    playlistHeight = (height - 100);

    let styleContent = "#page.watch-stage-mode .player-height { min-height: " + heightStr + "; } \
    #page.watch-stage-mode .player-width { left: " + leftStr + "; min-width: " + widthStr + "; } \
    #page.watch-stage-mode #watch-appbar-playlist {top: " + playlistTop + "; } \
    ";
    let styleContent = " \
    #page.watch-stage-mode .player-height { min-height: " + height + "px !important; } \
    #page.watch-stage-mode .player-width { left: " + left + "px !important; min-width: " + width + "px !important; } \
    #page.watch-stage-mode #watch-appbar-playlist {top: " + playlistTop + "px !important; } \
    #page.watch-stage-mode #playlist-autoscroll-list {max-height: " + playlistHeight + "px !important; } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    if (!ythdStyle)
    @@ -217,27 +225,33 @@
    // --- MAIN -----------


    let width, height;
    if (useCustomSize)
    {
    height = customHeight;
    width = customWidth;
    }
    else
    {
    let mastheadHeight = parseInt(win.getComputedStyle(doc.getElementById("masthead-positioner-height-offset")).height, 10) || 50;
    let mastheadPadding = (parseInt(win.getComputedStyle(doc.getElementById("yt-masthead-container")).paddingBottom, 10) * 2) || 16;
    let heightOffset = mastheadHeight + mastheadPadding;

    let i = resolutions.indexOf(targetRes) || 0;
    height = Math.min(heights[i], win.innerHeight - heightOffset);
    width = Math.min(widths[i], win.innerWidth);
    }

    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (changePlayerSize)
    if (changePlayerSize && win.location.href.indexOf("youtube.com") !== -1 && win.location.href.indexOf("gaming.") === -1)
    {
    let width, height;
    if (useCustomSize)
    {
    height = customHeight;
    width = customWidth;
    }
    else
    {
    // don't include youtube search bar as part of the space the video can try to fit in
    let heightOffsetEl = doc.getElementById("masthead-positioner-height-offset");
    let mastheadContainerEl = doc.getElementById("yt-masthead-container");
    let mastheadHeight = 0, mastheadPadding = 0;
    if (heightOffsetEl && mastheadContainerEl)
    {
    mastheadHeight = parseInt(win.getComputedStyle(heightOffsetEl).height, 10) || 50;
    mastheadPadding = (parseInt(win.getComputedStyle(mastheadContainerEl).paddingBottom, 10) * 2) || 16;
    }

    let i = Math.max(resolutions.indexOf(targetRes), 0);
    height = Math.min(heights[i], win.innerHeight - (mastheadHeight + mastheadPadding));
    width = Math.min(widths[i], win.innerWidth);
    }

    resizePlayer(ytPlayer, width, height);
    }

  27. @adisib adisib revised this gist Mar 23, 2017. 1 changed file with 29 additions and 31 deletions.
    60 changes: 29 additions & 31 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,7 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2017.01.01
    // @version 2017.03.23
    // @include http://youtube.com/*
    // @include http://www.youtube.com/*
    // @include https://youtube.com/*
    @@ -14,9 +14,17 @@

    // Only the html5 player is supported.
    // The video will only resize when in theater mode.
    // Only supports youtube website, not players embeded on other websites.
    // By default only runs youtube website, not players embeded on other websites.
    // YouTube players embeded on other websites should work if enabled, but this feature is not supported.

    // 2017.01.01
    // To enable for embedded players outside of YouTube website, do the following steps:
    // add " @include * " to the script metadata
    // remove " @noframes " from the script metadata

    // 2017.03.23
    // - Fixed resolution not being set when changing videos while in fullscreen
    // - Probably a video loading speed improvement when buffer is flushed
    // - As a side effect, should now work for embedded youtube players (but will always be disabled by default)
    // - various minor improvements

    (function() {
    @@ -89,12 +97,12 @@
    // --------------------


    // Get video ID from page div class
    function getVideoIDFromPage()
    // Get video ID from the currently loaded video (which might be different than currently loaded page)
    function getVideoIDFromURL(ytPlayer)
    {
    const idMatch = /(?:video-)([\S]+)/;
    let pageClass = doc.getElementById("page").className;
    let id = idMatch.exec(pageClass)[1] || "YTHD | ERROR: idMatch failed; youtube changed something";
    const idMatch = /(?:v=)([\w\-]+)/;
    let videoURL = ytPlayer.getVideoUrl();
    let id = idMatch.exec(videoURL)[1] || "YTHD | ERROR: idMatch failed; youtube changed something";

    return id;
    }
    @@ -131,7 +139,7 @@

    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromPage();
    let id = getVideoIDFromURL(ytPlayer);
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);

    @@ -187,7 +195,7 @@
    let ythdStyle = doc.getElementById("ythdStyleSheet");
    if (!ythdStyle)
    {
    ythdStyle = doc.createElement("STYLE");
    ythdStyle = doc.createElement("style");
    ythdStyle.type = "text/css";
    ythdStyle.id = "ythdStyleSheet";
    ythdStyle.innerHTML = styleContent;
    @@ -226,37 +234,27 @@
    width = Math.min(widths[i], win.innerWidth);
    }

    let ytPlayer = doc.getElementById("movie_player");
    let ytPlayer = doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];

    if (changePlayerSize)
    {
    resizePlayer(ytPlayer, width, height);
    }

    if (changeResolution && ytPlayer)
    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    if (ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }

    // This requires a check because youtube doesn't actually load a new video page instead using ajax
    // The page div class holds the video id and stage mode state, so just check for changes on its class
    let pageDiv = doc.getElementById("page");
    if (changeResolution && pageDiv)
    {
    let prevClass = pageDiv.className;
    let ytVidMutationObserver = new MutationObserver( function(mutations) {
    if(prevClass !== pageDiv.className) // Fullscreen will rewrite className with same content
    window.addEventListener("loadstart", function() {
    ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0];
    if (ytPlayer)
    {
    ytPlayer = ytPlayer || doc.getElementById("movie_player");
    if (ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    prevClass = pageDiv.className;
    setResOnReady(ytPlayer, resolutions);
    }
    } );
    let MOInitOps = { attributes: true, attributeFilter: ["class"] };
    ytVidMutationObserver.observe(pageDiv, MOInitOps);
    }, true );
    }

    })();
  28. @adisib adisib revised this gist Jan 1, 2017. 1 changed file with 94 additions and 110 deletions.
    204 changes: 94 additions & 110 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -3,19 +3,22 @@
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2016.10.02
    // @include http://youtube.com*
    // @include http://www.youtube.com*
    // @include https://youtube.com*
    // @include https://www.youtube.com*
    // @version 2017.01.01
    // @include http://youtube.com/*
    // @include http://www.youtube.com/*
    // @include https://youtube.com/*
    // @include https://www.youtube.com/*
    // @noframes
    // @grant none
    // ==/UserScript==

    // Only the html5 player is supported.
    // The video will not resize when not in theater mode.
    // The video will only resize when in theater mode.
    // Only supports youtube website, not players embeded on other websites.

    // 2017.01.01
    // - various minor improvements

    (function() {

    "use strict";
    @@ -24,18 +27,18 @@

    // Target Resolution to always set to. If not available, the next best resolution will be used.
    const changeResolution = true;
    const targetRes = "hd720";
    const targetRes = "hd1080";
    // Choices for targetRes are currently:
    // "highres" | ( 8K / 4320p / QUHD )
    // "hd2880" | ( 5K / 2880p / UHD+ )
    // "hd2160" | ( 4K / 2160p / UHD )
    // "hd1440" | ( 1440p / QHD )
    // "hd1080" | ( 1080p / FHD )
    // "hd720" | ( 720p / HD )
    // "large" | ( 480p )
    // "medium" | ( 360p )
    // "small" | ( 240p )
    // "tiny" | ( 144p )
    // "highres" >= ( 8K / 4320p / QUHD )
    // "hd2880" = ( 5K / 2880p / UHD+ )
    // "hd2160" = ( 4K / 2160p / UHD )
    // "hd1440" = ( 1440p / QHD )
    // "hd1080" = ( 1080p / FHD )
    // "hd720" = ( 720p / HD )
    // "large" = ( 480p )
    // "medium" = ( 360p )
    // "small" = ( 240p )
    // "tiny" = ( 144p )

    // If changePlayerSize is true, then the video's size will be changed on the page
    // instead of using youtube's default (if theater mode is enabled).
    @@ -72,35 +75,54 @@
    // --------------------


    // Attempt to set the video resolution to desired quality or the next best quality
    function setResolution(ytPlayer, resolutionList)
    function debugLog(message)
    {
    if (DEBUG)
    if (!DEBUG)
    {
    console.log("YTHD | Setting Resolution...");
    return;
    }

    console.log(message);
    }


    // --------------------


    // Get video ID from page div class
    function getVideoIDFromPage()
    {
    const idMatch = /(?:video-)([\S]+)/;
    let pageClass = doc.getElementById("page").className;
    let id = idMatch.exec(pageClass)[1] || "YTHD | ERROR: idMatch failed; youtube changed something";

    return id;
    }


    // --------------------


    // Attempt to set the video resolution to desired quality or the next best quality
    function setResolution(ytPlayer, resolutionList)
    {
    debugLog("YTHD | Setting Resolution...");

    // Youtube doesn't return "auto" for auto, so set to make sure that auto is not set by setting
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    ytPlayer.setPlaybackQuality(targetRes);

    if (DEBUG)
    {
    console.log("YTHD | Resolution Set To: " + targetRes);
    }
    debugLog("YTHD | Resolution Set To: " + targetRes);
    }
    else
    {
    let ytResolutions = ytPlayer.getAvailableQualityLevels();
    const len = resolutionList.length;
    let nextBestIndex = resolutionList.indexOf(targetRes) || 0;
    let len = resolutionList.length;
    let ytResolutions = ytPlayer.getAvailableQualityLevels();

    if (DEBUG)
    {
    console.log("YTHD | Available Resolutions: " + ytResolutions.join(", "));
    }
    debugLog("YTHD | Available Resolutions: " + ytResolutions.join(", "));

    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < (len-1) )
    {
    @@ -112,13 +134,12 @@
    let id = getVideoIDFromPage();
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);

    debugLog(id);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    if (DEBUG)
    {
    console.log("YTHD | Resolution Set To: " + resolutionList[nextBestIndex]);
    }
    debugLog("YTHD | Resolution Set To: " + resolutionList[nextBestIndex]);
    }

    }
    @@ -127,21 +148,7 @@
    // --------------------


    // Get video ID from page div class
    function getVideoIDFromPage()
    {
    let pageClass = document.getElementById("page").className;
    let idMatch = /(?:video-)([\S]+)/;
    let id = idMatch.exec(pageClass)[1] || "ERROR: idMatch needs modification";

    return id;
    }


    // --------------------


    // Set resolution, but only when API is ready
    // Set resolution, but only when API is ready (it should normally already be ready)
    function setResOnReady(ytPlayer, resolutionList)
    {
    if ( (ytPlayer.getPlayerState === undefined)
    @@ -163,74 +170,38 @@
    // resize the player
    function resizePlayer(ytPlayer, width, height)
    {
    if (DEBUG)
    {
    console.log("YTHD | Setting video player size");
    }
    debugLog("YTHD | Setting video player size");

    let heightStr, widthStr, leftStr, playlistTop;
    heightStr = height.toString() + "px !important";
    widthStr = width.toString() + "px !important";
    leftStr = (-width/2).toString() + "px !important";
    // TODO: Do more research on this
    playlistTop = (height - 360).toString() + "px !important";

    let styleContent = "#page.watch-stage-mode .player-height { min-height: " + heightStr + "; } \
    #page.watch-stage-mode .player-width { left: " + leftStr + "; min-width: " + widthStr + "; } \
    #page.watch-stage-mode #watch-appbar-playlist {top: " + playlistTop + "; } \
    ";

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    if (!ythdStyle)
    {
    ythdStyle = doc.createElement("style");
    ythdStyle = doc.createElement("STYLE");
    ythdStyle.type = "text/css";
    ythdStyle.id = "ythdStyleSheet";
    ythdStyle.innerHTML = styleContent;
    doc.head.appendChild(ythdStyle);
    }

    let heightStr, widthStr, leftStr, playlistTop;
    if (doc.getElementById("page").className.indexOf("watch-stage-mode") !== -1)
    {
    heightStr = height.toString() + "px !important";
    widthStr = width.toString() + "px !important";
    leftStr = (-width/2).toString() + "px !important";

    // TODO: Do more research on this
    playlistTop = (height - 360).toString() + "px !important";
    }
    else
    {
    heightStr = widthStr = leftStr = playlistTop = "0px";
    }

    let styleContent = ".player-height { min-height: " + heightStr + "; } \
    .player-width { left: " + leftStr + "; min-width: " + widthStr + "; } \
    #watch-appbar-playlist {top: " + playlistTop + "; } \
    ";

    if (styleContent !== ythdStyle.innerHTML)
    {
    ythdStyle.innerHTML = styleContent;

    // Youtube's video player wont resize itself until interacted with so remind it to resize on video page
    if (ytPlayer)
    {
    ytPlayer.setSize(width, height);
    }
    }
    }


    // --------------------


    // Set HD and Resize if appropriate
    function runActions(width, height)
    {
    let ytPlayer = doc.getElementById("movie_player");

    if (changePlayerSize)
    {
    resizePlayer(ytPlayer, width, height);
    }

    if (!ytPlayer || win.location.href.indexOf("/watch") === -1)
    // Youtube's video player wont resize itself until interacted with so remind it to resize on video page
    if (ytPlayer)
    {
    return;
    }

    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    ytPlayer.setSize(width, height);
    }
    }

    @@ -248,27 +219,40 @@
    {
    let mastheadHeight = parseInt(win.getComputedStyle(doc.getElementById("masthead-positioner-height-offset")).height, 10) || 50;
    let mastheadPadding = (parseInt(win.getComputedStyle(doc.getElementById("yt-masthead-container")).paddingBottom, 10) * 2) || 16;
    let heightOffset = (mastheadHeight + mastheadPadding);
    let heightOffset = mastheadHeight + mastheadPadding;

    let i = resolutions.indexOf(targetRes) || 0;
    height = Math.min(heights[i], win.innerHeight - heightOffset);
    width = Math.min(widths[i], win.innerWidth);
    }

    runActions(width, height);
    let ytPlayer = doc.getElementById("movie_player");

    if (changePlayerSize)
    {
    resizePlayer(ytPlayer, width, height);
    }

    if (changeResolution && ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }

    // This requires a check because youtube doesn't actually load a new video page instead using ajax
    // The page div class holds the video id and stage mode state, so just check for changes on its class
    let pageDiv = doc.getElementById("page");
    if (pageDiv)
    if (changeResolution && pageDiv)
    {
    let prevClass = pageDiv.className;
    let ytVidMutationObserver = new MutationObserver( function(mutations) {
    // Fullscreen will rewrite className with same content
    if(prevClass !== pageDiv.className)
    if(prevClass !== pageDiv.className) // Fullscreen will rewrite className with same content
    {
    ytPlayer = ytPlayer || doc.getElementById("movie_player");
    if (ytPlayer)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    prevClass = pageDiv.className;
    runActions(width, height);
    }
    } );
    let MOInitOps = { attributes: true, attributeFilter: ["class"] };
  29. @adisib adisib created this gist Oct 2, 2016.
    278 changes: 278 additions & 0 deletions youtube_hd.user.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,278 @@
    // ==UserScript==
    // @name Youtube HD
    // @author adisib
    // @namespace namespace_adisib
    // @description Select a youtube resolution and resize the player.
    // @version 2016.10.02
    // @include http://youtube.com*
    // @include http://www.youtube.com*
    // @include https://youtube.com*
    // @include https://www.youtube.com*
    // @noframes
    // @grant none
    // ==/UserScript==

    // Only the html5 player is supported.
    // The video will not resize when not in theater mode.
    // Only supports youtube website, not players embeded on other websites.

    (function() {

    "use strict";

    // --- SETTINGS -------

    // Target Resolution to always set to. If not available, the next best resolution will be used.
    const changeResolution = true;
    const targetRes = "hd720";
    // Choices for targetRes are currently:
    // "highres" | ( 8K / 4320p / QUHD )
    // "hd2880" | ( 5K / 2880p / UHD+ )
    // "hd2160" | ( 4K / 2160p / UHD )
    // "hd1440" | ( 1440p / QHD )
    // "hd1080" | ( 1080p / FHD )
    // "hd720" | ( 720p / HD )
    // "large" | ( 480p )
    // "medium" | ( 360p )
    // "small" | ( 240p )
    // "tiny" | ( 144p )

    // If changePlayerSize is true, then the video's size will be changed on the page
    // instead of using youtube's default (if theater mode is enabled).
    // If useCustomSize is false, then the player will be resized to try to match the target resolution.
    // If true, then it will use the customHeight and customWidth variables.
    const changePlayerSize = false;
    const useCustomSize = false;
    const customHeight = 600, customWidth = 1280;

    // If flushBuffer is false, then the very beginning of the video may not be the desired resolution
    // If true, then the entire video will be guaranteed to be target resolution, but there may be
    // a small additional delay before the video starts
    const flushBuffer = true;

    // --------------------




    // --- GLOBALS --------


    const DEBUG = false;

    // Possible resolution choices (in decreasing order, i.e. highres is the best):
    const resolutions = ['highres', 'hd2880', 'hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny'];
    // youtube is always 16:9 right now, but has to be at least 480x270 for the player UI
    const heights = [4320, 2880, 2160, 1440, 1080, 720, 480, 360, 270, 270];
    const widths = [7680, 5120, 3840, 2560, 1920, 1280, 854, 640, 480, 480];

    let doc = document; let win = window;


    // --------------------


    // Attempt to set the video resolution to desired quality or the next best quality
    function setResolution(ytPlayer, resolutionList)
    {
    if (DEBUG)
    {
    console.log("YTHD | Setting Resolution...");
    }

    // Youtube doesn't return "auto" for auto, so set to make sure that auto is not set by setting
    // even when already at target res or above, but do so without removing the buffer for this quality
    if (resolutionList.indexOf(targetRes) >= resolutionList.indexOf(ytPlayer.getPlaybackQuality()))
    {
    ytPlayer.setPlaybackQuality(targetRes);

    if (DEBUG)
    {
    console.log("YTHD | Resolution Set To: " + targetRes);
    }
    }
    else
    {
    let ytResolutions = ytPlayer.getAvailableQualityLevels();
    let nextBestIndex = resolutionList.indexOf(targetRes) || 0;
    let len = resolutionList.length;

    if (DEBUG)
    {
    console.log("YTHD | Available Resolutions: " + ytResolutions.join(", "));
    }

    while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < (len-1) )
    {
    ++nextBestIndex;
    }

    if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex])
    {
    let id = getVideoIDFromPage();
    let pos = ytPlayer.getCurrentTime();
    ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]);
    }
    ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]);

    if (DEBUG)
    {
    console.log("YTHD | Resolution Set To: " + resolutionList[nextBestIndex]);
    }
    }

    }


    // --------------------


    // Get video ID from page div class
    function getVideoIDFromPage()
    {
    let pageClass = document.getElementById("page").className;
    let idMatch = /(?:video-)([\S]+)/;
    let id = idMatch.exec(pageClass)[1] || "ERROR: idMatch needs modification";

    return id;
    }


    // --------------------


    // Set resolution, but only when API is ready
    function setResOnReady(ytPlayer, resolutionList)
    {
    if ( (ytPlayer.getPlayerState === undefined)
    // || (ytPlayer.getPlayerState() === -1) // This prevents a youtube bug where the video buffer gets stuck
    )
    {
    win.setTimeout(setResOnReady, 100, ytPlayer, resolutionList);
    }
    else
    {
    setResolution(ytPlayer, resolutionList);
    }
    }


    // --------------------


    // resize the player
    function resizePlayer(ytPlayer, width, height)
    {
    if (DEBUG)
    {
    console.log("YTHD | Setting video player size");
    }

    let ythdStyle = doc.getElementById("ythdStyleSheet");
    if (!ythdStyle)
    {
    ythdStyle = doc.createElement("style");
    ythdStyle.type = "text/css";
    ythdStyle.id = "ythdStyleSheet";
    doc.head.appendChild(ythdStyle);
    }

    let heightStr, widthStr, leftStr, playlistTop;
    if (doc.getElementById("page").className.indexOf("watch-stage-mode") !== -1)
    {
    heightStr = height.toString() + "px !important";
    widthStr = width.toString() + "px !important";
    leftStr = (-width/2).toString() + "px !important";

    // TODO: Do more research on this
    playlistTop = (height - 360).toString() + "px !important";
    }
    else
    {
    heightStr = widthStr = leftStr = playlistTop = "0px";
    }

    let styleContent = ".player-height { min-height: " + heightStr + "; } \
    .player-width { left: " + leftStr + "; min-width: " + widthStr + "; } \
    #watch-appbar-playlist {top: " + playlistTop + "; } \
    ";

    if (styleContent !== ythdStyle.innerHTML)
    {
    ythdStyle.innerHTML = styleContent;

    // Youtube's video player wont resize itself until interacted with so remind it to resize on video page
    if (ytPlayer)
    {
    ytPlayer.setSize(width, height);
    }
    }
    }


    // --------------------


    // Set HD and Resize if appropriate
    function runActions(width, height)
    {
    let ytPlayer = doc.getElementById("movie_player");

    if (changePlayerSize)
    {
    resizePlayer(ytPlayer, width, height);
    }

    if (!ytPlayer || win.location.href.indexOf("/watch") === -1)
    {
    return;
    }

    if (changeResolution)
    {
    setResOnReady(ytPlayer, resolutions);
    }
    }


    // --- MAIN -----------


    let width, height;
    if (useCustomSize)
    {
    height = customHeight;
    width = customWidth;
    }
    else
    {
    let mastheadHeight = parseInt(win.getComputedStyle(doc.getElementById("masthead-positioner-height-offset")).height, 10) || 50;
    let mastheadPadding = (parseInt(win.getComputedStyle(doc.getElementById("yt-masthead-container")).paddingBottom, 10) * 2) || 16;
    let heightOffset = (mastheadHeight + mastheadPadding);

    let i = resolutions.indexOf(targetRes) || 0;
    height = Math.min(heights[i], win.innerHeight - heightOffset);
    width = Math.min(widths[i], win.innerWidth);
    }

    runActions(width, height);

    // This requires a check because youtube doesn't actually load a new video page instead using ajax
    // The page div class holds the video id and stage mode state, so just check for changes on its class
    let pageDiv = doc.getElementById("page");
    if (pageDiv)
    {
    let prevClass = pageDiv.className;
    let ytVidMutationObserver = new MutationObserver( function(mutations) {
    // Fullscreen will rewrite className with same content
    if(prevClass !== pageDiv.className)
    {
    prevClass = pageDiv.className;
    runActions(width, height);
    }
    } );
    let MOInitOps = { attributes: true, attributeFilter: ["class"] };
    ytVidMutationObserver.observe(pageDiv, MOInitOps);
    }

    })();