-
-
Save adityatelange/f88b4f79f45b6d5c282073a16b6c0b2a to your computer and use it in GitHub Desktop.
Make youtube videos in HD and automatically resize
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Youtube HD | |
| // @author adisib | |
| // @namespace namespace_adisib | |
| // @description Select a youtube resolution and resize the player. | |
| // @version 2017.03.23 | |
| // @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 only resize when in theater mode. | |
| // 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. | |
| // 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() { | |
| "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 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; | |
| // -------------------- | |
| function debugLog(message) | |
| { | |
| if (!DEBUG) | |
| { | |
| return; | |
| } | |
| console.log(message); | |
| } | |
| // -------------------- | |
| // 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] || "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); | |
| debugLog("YTHD | Resolution Set To: " + targetRes); | |
| } | |
| else | |
| { | |
| const len = resolutionList.length; | |
| let nextBestIndex = resolutionList.indexOf(targetRes) || 0; | |
| let ytResolutions = ytPlayer.getAvailableQualityLevels(); | |
| debugLog("YTHD | Available Resolutions: " + ytResolutions.join(", ")); | |
| while ( (ytResolutions.indexOf(resolutionList[nextBestIndex]) === -1) && nextBestIndex < (len-1) ) | |
| { | |
| ++nextBestIndex; | |
| } | |
| if (flushBuffer && ytPlayer.getPlaybackQuality() !== resolutionList[nextBestIndex]) | |
| { | |
| let id = getVideoIDFromURL(ytPlayer); | |
| let pos = ytPlayer.getCurrentTime(); | |
| ytPlayer.loadVideoById(id, pos, resolutionList[nextBestIndex]); | |
| debugLog(id); | |
| } | |
| ytPlayer.setPlaybackQuality(resolutionList[nextBestIndex]); | |
| debugLog("YTHD | 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.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) | |
| { | |
| 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.type = "text/css"; | |
| ythdStyle.id = "ythdStyleSheet"; | |
| ythdStyle.innerHTML = styleContent; | |
| doc.head.appendChild(ythdStyle); | |
| } | |
| else | |
| { | |
| 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); | |
| } | |
| } | |
| // --- 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) | |
| { | |
| resizePlayer(ytPlayer, width, height); | |
| } | |
| if (changeResolution) | |
| { | |
| if (ytPlayer) | |
| { | |
| setResOnReady(ytPlayer, resolutions); | |
| } | |
| window.addEventListener("loadstart", function() { | |
| ytPlayer = ytPlayer || doc.getElementById("movie_player") || doc.getElementsByClassName("html5-video-player")[0]; | |
| if (ytPlayer) | |
| { | |
| setResOnReady(ytPlayer, resolutions); | |
| } | |
| }, true ); | |
| } | |
| })(); |
Author
Author
Bookmark
javascript:!function(){"use strict";const e=!0,t="hd1080",n=!1,i=!1,a=600,l=!1,o=!0,d=!1,r=!0,y=!0,s=!1,c=["highres","hd2880","hd2160","hd1440","hd1080","hd720","large","medium","small","tiny"],h=[4320,2880,2160,1440,1080,720,480,360,270,270];let m=document,g=window,u="",f=0;function p(e){s&&console.log("YTHD | "+e)}function v(e){return e&&e.wrappedJSObject?e.wrappedJSObject:e}function x(e){let t=e.getVideoUrl();return/(?:v=)([\w\-]+)/.exec(t)[1]||"ERROR: idMatch failed; youtube changed something"}function E(e,n){if(void 0===e.getPlaybackQuality)g.setTimeout(E,100,e,n);else{let i=x(e);if(i!==u){u=i,function(e,n){if(p("Setting Resolution..."),n.indexOf(t)>=n.indexOf(e.getPlaybackQuality()))return void 0!==e.setPlaybackQualityRange&&e.setPlaybackQualityRange(t),e.setPlaybackQuality(t),void p("Resolution Set To: "+t);const i=n.length-1;let a=Math.max(n.indexOf(t),0),l=e.getAvailableQualityLevels();for(p("Available Resolutions: "+l.join(", "));-1===l.indexOf(n[a])&&a<i;)++a;if(o&&e.getPlaybackQuality()!==n[a]){let t=x(e);if(-1===t.indexOf("ERROR: ")){let i=e.getCurrentTime();e.loadVideoById(t,i,n[a])}p("ID: "+t)}void 0!==e.setPlaybackQualityRange&&e.setPlaybackQualityRange(n[a]),e.setPlaybackQuality(n[a]),p("Resolution Set To: "+n[a])}(e,n);let a=localStorage.getItem("yt-player-quality");if(!a||-1===a.indexOf(t)){let e=Date.now(),n=e+2592e6;localStorage.setItem("yt-player-quality",'{"data":"'+t+'","expiration":'+n+',"creation":'+e+"}")}}}}function S(e){if(p("Setting Theater Mode"),-1!==g.location.href.indexOf("/watch")){let e=v(m.getElementsByTagName("ytd-watch-flexy")[0]);if(e){if(y){const e="#error-screen { z-index: 42 !important } .ytp-error { display: none !important }";let t=m.getElementById("ythdErrorWorkaroundStyleSheet");t?t.innerHTML=e:((t=m.createElement("style")).type="text/css",t.id="ythdStyleSheet",t.innerHTML=e,m.head.appendChild(t))}try{e.theaterModeChanged_(!0)}catch(e){}}}}function b(){let e=a;if(!i){let n=m.getElementById("masthead"),i=m.getElementById("masthead-container"),a=50,l=16;n&&i&&(a=parseInt(g.getComputedStyle(n).height,10),l=2*parseInt(g.getComputedStyle(i).paddingBottom,10));let o=Math.max(c.indexOf(t),0);e=Math.min(h[o],g.innerHeight-(a+l))}!function(e){if(p("Setting video player size"),f===e)return void p("Player size already set");let t="\t\tytd-watch-flexy[theater]:not([fullscreen]) #player-theater-container.style-scope { \t\t\tmin-height: "+e+"px !important; max-height: none !important; height: "+e+"px !important } \t\t",n=m.getElementById("ythdStyleSheet");n?n.innerHTML=t:((n=m.createElement("style")).type="text/css",n.id="ythdStyleSheet",n.innerHTML=t,m.head.appendChild(n));f=e,g.dispatchEvent(new Event("resize"))}(e)}function w(){let t=m.getElementById("movie_player")||m.getElementsByClassName("html5-video-player")[0],i=v(t);l&&i&&(d&&-1===m.cookie.indexOf("wide=1")&&(m.cookie="wide=1; domain=.youtube.com"),S()),n&&-1!==g.location.host.indexOf("youtube.com")&&-1===g.location.host.indexOf("gaming.")&&(b(),window.addEventListener("resize",b,!0)),e&&r&&i&&E(i,c),(e||l)&&g.addEventListener("loadstart",function(n){n.target instanceof g.HTMLMediaElement&&(t=m.getElementById("movie_player")||m.getElementsByClassName("html5-video-player")[0],(i=v(t))&&(p("Loaded new video"),e&&E(i,c),l&&S()))},!0),g.removeEventListener("yt-navigate-finish",w,!0)}w(),g.addEventListener("yt-navigate-finish",w,!0)}();
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
minified
!function(){"use strict";const e=!0,t="hd1080",n=!1,i=!1,a=600,l=!1,o=!0,d=!1,r=!0,y=!0,s=!1,c=["highres","hd2880","hd2160","hd1440","hd1080","hd720","large","medium","small","tiny"],h=[4320,2880,2160,1440,1080,720,480,360,270,270];let m=document,g=window,u="",f=0;function p(e){s&&console.log("YTHD | "+e)}function v(e){return e&&e.wrappedJSObject?e.wrappedJSObject:e}function x(e){let t=e.getVideoUrl();return/(?:v=)([\w\-]+)/.exec(t)[1]||"ERROR: idMatch failed; youtube changed something"}function E(e,n){if(void 0===e.getPlaybackQuality)g.setTimeout(E,100,e,n);else{let i=x(e);if(i!==u){u=i,function(e,n){if(p("Setting Resolution..."),n.indexOf(t)>=n.indexOf(e.getPlaybackQuality()))return void 0!==e.setPlaybackQualityRange&&e.setPlaybackQualityRange(t),e.setPlaybackQuality(t),void p("Resolution Set To: "+t);const i=n.length-1;let a=Math.max(n.indexOf(t),0),l=e.getAvailableQualityLevels();for(p("Available Resolutions: "+l.join(", "));-1===l.indexOf(n[a])&&a<i;)++a;if(o&&e.getPlaybackQuality()!==n[a]){let t=x(e);if(-1===t.indexOf("ERROR: ")){let i=e.getCurrentTime();e.loadVideoById(t,i,n[a])}p("ID: "+t)}void 0!==e.setPlaybackQualityRange&&e.setPlaybackQualityRange(n[a]),e.setPlaybackQuality(n[a]),p("Resolution Set To: "+n[a])}(e,n);let a=localStorage.getItem("yt-player-quality");if(!a||-1===a.indexOf(t)){let e=Date.now(),n=e+2592e6;localStorage.setItem("yt-player-quality",'{"data":"'+t+'","expiration":'+n+',"creation":'+e+"}")}}}}function S(e){if(p("Setting Theater Mode"),-1!==g.location.href.indexOf("/watch")){let e=v(m.getElementsByTagName("ytd-watch-flexy")[0]);if(e){if(y){const e="#error-screen { z-index: 42 !important } .ytp-error { display: none !important }";let t=m.getElementById("ythdErrorWorkaroundStyleSheet");t?t.innerHTML=e:((t=m.createElement("style")).type="text/css",t.id="ythdStyleSheet",t.innerHTML=e,m.head.appendChild(t))}try{e.theaterModeChanged_(!0)}catch(e){}}}}function b(){let e=a;if(!i){let n=m.getElementById("masthead"),i=m.getElementById("masthead-container"),a=50,l=16;n&&i&&(a=parseInt(g.getComputedStyle(n).height,10),l=2*parseInt(g.getComputedStyle(i).paddingBottom,10));let o=Math.max(c.indexOf(t),0);e=Math.min(h[o],g.innerHeight-(a+l))}!function(e){if(p("Setting video player size"),f===e)return void p("Player size already set");let t="\t\tytd-watch-flexy[theater]:not([fullscreen]) #player-theater-container.style-scope { \t\t\tmin-height: "+e+"px !important; max-height: none !important; height: "+e+"px !important } \t\t",n=m.getElementById("ythdStyleSheet");n?n.innerHTML=t:((n=m.createElement("style")).type="text/css",n.id="ythdStyleSheet",n.innerHTML=t,m.head.appendChild(n));f=e,g.dispatchEvent(new Event("resize"))}(e)}function w(){let t=m.getElementById("movie_player")||m.getElementsByClassName("html5-video-player")[0],i=v(t);l&&i&&(d&&-1===m.cookie.indexOf("wide=1")&&(m.cookie="wide=1; domain=.youtube.com"),S()),n&&-1!==g.location.host.indexOf("youtube.com")&&-1===g.location.host.indexOf("gaming.")&&(b(),window.addEventListener("resize",b,!0)),e&&r&&i&&E(i,c),(e||l)&&g.addEventListener("loadstart",function(n){n.target instanceof g.HTMLMediaElement&&(t=m.getElementById("movie_player")||m.getElementsByClassName("html5-video-player")[0],(i=v(t))&&(p("Loaded new video"),e&&E(i,c),l&&S()))},!0),g.removeEventListener("yt-navigate-finish",w,!0)}w(),g.addEventListener("yt-navigate-finish",w,!0)}();