Repository: Zren/ResizeYoutubePlayerToWindowSize
Branch: master
Commit: 2ba94521d35f
Files: 9
Total size: 125.7 KB
Directory structure:
gitextract_ufeouyam/
├── 153699.user.js
├── README.md
├── ResizeRedditToWindowSize.user.js
├── ResizeVideoDescription.md
├── ResizeVideoToWindowSize.user.js
├── YTDocs.md
├── changelog.md
├── description.md
└── ytwp.css
================================================
FILE CONTENTS
================================================
================================================
FILE: 153699.user.js
================================================
// ==UserScript==
// @name Resize YT To Window Size
// @description Moves the YouTube video to the top of the website and fill the window with the video player.
// @author Chris H (Zren / Shade)
// @license MIT
// @icon https://s.ytimg.com/yts/img/favicon_32-vflOogEID.png
// @homepageURL https://github.com/Zren/ResizeYoutubePlayerToWindowSize/
// @namespace http://xshade.ca
// @version 139
// @include http*://*.youtube.com/*
// @include http*://youtube.com/*
// @include http*://*.youtu.be/*
// @include http*://youtu.be/*
// @grant none
// ==/UserScript==
// Github: https://github.com/Zren/ResizeYoutubePlayerToWindowSize
// GreasyFork: https://greasyfork.org/scripts/811-resize-yt-to-window-size
// OpenUserJS.org: https://openuserjs.org/scripts/zren/Resize_YT_To_Window_Size
// Userscripts.org: http://userscripts-mirror.org/scripts/show/153699
(function (window) {
"use strict";
//--- Settings
var playerHeight = '100vh';
var enableOnLoad = true;
var scriptToggleKey = 'w';
//--- Imported Globals
// yt
// ytcenter
// html5Patched (Youtube+)
// ytplayer
var uw = window;
//--- Already Loaded?
// GreaseMonkey loads this script twice for some reason.
if (uw.ytwp) return;
//--- Is iframe?
function inIframe () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
if (inIframe()) return;
//--- Utils
function isStringType(obj) { return typeof obj === 'string'; }
function isArrayType(obj) { return obj instanceof Array; }
function isObjectType(obj) { return typeof obj === 'object'; }
function isUndefined(obj) { return typeof obj === 'undefined'; }
function buildVenderPropertyDict(propertyNames, value) {
var d = {};
for (var i in propertyNames)
d[propertyNames[i]] = value;
return d;
}
function observe(selector, config, callback) {
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation){
callback(mutation);
});
});
var target = document.querySelector(selector);
if (!target) {
return null;
}
observer.observe(target, config);
return observer;
}
//--- Stylesheet
var JSStyleSheet = function(id) {
this.id = id;
this.stylesheet = '';
};
JSStyleSheet.prototype.buildRule = function(selector, styles) {
var s = "";
for (var key in styles) {
s += "\t" + key + ": " + styles[key] + ";\n";
}
return selector + " {\n" + s + "}\n";
};
JSStyleSheet.prototype.appendRule = function(selector, k, v) {
if (isArrayType(selector))
selector = selector.join(',\n');
var newStyle;
if (!isUndefined(k) && !isUndefined(v) && isStringType(k)) { // v can be any type (as we stringify it).
var d = {};
d[k] = v;
newStyle = this.buildRule(selector, d);
} else if (!isUndefined(k) && isUndefined(v) && isObjectType(k)) {
newStyle = this.buildRule(selector, k);
} else {
// Invalid Arguments
console.log('Illegal arguments', arguments);
return;
}
this.stylesheet += newStyle;
};
JSStyleSheet.injectIntoHeader = function(injectedStyleId, stylesheet) {
var styleElement = document.getElementById(injectedStyleId);
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.type = 'text/css';
styleElement.id = injectedStyleId;
document.getElementsByTagName('head')[0].appendChild(styleElement);
}
styleElement.appendChild(document.createTextNode(stylesheet));
};
JSStyleSheet.prototype.injectIntoHeader = function() {
JSStyleSheet.injectIntoHeader(this.id, this.stylesheet);
};
//--- History
var HistoryEvent = function() {}
HistoryEvent.listeners = []
HistoryEvent.dispatch = function(state, title, url) {
var stack = this.listeners
for (var i = 0, l = stack.length; i < l; i++) {
stack[i].call(this, state, title, url)
}
}
HistoryEvent.onPushState = function(state, title, url) {
HistoryEvent.dispatch(state, title, url)
return HistoryEvent.origPushState.apply(window.history, arguments)
}
HistoryEvent.onReplaceState = function(state, title, url) {
HistoryEvent.dispatch(state, title, url)
return HistoryEvent.origReplaceState.apply(window.history, arguments)
}
HistoryEvent.inject = function() {
if (!HistoryEvent.injected) {
HistoryEvent.origPushState = window.history.pushState
HistoryEvent.origReplaceState = window.history.replaceState
window.history.pushState = HistoryEvent.onPushState
window.history.replaceState = HistoryEvent.onReplaceState
HistoryEvent.injected = true
}
}
HistoryEvent.timerId = 0
HistoryEvent.onTick = function() {
var currentPage = window.location.pathname + window.location.search
if (HistoryEvent.lastPage != currentPage) {
HistoryEvent.dispatch({}, document.title, window.location.href)
HistoryEvent.lastPage = currentPage
}
}
HistoryEvent.startTimer = function() {
HistoryEvent.lastPage = window.location.pathname + window.location.search
HistoryEvent.timerId = setInterval(HistoryEvent.onTick, 500)
}
HistoryEvent.stopTimer = function() {
clearInterval(HistoryEvent.timerId)
}
window.ytwpHistoryEvent = HistoryEvent
//--- Constants
var scriptShortName = 'ytwp'; // YT Window Player
var scriptStyleId = scriptShortName + '-style'; // ytwp-style
var scriptBodyClassId = scriptShortName + '-window-player'; // .ytwp-window-player
var viewingVideoClassId = scriptShortName + '-viewing-video'; // .ytwp-viewing-video
var topOfPageClassId = scriptShortName + '-scrolltop'; // .ytwp-scrolltop
var scriptHtmlSelector = 'html:not([fullscreen="true"])';
var scriptBodySelector = 'body.' + scriptBodyClassId; // body.ytwp-window-player
scriptBodySelector += ':not(.enhancer-for-youtube-pinned-player)'; // Support "Enhancer for Youtube" (Pull Request #51)
var scriptSelector = scriptHtmlSelector + ' ' + scriptBodySelector;
var videoContainerId = 'player';
var videoContainerPlacemarkerId = scriptShortName + '-placemarker'; // ytwp-placemarker
var transitionProperties = ["transition", "-ms-transition", "-moz-transition", "-webkit-transition", "-o-transition"];
var transformProperties = ["transform", "-ms-transform", "-moz-transform", "-webkit-transform", "-o-transform"];
//--- YTWP
var ytwp = uw.ytwp = {
scriptShortName: scriptShortName, // YT Window Player
log_: function(logger, args) { logger.apply(console, ['[' + this.scriptShortName + '] '].concat(Array.prototype.slice.call(args))); return 1; },
log: function() { return this.log_(console.log, arguments); },
error: function() { return this.log_(console.error, arguments); },
initialized: false,
pageReady: false,
isWatchPage: false,
};
ytwp.debugPage = function() {
function prettyHtml(el) {
var s = el.outerHTML
return s.substr(0, s.indexOf('>')+1)
}
var defStyle = {
'display':'block', 'position': 'static',
'left': 'auto', 'right': 'auto', 'top': 'auto', 'bottom': 'auto',
'padding-left':'0px', 'padding-right':'0px', 'padding-top':'0px', 'padding-bottom':'0px',
'margin-left':'0px', 'margin-right':'0px', 'margin-top':'0px', 'margin-bottom':'0px',
'width': 'auto', 'min-width': 'auto', 'max-width': 'auto',
'height': 'auto', 'min-height': 'auto', 'max-height': 'auto',
}
var keyFilter = Object.keys(defStyle)
var node = document.querySelector('#movie_player video')
var outStr = ''
while (node && node.parentNode) {
var style = getComputedStyle(node)
var styleDiff = {}
for (var key of style) {
if (keyFilter.includes(key) && style[key] != defStyle[key]) {
styleDiff[key] = style[key]
}
}
outStr += prettyHtml(node) + ' ' + JSON.stringify(styleDiff) + '\n'
node = node.parentNode
}
outStr = outStr.split('\n').reverse().join('\n')
ytwp.log('debugPage', outStr)
}
ytwp.hasYoutubeChanged = function() {
var tree = [
'html',
'body',
'ytd-app',
'#content.ytd-app',
'ytd-page-manager#page-manager.ytd-app',
'ytd-watch-flexy.ytd-page-manager',
'#full-bleed-container.ytd-watch-flexy',
'#player-full-bleed-container.ytd-watch-flexy',
'#player-container.ytd-watch-flexy',
'ytd-player#ytd-player.ytd-watch-flexy',
'#container.ytd-player',
'.html5-video-player',
'.html5-video-container',
'video.html5-main-video',
]
tree = tree.reverse()
var node = document.querySelector(tree[0])
if (!node) {
ytwp.error('YT has changed!', tree[0], 'no longer exists!')
return true
}
for (var i = 1; i < tree.length; i++) {
var parent = node.parentNode
var selector = tree[i]
if (parent.matches(selector)) {
node = parent
} else {
ytwp.error('YT has changed!', selector, 'no longer exists!')
}
}
return false
}
ytwp.isWatchUrl = function (url) {
if (!url)
url = uw.location.href;
if (url.match(/https?:\/\/(www\.)?youtube.com\/(c|channel|user)\/[^\/]+\/live/)) {
if (document.querySelector('ytd-browse')) {
return false
} else {
return true
}
}
return url.match(/https?:\/\/(www\.)?youtube.com\/watch\?/);
};
ytwp.setTheaterMode = function(enable) {
// ytwp.log('setTheaterMode', enable)
var watchElement = document.querySelector('ytd-watch:not([hidden])') || document.querySelector('ytd-watch-flexy:not([hidden])') || document.querySelector('ytd-watch-grid:not([hidden])')
if (watchElement) {
var isTheater = watchElement.hasAttribute('theater')
if (enable != isTheater) {
// Note: (Issue #75) ytd-watch-flexy watchElement.querySelector() will find
// Nothing for some reason. We need to query from the document scope.
var sizeButton = document.querySelector(watchElement.tagName + ':not([hidden]) button.ytp-size-button')
if (!sizeButton) {
var screenModeButtons = document.querySelectorAll(watchElement.tagName + ':not([hidden]) button.ytp-screen-mode-settings-button')
sizeButton = screenModeButtons[1] // 2nd button is "Theater mode (t)"
}
if (sizeButton) {
sizeButton.click()
}
}
watchElement.canFitTheater_ = true // When it's too small, it disables the theater mode.
} else if (watchElement = document.querySelector('#page.watch')) {
var isTheater = watchElement.classList.contains('watch-stage-mode')
if (enable != isTheater) {
var sizeButton = watchElement.querySelector('button.ytp-size-button')
if (sizeButton) {
sizeButton.click()
}
}
}
}
ytwp.enterTheaterMode = function() {
// ytwp.log('enterTheaterMode')
if (!document.body.classList.contains(scriptBodyClassId)) {
return
}
ytwp.setTheaterMode(true)
}
ytwp.enterTheaterMode();
uw.addEventListener('resize', ytwp.enterTheaterMode);
ytwp.detectPlayerUnavailable = function() {
if (document.querySelector('[player-unavailable]')) {
ytwp.event.removeBodyClass()
}
}
ytwp.init = function() {
ytwp.log('init');
if (!ytwp.initialized) {
ytwp.isWatchPage = ytwp.isWatchUrl();
if (ytwp.isWatchPage) {
ytwp.removeSearchAutofocus();
if (!document.getElementById(scriptStyleId)) {
ytwp.event.initStyle();
}
ytwp.initScroller();
ytwp.initialized = true;
ytwp.pageReady = false;
}
}
ytwp.event.onWatchInit();
if (ytwp.isWatchPage) {
ytwp.html5PlayerFix();
}
}
ytwp.initScroller = function() {
// Register listener & Call it now.
uw.addEventListener('scroll', ytwp.onScroll, false);
uw.addEventListener('resize', ytwp.onScroll, false);
ytwp.onScroll();
}
ytwp.onScroll = function() {
var viewportHeight = document.documentElement.clientHeight;
// topOfPageClassId
if (ytwp.isWatchPage && uw.scrollY == 0) {
document.body.classList.add(topOfPageClassId);
//var player = document.getElementById('movie_player');
//if (player)
// player.focus();
} else {
document.body.classList.remove(topOfPageClassId);
}
// viewingVideoClassId
if (ytwp.isWatchPage && uw.scrollY <= viewportHeight) {
document.body.classList.add(viewingVideoClassId);
} else {
document.body.classList.remove(viewingVideoClassId);
}
}
ytwp.event = {
initStyle: function() {
ytwp.log('initStyle');
ytwp.style = new JSStyleSheet(scriptStyleId);
ytwp.event.buildStylesheet();
// Duplicate stylesheet targeting data-spf-name if enabled.
if (uw.spf) {
var temp = scriptBodySelector;
scriptBodySelector = 'body[data-spf-name="watch"]';
scriptSelector = scriptHtmlSelector + ' ' + scriptBodySelector
ytwp.event.buildStylesheet();
ytwp.style.appendRule('body[data-spf-name="watch"]:not(.ytwp-window-player) #masthead-positioner', {
'position': 'absolute',
'top': playerHeight + ' !important'
});
}
ytwp.style.injectIntoHeader();
},
buildStylesheet: function() {
ytwp.log('buildStylesheet');
//--- Browser Scrollbar
// Chrome/Webkit
ytwp.style.appendRule(scriptBodySelector + '::-webkit-scrollbar', {
'width': '0 !important',
'height': '0 !important',
});
// Firefox/Gecko
// Requires about:config flag to be toggled as of FireFox v63
// https://github.com/Zren/ResizeYoutubePlayerToWindowSize/issues/42
ytwp.style.appendRule('html', {
'scrollbar-width': 'none',
});
//--- Video Player
var d;
d = buildVenderPropertyDict(transitionProperties, 'left 0s linear, padding-left 0s linear');
d['padding'] = '0 !important';
d['margin'] = '0 !important';
ytwp.style.appendRule([
scriptBodySelector + ' #player',
scriptBodySelector + '.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible #player',
scriptBodySelector + '.ltr.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible.guide-collapsed #player',
scriptBodySelector + '.ltr.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible.guide-collapsed #player-legacy',
scriptBodySelector + '.ltr.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible.guide-collapsed #watch7-main-container',
], d);
//
d = buildVenderPropertyDict(transitionProperties, 'width 0s linear, left 0s linear');
// Bugfix for Firefox
// Parts of the header (search box) are hidden under the player.
// Firefox doesn't seem to be using the fixed header+guide yet.
d['float'] = 'initial';
// Skinny mode
d['left'] = 0;
d['margin-left'] = 0;
ytwp.style.appendRule(scriptBodySelector + ' #player-api', d);
// Theater mode
ytwp.style.appendRule(scriptBodySelector + ' .watch-stage-mode #player .player-api', {
'left': 'initial !important',
'margin-left': 'initial !important',
});
// Hide the cinema/wide mode button since it's useless.
//ytwp.style.appendRule(scriptBodySelector + ' #movie_player .ytp-size-button', 'display', 'none');
// !important is mainly for simplicity, but is needed to override the !important styling when the Guide is open due to:
// .sidebar-collapsed #watch7-video, .sidebar-collapsed #watch7-main, .sidebar-collapsed .watch7-playlist { width: 945px!important; }
// Also, Youtube Center resizes #player at element level.
// Don't resize if Youtube+'s html.floater is detected.
// Dont' resize if Youtube+ (Iridium/Material)'s html.iri-always-visible is detected.
ytwp.style.appendRule(
[
scriptSelector + ' #player',
scriptSelector + ' #player-wrap',
scriptSelector + ' #player-api',
scriptHtmlSelector + ':not(.floater):not(.iri-always-visible) ' + scriptBodySelector + ' #movie_player',
scriptSelector + ' #player-mole-container',
scriptHtmlSelector + ':not(.floater):not(.iri-always-visible) ' + scriptBodySelector + ' .html5-video-container',
scriptHtmlSelector + ':not(.floater):not(.iri-always-visible) ' + scriptBodySelector + ' .html5-main-video',
scriptSelector + ' ytd-watch-flexy[theater] #player-theater-container.ytd-watch-flexy',
scriptSelector + ' ytd-watch-flexy[flexy] #player-container-outer.ytd-watch-flexy',
scriptSelector + ' ytd-watch-flexy[flexy] #player-container-inner.ytd-watch-flexy',
scriptSelector + ' ytd-watch-flexy[flexy] #player-container.ytd-watch-flexy',
scriptSelector + ' ytd-watch-grid[theater] #player-theater-container.ytd-watch-grid',
scriptSelector + ' ytd-watch-grid[flexy] #player-container-outer.ytd-watch-grid',
scriptSelector + ' ytd-watch-grid[flexy] #player-container-inner.ytd-watch-grid',
scriptSelector + ' ytd-watch-grid[flexy] #player-container.ytd-watch-grid',
],
{
'width': '100% !important',
'min-width': '100% !important',
'max-width': '100% !important',
'height': playerHeight + ' !important',
'min-height': playerHeight + ' !important',
'max-height': playerHeight + ' !important',
}
);
ytwp.style.appendRule(
[
scriptSelector + ' #player',
scriptSelector + ' .html5-main-video',
],
{
'top': '0 !important',
'right': '0 !important',
'bottom': '0 !important',
'left': '0 !important',
}
);
// Resize #player-unavailable, #player-api
// Using min/max width/height will keep
ytwp.style.appendRule(scriptSelector + ' #player .player-width', 'width', '100% !important');
ytwp.style.appendRule(scriptSelector + ' #player .player-height', 'height', '100% !important');
// Fix video overlays
ytwp.style.appendRule([
scriptSelector + ' .html5-video-player .ad-container-single-media-element-annotations', // Ad
scriptSelector + ' .html5-video-player .ytp-upnext', // Autoplay Next Video
], 'top', '0');
// Fix video cropping (object-fit: cover) (Issue #70)
ytwp.style.appendRule(scriptSelector + ' .ytp-fit-cover-video .html5-main-video', 'object-fit', 'contain !important');
// Thumbnail cropping
ytwp.style.appendRule(scriptSelector + ' .ytp-cued-thumbnail-overlay-image', {
'background-size': 'contain !important',
'-moz-background-size': 'contain !important',
'-webkit-background-size': 'contain !important',
});
//--- Video Container Background
ytwp.style.appendRule(scriptSelector + ' #movie_player', 'background-color', '#000000');
//--- Move Video Player
ytwp.style.appendRule(scriptSelector + ' #player', {
'position': 'absolute',
// Already top:0; left: 0;
});
ytwp.style.appendRule(scriptSelector, { // body
'margin-top': playerHeight,
});
// Fix the top right avatar button
ytwp.style.appendRule(scriptSelector + ' button.ytp-button.ytp-cards-button', 'top', '0');
//--- Sidebar
// Remove the transition delay as you can see it moving on page load.
d = buildVenderPropertyDict(transitionProperties, 'margin-top 0s linear, padding-top 0s linear');
d['margin-top'] = '0 !important';
d['top'] = '0 !important';
ytwp.style.appendRule(scriptSelector + ' #watch7-sidebar', d);
ytwp.style.appendRule(scriptSelector + '.cardified-page #watch7-sidebar-contents', 'padding-top', '0');
//--- Absolutely position the fixed header.
// Masthead
ytwp.style.appendRule('#skip-navigation.ytd-masthead', 'top', '-150vh'); // Normally -1000px can be shorter than screen (Issue #77)
d = buildVenderPropertyDict(transitionProperties, 'top 0s linear !important');
ytwp.style.appendRule(scriptSelector + '.hide-header-transition #masthead-positioner', d);
ytwp.style.appendRule(scriptSelector + '.' + viewingVideoClassId + ' #masthead-positioner', {
'position': 'absolute',
'top': playerHeight + ' !important'
});
// Lower masthead below Youtube+'s html.floater
ytwp.style.appendRule('html.floater ' + scriptBodySelector + '.' + viewingVideoClassId + ' #masthead-positioner', {
'z-index': '5',
});
// Autocomplete popup
ytwp.style.appendRule(scriptSelector + ' .sbdd_a', {
'top': '56px',
});
ytwp.style.appendRule(scriptSelector + '.' + viewingVideoClassId + ' .sbdd_a', {
'top': 'calc(' + playerHeight + ' + 56px) !important',
'position': 'absolute !important',
});
// Guide
// When watching the video, we need to line it up with the masthead.
ytwp.style.appendRule(scriptSelector + '.' + viewingVideoClassId + ' #appbar-guide-menu', {
'display': 'initial',
'position': 'absolute',
'top': '100% !important' // Masthead height
});
ytwp.style.appendRule(scriptSelector + '.' + viewingVideoClassId + ' #page.watch #guide', {
'display': 'initial',
'margin': '0',
'position': 'initial'
});
// When the guide is open, it adds body{top:-1000px} which messes with the top position (Issue #77)
ytwp.style.appendRule(scriptSelector + '.lock-scrollbar', {
'top': '0 !important',
'position': 'static !important',
});
//---
// MiniPlayer-Bar
ytwp.style.appendRule(scriptSelector + ' #miniplayer-bar #player', {
'position': 'static',
});
ytwp.style.appendRule(
[
scriptSelector + ' #miniplayer-bar #player',
scriptSelector + ' #miniplayer-bar #player-api',
scriptHtmlSelector + ':not(.floater):not(.iri-always-visible) ' + scriptBodySelector + ' #miniplayer-bar #movie_player',
scriptSelector + ' #player-mole-container',
scriptHtmlSelector + ':not(.floater):not(.iri-always-visible) ' + scriptBodySelector + ' #miniplayer-bar .html5-video-container',
scriptHtmlSelector + ':not(.floater):not(.iri-always-visible) ' + scriptBodySelector + ' #miniplayer-bar .html5-main-video',
],
{
'width': '252px !important',
'min-width': '252px !important',
'max-width': '252px !important',
'height': '142px !important',
'min-height': '142px !important',
'max-height': '142px !important',
}
);
// Override inline style (caused by a JS animation) that breaks the miniplayer video
// https://github.com/Zren/ResizeYoutubePlayerToWindowSize/issues/41#issuecomment-439710130
ytwp.style.appendRule('.video-stream.html5-main-video', {
'top': '0 !important',
});
//---
// Hide Scrollbars
ytwp.style.appendRule(scriptSelector + '.' + topOfPageClassId, 'overflow-x', 'hidden');
//--- Fix Other Possible Style Issues
ytwp.style.appendRule(scriptSelector + ' #placeholder-player', 'display', 'none');
ytwp.style.appendRule(scriptSelector + ' #watch-sidebar-spacer', 'display', 'none');
ytwp.style.appendRule(scriptSelector + ' .skip-nav', 'display', 'none');
//--- Whitespace Leftover From Moving The Video
ytwp.style.appendRule(scriptSelector + ' #page.watch', 'padding-top', '0');
ytwp.style.appendRule(scriptSelector + ' .player-branded-banner', 'height', '0');
//--- Youtube+ Compatiblity
ytwp.style.appendRule(scriptSelector + ' #body-container', 'position', 'static');
ytwp.style.appendRule(scriptHtmlSelector + '.part_static_size:not(.content-snap-width-skinny-mode) ' + scriptBodySelector + ' .watch-non-stage-mode #player-playlist', 'width', '1066px');
//--- Playlist Bar
ytwp.style.appendRule([
scriptSelector + ' #placeholder-playlist',
scriptSelector + ' #player .player-height#watch-appbar-playlist',
], {
'height': '540px !important',
'max-height': '540px !important',
});
d = buildVenderPropertyDict(transitionProperties, 'transform 0s linear');
ytwp.style.appendRule(scriptSelector + ' #watch-appbar-playlist', d);
d = buildVenderPropertyDict(transformProperties, 'translateY(0px)');
d['margin-left'] = '0';
d['top'] = 'calc(' + playerHeight + ' + 60px)';
ytwp.style.appendRule(scriptSelector + ' #player .player-height#watch-appbar-playlist', d);
ytwp.style.appendRule(scriptSelector + ' .playlist-videos-list', {
'max-height': '470px !important',
'height': 'initial !important',
});
// Old layout `&disable_polymer=true`
ytwp.style.appendRule(scriptSelector + ' #player .player-height#watch-appbar-playlist', {
'left': 'calc((100vw - 1066px)/2 + 640px + 10px)',
'width': '416px',
});
ytwp.style.stylesheet += '@media screen and (min-height: 630px) and (min-width: 1294px) {\n';
ytwp.style.appendRule(scriptSelector + ' #player .player-height#watch-appbar-playlist', {
'left': 'calc((100vw - 1280px)/2 + 854px + 10px)',
});
ytwp.style.stylesheet += '}\n @media screen and (min-width: 1720px) and (min-height:980px) {\n';
ytwp.style.appendRule(scriptSelector + ' #player .player-height#watch-appbar-playlist', {
'left': 'calc((100vw - 1706px)/2 + 1280px + 10px)',
});
ytwp.style.stylesheet += '}\n';
//---
// Material UI
ytwp.style.appendRule(scriptSelector + '.ytwp-scrolltop #extra-buttons', 'display', 'none !important');
// ytwp.style.appendRule('body > #player:not(.ytd-watch)', 'display', 'none');
// ytwp.style.appendRule('body.ytwp-viewing-video #content:not(app-header-layout) ytd-page-manager', 'margin-top', '0 !important');
// ytwp.style.appendRule('.ytd-watch-0 #content-separator.ytd-watch', 'margin-top', '0');
ytwp.style.appendRule('ytd-app', 'position', 'static !important');
ytwp.style.appendRule('ytd-watch #top', 'margin-top', '71px !important'); // 56px (topnav height) + 15px (margin)
ytwp.style.appendRule('ytd-watch #container', 'margin-top', '0 !important');
ytwp.style.appendRule('ytd-watch #content-separator', 'margin-top', '0 !important');
// Note: Container is now relative since 2023 June (Issue #77)
// Note: Container is now a full-bleed-player (Issue #79)
ytwp.style.appendRule([
scriptSelector + ' ytd-watch-flexy[theater] #player-wide-container.ytd-watch-flexy',
scriptSelector + ' ytd-watch-flexy[fullscreen] #player-wide-container.ytd-watch-flexy',
scriptSelector + ' ytd-watch-flexy[full-bleed-player] #player-full-bleed-container.ytd-watch-flexy', // Issue #79 (2023-08-17)
scriptSelector + ' ytd-watch-flexy[full-bleed-player] #full-bleed-container.ytd-watch-flexy', // Issue #79 (2023-08-22)
scriptSelector + ' ytd-watch-grid[theater] #player-wide-container.ytd-watch-grid',
scriptSelector + ' ytd-watch-grid[fullscreen] #player-wide-container.ytd-watch-grid',
scriptSelector + ' ytd-watch-grid[full-bleed-player] #player-full-bleed-container.ytd-watch-grid', // Issue #81 (2023-08-30)
scriptSelector + ' ytd-watch-grid[full-bleed-player] #full-bleed-container.ytd-watch-grid', // Issue #81 (2023-08-30)
], {
'position': 'static',
'height': 0,
'min-height': 0,
});
ytwp.style.appendRule(scriptSelector + '.ytwp-viewing-video ytd-app #masthead-container.ytd-app', {
'position': 'absolute',
'top': playerHeight,
'z-index': 0,
});
ytwp.style.appendRule(scriptSelector + '.ytwp-viewing-video ytd-watch #masthead-positioner', {
'top': playerHeight + ' !important',
});
ytwp.style.appendRule(scriptSelector + ' .ytp-cued-thumbnail-overlay', 'z-index', '10');
//---
// Flexy UI
ytwp.style.appendRule([
scriptSelector + ' ytd-watch-flexy[theater] #player-theater-container.ytd-watch-flexy',
scriptSelector + ' ytd-watch-grid[theater] #player-theater-container.ytd-watch-grid',
], {
'position': 'absolute',
'top': '0',
});
// Youtube seems to be ignoring the margin/padding top in certain elements for some reason (Issue #88)
// ytwp.style.appendRule([
// scriptSelector + ' ytd-watch-flexy',
// scriptSelector + ' ytd-watch-grid',
// ], 'padding-top', '71px'); // 56px (topnav height) + 15px (margin)
ytwp.style.appendRule('#page-manager.ytd-app', 'padding-top', 'var(--ytd-masthead-height,var(--ytd-toolbar-height))');
ytwp.style.appendRule(scriptSelector + ' #error-screen', 'z-index', '11');
},
onWatchInit: function() {
ytwp.log('onWatchInit');
if (!ytwp.initialized) return;
if (ytwp.pageReady) return;
if (enableOnLoad) {
ytwp.event.addBodyClass();
}
if (ytwp.hasYoutubeChanged()) {
ytwp.debugPage()
}
ytwp.pageReady = true;
},
onDispose: function() {
ytwp.log('onDispose');
ytwp.initialized = false;
ytwp.pageReady = false;
ytwp.isWatchPage = false;
},
addBodyClass: function() {
// Insert CSS Into the body so people can style around the effects of this script.
document.body.classList.add(scriptBodyClassId);
ytwp.log('Applied ' + scriptBodySelector);
},
removeBodyClass: function() {
document.body.classList.remove(scriptBodyClassId);
ytwp.log('Removed ' + scriptBodySelector);
},
};
ytwp.html5PlayerFix = function() {
ytwp.log('html5PlayerFix');
return;
try {
if (!uw.ytcenter // Youtube Center
&& !uw.html5Patched // Youtube+
&& (!ytwp.html5.app)
&& (uw.ytplayer && uw.ytplayer.config)
&& (uw.yt && uw.yt.player && uw.yt.player.Application && uw.yt.player.Application.create)
) {
ytwp.html5.app = ytwp.html5.getPlayerInstance();
}
ytwp.html5.update();
ytwp.html5.autohideControls();
} catch (e) {
ytwp.error(e);
}
}
ytwp.fixMasthead = function() {
ytwp.log('fixMasthead');
var el = document.querySelector('#masthead-positioner-height-offset');
if (el) {
ytwp.fixMastheadElement(el);
}
}
ytwp.fixMastheadElement = function(el) {
ytwp.log('fixMastheadElement', el);
if (el.style.height) { // != ""
setTimeout(function(){
el.style.height = ""
document.querySelector('#appbar-guide-menu').style.marginTop = "";
}, 0);
}
}
JSStyleSheet.injectIntoHeader(scriptStyleId + '-focusfix', 'input#search[autofocus] { display: none; }');
ytwp.removeSearchAutofocus = function() {
var e = document.querySelector('input#search');
// ytwp.log('removeSearchAutofocus', e)
if (e) {
e.removeAttribute('autofocus')
}
}
ytwp.registerMastheadFix = function() {
ytwp.log('registerMastheadFix');
// Fix the offset when closing the Share widget (element.style.height = ~275px).
observe('#masthead-positioner-height-offset', {
attributes: true,
}, function(mutation) {
console.log(mutation.type, mutation)
if (mutation.attributeName === 'style') {
var el = mutation.target;
if (el.style.height) { // != ""
setTimeout(function(){
el.style.height = ""
document.querySelector('#appbar-guide-menu').style.marginTop = "";
}, 0);
}
}
});
}
//--- Material UI
ytwp.materialPageTransition = function() {
ytwp.log('materialPageTransition')
ytwp.init();
if (ytwp.isWatchUrl()) {
ytwp.removeSearchAutofocus();
if (enableOnLoad) {
ytwp.event.addBodyClass();
}
// if (!ytwp.html5.app) {
if (!ytwp.initialized) {
ytwp.log('materialPageTransition !ytwp.html5.app', ytwp.html5.app)
setTimeout(ytwp.materialPageTransition, 100);
}
// Focus player
// var moviePlayer = document.querySelector('#movie_player')
// if (moviePlayer) {
// moviePlayer.click()
// }
} else {
ytwp.event.onDispose();
document.body.classList.remove(scriptBodyClassId);
}
ytwp.onScroll();
ytwp.fixMasthead();
ytwp.attemptToUpdatePlayer();
};
//--- Listeners
ytwp.registerListeners = function() {
ytwp.registerMaterialListeners();
ytwp.registerMastheadFix();
};
ytwp.registerMaterialListeners = function() {
// For Material UI
// HistoryEvent.listeners.push(ytwp.materialPageTransition);
// HistoryEvent.startTimer();
// HistoryEvent.inject();
// HistoryEvent.listeners.push(console.log.bind(console));
document.addEventListener('yt-page-data-fetched', ytwp.materialPageTransition)
document.addEventListener('yt-navigate-finish', ytwp.materialPageTransition)
// Debugging
// document.addEventListener('yt-navigate-start', function(e){ ytwp.log('document.yt-navigate-start', e)})
document.addEventListener('yt-page-data-fetched', function(e){ ytwp.log('document.yt-page-data-fetched', e)})
document.addEventListener('yt-navigate-finish', function(e){ ytwp.log('document.yt-navigate-finish', e)})
// document.addEventListener('yt-navigate-error', function(e){ ytwp.log('document.yt-navigate-error', e)})
// document.addEventListener('yt-navigate-cache', function(e){ ytwp.log('document.yt-navigate-cache', e)})
// document.addEventListener('yt-navigate-redirect', function(e){ ytwp.log('document.yt-navigate-redirect', e)})
// document.addEventListener('yt-navigate-action', function(e){ ytwp.log('document.yt-navigate-action', e)})
// document.addEventListener('yt-navigate-home-action', function(e){ ytwp.log('document.yt-navigate-home-action', e)})
};
ytwp.main = function() {
ytwp.registerListeners();
ytwp.init();
ytwp.fixMasthead();
};
ytwp.main();
// ytwp.updatePlayerTimerId = 0;
ytwp.updatePlayerAttempts = -1;
ytwp.updatePlayerMaxAttempts = 150; // 60fps = 2.5sec
ytwp.attemptToUpdatePlayer = function() {
// console.log('ytwp.attemptToUpdatePlayer')
if (0 <= ytwp.updatePlayerAttempts && ytwp.updatePlayerAttempts < ytwp.updatePlayerMaxAttempts) {
ytwp.updatePlayerAttempts = 0;
} else {
ytwp.updatePlayerAttempts = 0;
ytwp.attemptToUpdatePlayerTick();
}
// setTimeout(ytwp.updatePlayer, 10000); /// Just in case it's not caught
}
ytwp.attemptToUpdatePlayerTick = function() {
// console.log('ytwp.attemptToUpdatePlayerTick', ytwp.updatePlayerAttempts)
if (ytwp.updatePlayerAttempts < ytwp.updatePlayerMaxAttempts) {
ytwp.updatePlayerAttempts += 1;
ytwp.updatePlayer();
// ytwp.updatePlayerTimerId = setTimeout(ytwp.attemptToUpdatePlayerTick, 200);
requestAnimationFrame(ytwp.attemptToUpdatePlayerTick);
}
}
ytwp.updatePlayer = function() {
ytwp.removeSearchAutofocus();
ytwp.enterTheaterMode();
ytwp.detectPlayerUnavailable();
}
ytwp.toggleExtension = function() {
document.body.classList.toggle('ytwp-window-player')
ytwp.setTheaterMode(document.body.classList.contains('ytwp-window-player'))
}
//--- Main
ytwp.materialPageTransition()
setInterval(ytwp.updatePlayer, 2500);
//--- Keyboard Shortcut
function childOf(child, ancestor) {
var parent = child.parentNode
while (parent) {
if (parent == ancestor) {
return true
}
parent = parent.parentNode
}
return false
}
function cancelIfToggleKey(validKeyCallback, e) {
var isKey = e.key === scriptToggleKey
var validTarget = (
e.target === document.body
|| e.target.id === 'player-api'
|| e.target.id === 'movie_player'
|| childOf(e.target, document.querySelector('#movie_player'))
)
if (validTarget && isKey) {
e.preventDefault()
e.stopPropagation()
console.log('cancelIfToggleKey.validKeyCallback', validKeyCallback, 'e', e)
if (validKeyCallback) {
validKeyCallback()
}
}
}
window.addEventListener('keydown', cancelIfToggleKey.bind(null, ytwp.toggleExtension), true)
window.addEventListener('keyup', cancelIfToggleKey.bind(null, null), true)
// Note: keypress is deprecated
// https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event
window.addEventListener('keypress', cancelIfToggleKey.bind(null, null), true)
//--- Browser Extension
if (typeof browser !== "undefined") {
browser.runtime.onMessage.addListener(request => {
if (request.id == "toggle") {
ytwp.toggleExtension()
return Promise.resolve({
enabled: document.body.classList.contains('ytwp-window-player'),
})
} else {
return Promise.reject(new Error('Unreconized message.id'))
}
});
}
})(window);
================================================
FILE: README.md
================================================
# Resize Youtube Player To Window Size
Moves the video to the top of the website and resizes it to the screen size. A side effect is that the resolution will auto-select 480p/720p/1080p if it fits in the window due to the video player's default behaviour.
## UserJS Hosts
* **GreasyFork:** https://greasyfork.org/scripts/811-resize-yt-to-window-size
* **OpenUserJS.org:** https://openuserjs.org/scripts/zren/Resize_YT_To_Window_Size
* ~~**Userscripts.org:** http://userscripts-mirror.org/scripts/show/153699~~
## License
GPL
================================================
FILE: ResizeRedditToWindowSize.user.js
================================================
// ==UserScript==
// @name Resize Reddit To Window Size
// @description Resize the video player for various sites to the window size.
// @author Chris H (Zren / Shade)
// @namespace https://www.github.com/Zren
// @icon https://reddit.com/favicon.ico
// @version 50
// @include https://*.reddit.com/*
// @grant GM_addStyle
// ==/UserScript==
(function() {
var movedTopPlayer = function(videoBoxElement) {
document.body.insertBefore(videoBoxElement, document.body.firstChild);
videoBoxElement.style.width = '100%'
videoBoxElement.style.height = '100vh'
videoBoxElement.style.backgroundColor = '#000'
}
var urlMatch = function(regexStr) {
regexStr = regexStr.replace(/\//g, '\\/'); // Auto escape forward slashes to make url regexes more legible.
var regex = new RegExp(regexStr);
return regex.exec(window.location.href);
}
var addViewportHeight = function(selector) {
var el = document.querySelector(selector)
if (!el) { return }
var style = getComputedStyle(el)
if (style.position == "absolute") {
var top = style.top || "0"
el.style.top = "calc(100vh + " + top + ")"
}
}
if (document.location.host.endsWith('reddit.com')) {
var commentsRegex = /^https:\/\/www\.reddit\.com\/(r|user)\/[^\/]+\/comments\//
if (!window.location.href.match(commentsRegex)) { return }
var videoBoxElement = document.querySelector('.reddit-video-player-root')
if (!videoBoxElement) { return }
movedTopPlayer(videoBoxElement)
var css = '.reddit-video-player-root { width: 100vw !important; height: 100vh !important; position: relative !important; display: block !important; float: none; z-index: 1000000; }'
css += '.reddit-video-player-root .pinned-controls { display: none; }'
css += '.pinnable-content.pinned { background-color: transparent !important; box-shadow: none !important; }'
css += '.pinnable-content.pinned .dismiss-pinnable { display: none; }'
css += '.pinnable-content .expando { display: none; }'
css += '.pinnable-content .expando-button { visibility: hidden; }'
css += '.pinnable-content.pinned { position: static !important; }'
css += '.pinnable-content.pinned .top-matter { position: static !important; }'
css += '.pinnable-content.pinned .midcol { position: static !important; }'
css += 'html, body { padding-left: 0 !important; padding-right: 0 !important }'
GM_addStyle(css)
setTimeout(function(){
addViewportHeight('.side #search')
addViewportHeight('.side .submit-link')
addViewportHeight('.side .submit-text')
addViewportHeight('.linkinfo')
}, 2000)
}
GM_addStyle('html::-webkit-scrollbar { width: 0; height: 0; } body::-webkit-scrollbar { width: 0; height: 0; }')
GM_addStyle('html { scrollbar-width: none; } body { scrollbar-width: none; }')
})();
================================================
FILE: ResizeVideoDescription.md
================================================
Resizes the following sites
* https://www.crunchyroll.com/
* https://docs.google.com/file/
* https://drive.google.com/drive/
* https://vimeo.com/ (Will also autoplay video)
* http://www.onepieceofficial.com/
* https://www.youpak.com/
* http://olympics.cbc.ca/
* ~~http://www.dailymotion.com/ (Will also hide control bar faster)~~
* https://streamable.com/
* https://www.globaltv.com/shows/the-late-show-with-stephen-colbert/
* https://www.much.com/shows/south-park/episode/
* https://www.ctvnews.ca/
* https://watch.cbc.ca/live/
* https://www.ctv.ca/ (Will also unmute, and reload the page to workaround uBlockOrigin bug)
* https://www.funimation.com/
* https://www.crave.ca/
* https://tubitv.com/
* https://tv.bell.ca/
# Suggestions
* Use [Resize YT To Window Size](https://greasyfork.org/en/scripts/811-resize-yt-to-window-size) for YouTube. It has it's own script since YouTube's website is much more complicated and has many edge cases.
* Experimental support for hiding scrollbar in Firefox v63. Go to `about:config` and set `layout.css.scrollbar-width.enabled` to `true`, then restart Firefox.
## Screenshots



================================================
FILE: ResizeVideoToWindowSize.user.js
================================================
// ==UserScript==
// @name Resize Video To Window Size
// @description Resize the video player for various sites to the window size.
// @author Chris H (Zren / Shade)
// @namespace http://xshade.ca
// @version 67
// @include https://www.crunchyroll.com/*
// @include https://beta.crunchyroll.com/*
// @include https://static.crunchyroll.com/vilos-v2/web/vilos/player.html*
// @include https://docs.google.com/file/*
// @include https://drive.google.com/drive/*
// @include https://drive.google.com/file/*
// @include https://vimeo.com/*
// @include http://onepieceofficial.com/videos.aspx*
// @include http://www.onepieceofficial.com/videos.aspx*
// @include https://www.youpak.com/watch*
// @include https://olympics.cbc.ca/video/*
// @include https://olympics.cbc.ca/divaPlayer/*
// @include http://www.dailymotion.com/*
// @include https://www.dailymotion.com/*
// @include https://streamable.com/*
// @include https://www.globaltv.com/shows/*
// @include https://watch.globaltv.com/video/*
// @include https://www.much.com/shows/south-park/episode/*/*/
// @include http://*.ctvnews.ca/*
// @include https://watch.cbc.ca/live/channel/*
// @include https://watch.cbc.ca/live/*
// @include https://www.ctv.ca/shows/*
// @include https://www.ctv.ca/video/*
// @include https://www.ctv.ca/*/Video*
// @include https://www.ctv.ca/Movie/*
// @include https://www.funimation.com/shows/*
// @include https://www.funimation.com/player/*
// @include https://www.crave.ca/*
// @include https://tubitv.com/*
// @include https://tv.bell.ca/*
// @grant GM_addStyle
// ==/UserScript==
(function() {
var fixedOverlayPlayer = function(selector) {
var css = selector + "{";
css += "position: fixed;";
css += "top: 0;";
css += "left: 0;";
css += "right: 0;";
css += "bottom: 0;";
css += "}";
GM_addStyle(css);
};
var absoluteTopPlayer = function(selector, staticSelectors) {
var css = selector + "{";
css += "position: absolute;";
css += "top: 0;";
css += "left: 0;";
css += "width: 100vw;";
css += "height: 100vh;";
css += "padding: 0;";
css += "margin: 0;";
css += "}";
css += "body {";
css += "margin-top: 100vh;";
css += "margin-top: 100vh;";
css += "padding-top: 0;";
css += "}";
if (staticSelectors) {
css += staticSelectors + "{";
css += "position: static";
css += "}";
}
GM_addStyle(css);
};
var movedTopPlayer = function(videoBoxElement) {
document.body.insertBefore(videoBoxElement, document.body.firstChild);
videoBoxElement.style.width = '100%';
videoBoxElement.style.height = '100%';
videoBoxElement.style.backgroundColor = '#000';
};
var waitFor = function(selector, callback) {
var tick = function(){
var e = document.querySelector(selector);
if (e) {
callback(e);
} else {
setTimeout(tick, 100);
}
};
tick();
};
var bindJWPlayerSpacebar = function() {
window.addEventListener('keydown', function(e){
if (e.key == ' ' && e.target == document.body) {
var video = document.querySelector('.jwplayer video')
if (video) {
e.preventDefault();
if (video.paused) {
video.play()
} else {
video.pause()
}
}
}
});
};
var urlMatch = function(regexStr) {
regexStr = regexStr.replace(/\//g, '\\/'); // Auto escape forward slashes to make url regexes more legible.
var regex = new RegExp(regexStr);
return regex.exec(window.location.href);
};
if (document.location.host.endsWith('crunchyroll.com')) {
// console.log('doc loc', document.location)
// console.log('win loc', window.location)
if (document.location.hostname == 'www.crunchyroll.com' || document.location.hostname == 'beta.crunchyroll.com') {
var rvtwsHeaderClass = 'rvtws-header-hidden'
var css = ''
css += '.erc-header.'+rvtwsHeaderClass+' { position: absolute; }'
css += '.erc-header.'+rvtwsHeaderClass+' .header-content { opacity: 0; transition: opacity: 0.1s; }'
css += '.erc-header.'+rvtwsHeaderClass+' .header-content:hover { opacity: 1; }'
css += '.erc-watch-episode-layout .video-player-wrapper { max-height: 100vh; height: 100vh; display: flex; }'
// css += '.erc-watch-episode-layout .video-player { height: 56.25vw; align-self: center; }'
GM_addStyle(css)
function updateHeader() {
var ercHeader = document.querySelector('.erc-header')
var ercWatchEpisode = document.querySelector('.erc-watch-episode')
if (ercHeader) {
if (ercWatchEpisode) {
ercHeader.classList.add(rvtwsHeaderClass)
} else {
ercHeader.classList.remove(rvtwsHeaderClass)
}
}
}
window.addEventListener('popstate', updateHeader)
setInterval(updateHeader, 1000)
updateHeader()
} else if (document.location.hostname == 'static.crunchyroll.com' && document.location.pathname == '/vilos-v2/web/vilos/player.html') {
GM_addStyle('#vilosRoot { height: 100vh !important; }');
GM_addStyle('#vilosControlsContainer > div:first-child { margin-top: 3.75rem; }'); // Make room for header
}
} else if (document.location.href.startsWith('https://docs.google.com/file/')) {
fixedOverlayPlayer('#drive-viewer-video-player-object-0');
var css = 'body:not(:hover) .ytp-chrome-bottom { opacity: 0 !important; }';
css += 'body:not(:hover) .drive-viewer-toolstrip { opacity: 0 !important; }';
GM_addStyle(css);
} else if (document.location.href.startsWith('https://drive.google.com/')) {
fixedOverlayPlayer('.drive-viewer-video-player');
var css = '.drive-viewer-toolstrip { opacity: 0 !important; }';
css += '.drive-viewer-toolstrip:hover { opacity: 1 !important; }';
GM_addStyle(css);
} else if (document.location.href.startsWith('https://vimeo.com/')) {
if (! /\/\d+/.exec(document.location.pathname))
return;
var css = '.js-player_area-wrapper, .player_area-wrapper, .player_area, .player_container, .player, .video-wrapper, .video, .video * { width: 100vw !important; height: 100vh !important; max-height: 100vh !important; }';
css += '.vp-player-layout { left: 0 !important; top: 0 !important; width: 100vw !important; height: 100vh !important; }';
css += '.clip_main > *:not(.player_area-wrapper) { margin-top: 70px; }';
css += '.VimeoBrand_ColorRibbon, .body_ribbon, .topnav_desktop, .topnav_mobile { position: absolute; top: 100vh; width: 100%; }';
css += '.topnav_desktop { top: calc(100vh + 5px); }';
GM_addStyle(css);
// autoplay
function tick() {
var e = document.querySelector('button.play[aria-label="Play"]');
if (e) {
e.click();
} else {
setTimeout(tick, 100);
}
}
setTimeout(tick, 100);
} else if (document.location.host.endsWith('onepieceofficial.com')) {
movedTopPlayer(document.querySelector('#FUNimationVideo'));
} else if (document.location.host.endsWith('youpak.com')) {
movedTopPlayer(document.querySelector('.videoWrapper'))
var css = 'body > .container { padding-top: 60px; }'
css += '.navbar-fixed-top { position: absolute; top: 100vh; }'
css += 'body { padding-top: 0; }'
GM_addStyle(css)
} else if (document.location.host == 'olympics.cbc.ca') {
console.log(document.location.pathname, document.location.pathname.match(/\/video\/([^\/]+)\/([^\/]+)(\/?)/))
if (document.location.pathname.match(/\/video\/([^\/]+)\/([^\/]+)(\/?)/)) {
var css = '.cbc-video--player-wrapper { position: static !important; }'
css += '.cbc-video {'
css += ' position: absolute !important;'
css += ' top: 0 !important;'
css += ' left: 0 !important;'
css += ' padding: 0px !important;'
css += ' margin: 0px !important;'
css += ' width: 100% !important;'
css += ' height: 100vh !important;'
css += '}'
css += 'figure.cbc-video--thumb-wrapper, a[data-js-hook="play-video"] picture img { max-height: 100vh !important; }'
css += '.or-podium .or-box { position: static !important; }'
css += '.or-podium .col-xs-1, .or-podium .col-sm-1, .or-podium .col-md-1, .or-podium .col-lg-1, .or-podium .col-xs-2, .or-podium .col-sm-2, .or-podium .col-md-2, .or-podium .col-lg-2, .or-podium .col-xs-3, .or-podium .col-sm-3, .or-podium .col-md-3, .or-podium .col-lg-3, .or-podium .col-xs-4, .or-podium .col-sm-4, .or-podium .col-md-4, .or-podium .col-lg-4, .or-podium .col-xs-5, .or-podium .col-sm-5, .or-podium .col-md-5, .or-podium .col-lg-5, .or-podium .col-xs-6, .or-podium .col-sm-6, .or-podium .col-md-6, .or-podium .col-lg-6, .or-podium .col-xs-7, .or-podium .col-sm-7, .or-podium .col-md-7, .or-podium .col-lg-7, .or-podium .col-xs-8, .or-podium .col-sm-8, .or-podium .col-md-8, .or-podium .col-lg-8, .or-podium .col-xs-9, .or-podium .col-sm-9, .or-podium .col-md-9, .or-podium .col-lg-9, .or-podium .col-xs-10, .or-podium .col-sm-10, .or-podium .col-md-10, .or-podium .col-lg-10, .or-podium .col-xs-11, .or-podium .col-sm-11, .or-podium .col-md-11, .or-podium .col-lg-11, .or-podium .col-xs-12, .or-podium .col-sm-12, .or-podium .col-md-12, .or-podium .col-lg-12 { position: static; }'
css += 'body:not(.cbc-main-page) { padding-top: 100vh; }'
GM_addStyle(css);
var playVideoButton = document.querySelector('a[data-js-hook="play-video"]')
if (playVideoButton) {
playVideoButton.click()
}
} else if (document.location.pathname.startsWith('/divaPlayer')) {
var css = '#videoContainer:not(:hover) > .caption { opacity: 0; }'
css += '#videoContainer:not(:hover) .controlbar-diva { opacity: 0 !important; }'
css += '#videoContainer:not(:hover) #icon-menu-diva { opacity: 0; }'
css += '#videoContainer:not(:hover) diva-simple-controls { opacity: 0 !important; }'
GM_addStyle(css);
} else {
return; // Keep scrollbars
}
} else if (false && document.location.host.endsWith('www.dailymotion.com')) {
var css = '#player:not(:hover) .dmp_will-transition.dmp_is-transitioned--fadeinslide { opacity: 0; }';
if (document.location.pathname.startsWith('/playlist')) {
css += '#player_container { height: 100vh!important; width: 100vw!important; }';
css += '#playerv5-iframe { width: 100% !important; height: 100% !important; }'; // playlists
css += '.sd_header.sd_header--fixed { top: 100vh; position: absolute; }';
css += '#content { margin-top: 60px; }';
movedTopPlayer(document.querySelector('#player_container'));
absoluteTopPlayer('#player_container');
GM_addStyle(css);
} else if (document.location.pathname.startsWith('/video')) {
//css +='.main-container-player { display: none; }';
//css += '#player { height: 100vh!important; width: 100vw!important; }';
css += '.Player { height: 100vh!important; width: 100vw!important; }';
css += '.Player { top: 0!important; left: 0!important; }';
css += 'header { position: absolute!important; top: 100vh !important; }';
css += 'footer { margin-top: 50px; }';
css += 'div[class^="Video__placeholder___"] { margin-top: -180px; height: 100vh!important; }';
GM_addStyle(css);
document.addEventListener('load',function(){
movedTopPlayer(document.querySelector('.Player'));
});
}
} else if (document.location.host.endsWith('streamable.com')) {
if (document.location.pathname == '/') {
return;
}
var css = '#player-content, #player.container .media-container, #player.container #filler, #player.container .player { max-width: 100% !important; width:100%; }';
css += '#player.container #filler { padding-bottom: 100vh !important; }';
css += '.player { background: #000; }';
css += '#player.container .player { display: flex; }';
css += '.player, #player.container video { max-height: 100vh; object-fit: contain; }';
css += '#player > div[style="height:15px;"] { display: none; }';
css += '#player.container .topbanner { display: none; }';
GM_addStyle(css);
} else if (document.location.host.endsWith('globaltv.com')) {
var css = 'html, body, #root, .App, .Video {'
css += 'min-height: 100%; height: 100%; max-height: 100%;'
css += 'min-width: 100%; width: 100%; max-width: 100%;'
css += '}'
css += 'body { overflow-y: auto; }'
GM_addStyle(css);
waitFor('.jwplayer', function(jwPlayerElement) {
waitFor('.jwplayer video', function(videoElement) {
setTimeout(function() {
videoElement.muted = false;
}, 200)
});
});
bindJWPlayerSpacebar();
} else if (document.location.host.endsWith('much.com')) {
var css = '#TopVideoWidgetSection, #ShowNav, #MainHeader, #MastHeadTakeover { display: none; }';
css += '#ShowTop #PlayerWrapper, #ShowTop .container-fluid, #ShowTop #ShowInfo, #ShowTop {';
css += 'margin: 0 !important; padding: 0 !important;';
css += 'width: 100vw !important; height: 100vh !important; max-width: 100vw !important; max-height: 100vh !important;';
css += '}';
css += '#ShowTop #ShowInfo #EpisodeInfo { margin-top: 0 !important; }';
css += '.jwplayer { max-height: 100vh; }';
css += '#EpisodeInfo .new-episodes { display: none !important; }';
GM_addStyle(css);
} else if (document.location.host.endsWith('ctvnews.ca')) {
if (window.location.pathname == '/latest') {
// Redirect to latest video
document.body.style.opacity = "0"
document.documentElement.style.transition = "background 0.4s"
document.documentElement.style.background = "#000"
var latestVideoLink = document.querySelector('.mainnavigation + .drop_down + script + .drop_down > .drop_down_element_container > div > div > ul > li:first-child > a')
if (latestVideoLink) {
window.location.href = latestVideoLink.href
}
} else if (window.location.pathname == '/video') {
var contentWrapper = document.querySelector('body > .content > .video-header > .content-wrapper')
if (contentWrapper) {
var header = document.querySelector('body > header')
document.body.insertBefore(contentWrapper, header)
var mediaplayerdiv = document.querySelector('#mediaplayerdiv')
contentWrapper.querySelector('.topname').style.display = "none"
contentWrapper.style.width = "100%"
contentWrapper.style.height = "100vh"
contentWrapper.style.maxWidth = "100vw"
contentWrapper.style.maxHeight = "100vh"
contentWrapper.style.background="#000"
function onWindowResize() {
var viewportWidth = document.documentElement.clientWidth
var viewportHeight = document.documentElement.clientHeight
var translate = "translate(" + ((viewportWidth - 960)/2) + "px, " + ((viewportHeight - 540)/2) + "px)"
var scale = "scale(" + Math.min(viewportWidth / 960, viewportHeight / 540) + ")"
mediaplayerdiv.style.transform = translate + " " + scale
}
window.addEventListener('resize', onWindowResize);
onWindowResize();
return; // Keep scrollbars
}
} else {
return; // Keep scrollbars
}
} else if (document.location.host.endsWith('watch.cbc.ca')) {
var css = '#masthead { position: absolute; z-index: 1; width: 100%; opacity: 0; transition: opacity 250ms ease-in-out; }';
css += '#masthead:hover { opacity: 1; }';
css += '.regional-channel .container { max-width: 100%; }';
css += '.player-container.live, .jwplayer.jw-flag-aspect-mode { max-height: 100vh; }';
css += '.jwplayer.jw-stretch-uniform video { object-fit: contain !important; }';
css += '.regional-channel footer.regional-channel-footer, section.content-article.live { padding: 10px 0; }';
css += 'section.content-article.live-premium { display: none; }';
css += '.upgrade-banner, .live-premium, iframe.zEWidget-launcher { display: none; }';
css += '.upgrade-banner + .app-container.with-banner-large { top: 0; }';
css += '.content-article { padding-top: 0; padding-bottom: 0; }';
css += '.content-section.live-detail-layout { max-width: 100%; }';
GM_addStyle(css);
} else if (document.location.host.endsWith('www.ctv.ca')) {
var css = ''
css += 'header.navigation { opacity: 0; position: fixed; }'
css += 'header.navigation:hover { opacity: 1; }'
css += '.main { padding-top: 0 !important; }'
css += '#vidi-player-standalone { margin: 0vw 0vw 0; }'
css += 'div[class*="VidiPlayerstyles__VidiPlayerStandAloneContainer"] { margin: 0vw 0vw 0; }'
css += '.jwplayer.jw-flag-aspect-mode { min-height: 100vh !important; height: 100vh !important; max-height: 100vh !important; }'
css += 'div[class*="BrowserNotificationstyles"] { display: none; }'
css += 'div[class^="ArrowBackstyles__ButtonContainer"] { display: none; }'
css += 'div[class^="globalStyles__MainContainer"] { padding-top: 0 !important; }'
css += 'div[class^="VidiPlayerstyles__VidiPlayerPageContainer"] { margin: 0 !important; }'
GM_addStyle(css);
waitFor('.jwplayer', function(jwPlayerElement) {
waitFor('.jwplayer video', function(videoElement) {
setTimeout(function() {
videoElement.muted = false;
}, 200)
});
});
bindJWPlayerSpacebar();
var reverseEpisodeOrder = [
'/shows/the-daily-show-with-trevor-noah',
]
waitFor('ul[class*="Episodesstyles__EpisodeList"]', function(ul) {
if (reverseEpisodeOrder.indexOf(document.location.pathname) >= 0) {
for (var i = 0; i < ul.children.length; i++) {
ul.insertBefore(ul.children[i], ul.firstChild)
}
}
});
setInterval(function(){
var e = document.querySelector('#__next div:not(.App)')
if (e) {
var h2 = e.querySelector('h2')
if (h2 && h2.textContent == 'An unexpected error has occurred.') {
// CTV doesn't like uBlockOrigin, so reload the page to workaround the AJAX React links breaking.
window.location.reload()
}
}
}, 100);
} else if (document.location.host.endsWith('funimation.com')) {
console.log('funimation.com')
var videoBoxElement = document.querySelector('.video-player-section .video-player-container');
console.log('videoBoxElement', videoBoxElement)
if (videoBoxElement) {
movedTopPlayer(videoBoxElement);
videoBoxElement.classList.remove('col-md-10');
var css = 'html, body { width: 100%; height: 100%; }';
css += '.video-player-container { width: 100vw !important; height: 100vh !important; }';
css += '#funimation-main-site-header { position: absolute; top: 100vh; }';
GM_addStyle(css);
} else {
console.log('location', document.location)
waitFor('#brightcove-player', function(player){
console.log('player', player)
player.removeAttribute('muted')
waitFor('.vjs-mute-control.vjs-vol-0', function(muteButton){
console.log('muteButton', muteButton)
muteButton.click()
})
})
}
} else if (document.location.host.endsWith('crave.ca')) {
if (document.location.pathname.startsWith('/live')) return;
var videoBoxElement = document.querySelector('video-player');
if (!videoBoxElement) return;
var css = 'footer, .back-button-wrapper, #mega-menu { display: none !important; }';
css += '.container-site-margin { margin-left: 0; margin-right: 0; }';
css += '.web-videoplayer { margin: 0; }';
css += 'html .jwplayer.jw-flag-aspect-mode { height: 100vh !important; }';
GM_addStyle(css);
} else if (document.location.host.endsWith('tubitv.com')) {
var css = 'header { transition: transform .3s, opacity .3s !important; }';
css += 'header.hide-header { opacity: 0 !important }';
css += 'header.hide-header:hover { opacity: 1 !important; }';
css += 'header + div > div:first-child > div:first-child > div:nth-child(2) { top: 0 !important; left: 0 !important; width: 100% !important; height: 100vh !important; }';
css += 'header + div > div:first-child > div:first-child > div:nth-child(2) > div:first-child > section { padding-top: 0 !important; height: 100vh !important; }';
css += 'header + div > div:first-child > div:first-child > div:nth-child(2) > div:first-child > section > div > div:nth-child(2) > div:first-child { background-image: linear-gradient(0deg,rgba(0,0,0,0), rgba(0,0,0,0.25) 30%, rgba(0, 0, 0, 1) 90%); }';
css += 'header + div > div:first-child > div:first-child > div:nth-child(2) > div:first-child > section > div > div:nth-child(2) > div:nth-child(2) { background-image: linear-gradient(180deg,rgba(0,0,0,0), rgba(0,0,0,0.25) 30%, rgba(0, 0, 0, 1) 90%); }';
css += '#captionsComponent > span { background: none !important; font-size: 3rem !important;';
css += 'text-shadow: 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000, 0 0 0.5rem #000;';
css += '}';
GM_addStyle(css);
var updateHeader = function() {
var header = document.querySelector('header')
if (header) {
var video = document.querySelector('video')
if (video) {
header.classList.add('hide-header')
} else {
header.classList.remove('hide-header')
}
}
}
updateHeader()
setInterval(updateHeader, 1000)
} else if (document.location.host.endsWith('tv.bell.ca')) {
if (!document.location.pathname.startsWith('/watch/')) return;
//let videoBoxElement = document.querySelector('video[playsinline]');
//if (!videoBoxElement) return;
waitFor('video[playsinline]', function(videoBoxElement){
let css = ''
css += '.bg-greyscale-black.w-capped { position: absolute !important; top: calc((var(--headerHeight) + 100vh) * -1 ) !important; height: 100vh !important; }';
css += '.bg-greyscale-black.w-full { position: absolute !important; top: -100vh !important; height: 100vh !important; }';
css += 'body { padding-top: 100vh !important; }';
css += '[class*="&_.bmpui-ui-subtitle-label]:!bg-greyscale-black-70"].h-full.w-full.justify-center { max-width: 100% !important; }'
css += 'header[class="bg-greyscale-03 virgin:bg-tertiary-medium flex"][aria-label="Global"] { display: none !important; }'
console.log('css', css)
GM_addStyle(css);
})
}
GM_addStyle('html::-webkit-scrollbar { width: 0; height: 0; } body::-webkit-scrollbar { width: 0; height: 0; }');
GM_addStyle('html { scrollbar-width: none; } body { scrollbar-width: none; }');
})();
================================================
FILE: YTDocs.md
================================================
# Youtube Player Documentation
## 2023 Oct 31
https://www.youtube.com/s/desktop/9e7f5697/jsbin/desktop_polymer_enable_wil_icons.vflset/desktop_polymer_enable_wil_icons.js
Note, `yt-navigate-start` does not fire on web browser Back button ([Issue #76](https://github.com/Zren/ResizeYoutubePlayerToWindowSize/issues/76)). `document` events fire before `window` events.
```js
document.addEventListener('yt-navigate-start', function(){ console.log('document.yt-navigate-start', arguments)})
document.addEventListener('yt-navigate-finish', function(){ console.log('document.yt-navigate-finish', arguments)})
document.addEventListener('yt-navigate-error', function(){ console.log('document.yt-navigate-error', arguments)})
document.addEventListener('yt-navigate-redirect', function(){ console.log('document.yt-navigate-redirect', arguments)})
document.addEventListener('yt-navigate-cache', function(){ console.log('document.yt-navigate-cache', arguments)})
document.addEventListener('yt-navigate-action', function(){ console.log('document.yt-navigate-action', arguments)})
document.addEventListener('yt-navigate-home-action', function(){ console.log('document.yt-navigate-home-action', arguments)})
document.addEventListener('yt-page-data-fetched', function(){ console.log('document.yt-page-data-fetched', arguments)})
window.addEventListener('yt-navigate-start', function(){ console.log('window.yt-navigate-start', arguments)})
window.addEventListener('yt-navigate-finish', function(){ console.log('window.yt-navigate-finish', arguments)})
window.addEventListener('yt-navigate-error', function(){ console.log('window.yt-navigate-error', arguments)})
window.addEventListener('yt-navigate-redirect', function(){ console.log('window.yt-navigate-redirect', arguments)})
window.addEventListener('yt-navigate-cache', function(){ console.log('window.yt-navigate-cache', arguments)})
window.addEventListener('yt-navigate-action', function(){ console.log('window.yt-navigate-action', arguments)})
window.addEventListener('yt-navigate-home-action', function(){ console.log('window.yt-navigate-home-action', arguments)})
window.addEventListener('yt-page-data-fetched', function(){ console.log('window.yt-page-data-fetched', arguments)})
```
```js
T8c = function (a, b) {
a.listen(b, 'yt-navigate-start', 'onYtNavigateStart');
a.listen(b, 'yt-navigate-finish', 'onYtNavigateFinish');
a.listen(b, 'yt-navigate-error', 'onYtNavigateError');
a.listen(b, 'yt-page-data-fetched', 'onYtPageDataFetched');
a.listen(b, 'yt-navigate-redirect', 'onYtNavigateRedirect')
};
f = C6.prototype;
f.detached = function () {
var a = rp().resolve(BE);
this.unlisten(a, 'yt-navigate-start', 'onYtNavigateStart');
this.unlisten(a, 'yt-navigate-finish', 'onYtNavigateFinish');
this.unlisten(a, 'yt-navigate-error', 'onYtNavigateError');
this.unlisten(a, 'yt-page-data-fetched', 'onYtPageDataFetched');
this.unlisten(document, 'yt-navigate-cache', 'onYtNavigateCache');
this.unlisten(a, 'yt-navigate-redirect', 'onYtNavigateRedirect');
this.ytActionHandlerBehavior.unregisterActionMap(this.appBehaviorActionMap)
};
```
```js
a.actionMap = {
'yt-command-executor-command': 'handleCommandWithCommandHandler',
'yt-dark-mode-toggled-action': 'onDarkModeToggledAction',
'yt-edu-dismiss-action': 'handleEduDismissAction',
'yt-edu-impression-action': 'handleEduImpressionAction',
'yt-navigate-action': 'onYtNavigateAction',
'yt-navigate-home-action': 'onYtNavigateHomeAction',
'yt-player-fullscreen': 'onPlayerFullscreen',
'yt-register-create-family-dialog': 'onYtRegisterCreateFamilyDialog',
'yt-select-country-command': 'handleSelectCountryCommand',
'yt-select-language-command': 'handleSelectLanguageCommand',
'yt-clear-url-param-command': 'handleClearUrlParamCommand',
'yt-set-cookie-command': 'onSetCookieCommand',
'yt-set-pref-storage-entry-command': 'onSetPrefStorageEntryCommand',
'yt-set-local-storage-command': 'onSetLocalStorageCommand',
'yt-set-push-notifications-enabled-command': 'onSetPushNotificationsEnabledCommand',
'yt-signal-action-copy-debug-data': 'onYtSignalActionCopyDebugData',
'yt-signal-action-enable-chrome-notifications': 'onYtSignalActionEnableChromeNotifications',
'yt-signal-action-toggle-restricted-mode-on': 'onYtSignalActionToggleRestrictedModeOnAction',
'yt-signal-action-toggle-restricted-mode-off': 'onYtSignalActionToggleRestrictedModeOffAction',
'yt-signal-action-confirm-mentions-edu': 'onYtSignalActionConfirmMentionsEdu',
'yt-signal-action-record-mentions-edu-impression': 'onYtSignalActionRecordMentionsEduImpression',
'yt-signal-action-show-keyboard-shortcut-dialog': 'onYtSignalActionShowKeyboardShortcutDialog',
'yt-signal-action-skip-navigation': 'onYtSignalActionSkipNavigation',
'yt-signal-action-request-persistent-storage': 'onYtSignalActionRequestPersistentStorage',
'yt-timed-command': 'onYtTimedCommand',
'yt-window-resized': 'onWindowResized',
'yt-window-scrolled': 'onWindowScrolled',
'yt-persist-subscriptions-display-preferences-command': 'handlePersistSubscriptionsDisplayPreferencesCommand',
'yt-invoke-instrument-manager-action': 'onInvokeInstrumentManagerAction',
'yt-entity-update-command': 'handleEntityUpdateCommand',
'yt-web-native-share-command': 'handleWebNativeShareCommand',
'yt-confirm-dialog-endpoint': 'handleConfirmDialogEndpoint',
'yt-ad-feedback-endpoint': 'handleOpenPopupNavigationEndpoints',
'yt-create-backstage-post-dialog-endpoint': 'handleOpenPopupNavigationEndpoints',
'yt-manage-purchase-endpoint': 'handleOpenPopupNavigationEndpoints',
'yt-modal-endpoint': 'handleOpenPopupNavigationEndpoints',
'yt-unlimited-family-flow-endpoint': 'handleOpenPopupNavigationEndpoints',
'yt-ypc-cancel-survey-endpoint': 'handleOpenPopupNavigationEndpoints',
'yt-register-promo-command': 'handleYtRegisterPromoCommand',
'yt-location-collection-command': 'onYtLocationCollectionCommand',
'yt-get-location-command': 'onYtGetLocationCommand',
'yt-log-flow-logging-event-command': 'logFlowLoggingEventCommand',
'yt-save-command-to-session-storage-action': 'handleSaveCommandToSessionStorage',
'yt-show-dma-consent-flow-command': 'handleShowDmaConsentFlow',
'yt-signal-action-show-dma-consent-flow': 'handleShowDmaConsentFlow',
'yt-signal-action-toggle-dark-theme-on': 'handleSignalActionToggleDarkThemeOn',
'yt-signal-action-toggle-dark-theme-off': 'handleSignalActionToggleDarkThemeOff',
'yt-signal-action-toggle-dark-theme-device': 'handleSignalActionToggleDarkThemeDevice',
'yt-select-active-identity-endpoint': 'handleSelectActiveIdentityEndpointInternal',
'yt-update-permission-role-command': 'handleUpdatePermissionRoleCommand',
'yt-channel-creation-form-endpoint': 'handleYtChannelCreationFormEndpoints',
'yt-google-payment-billing-command': 'handleCommandWithCommandHandler'
}
```
## 2017 May 11
`base.js` defines the classes and exposes them at `window._yt_player`
a watch page will add a script tag that sets `window.ytplayer.config`
then immeditately calls `Application.create()`, but doesn't expose the app instance.
```js
ytplayer.load = function() {
yt.player.Application.create("player-api", ytplayer.config);
ytplayer.config.loaded = true;
};
(function() {
if (!!window.yt && yt.player && yt.player.Application) {
ytplayer.load();
}
}());
```
`Application.create` does store the app instance in a list,
but it's no longer accessible.
Reinitializing the player will work, but may cause a 2nd `#movie_player` element to be created.
`Application.create()` will call
```js
O1 = function(a, b) {
g.M.call(this);
var c = this;
this.ca = Xia(b);
var d = this.ca.args || {};
this.Z = new zO(d);
g.N(this, this.Z);
this.Z.experiments.g("legacy_autoplay_flag") || "detailpage" != this.Z.g || (d.autoplay = "1");
this.Bc = dO("detailpage" == this.Z.g && "blazer" != this.Z.o, d.enablesizebutton);
this.oa = dO(!1, d.player_wide);
this.V = this.Z.Fb && dO(!1, d.external_list);
this.va = (this.qc = this.Z.Fb && dO(!1, d.external_play_video)) && this.Z.experiments.g("player_unified_fullscreen_transitions");
this.P = new g.BL(this);
g.N(this, this.P);
Gc = function(a, b) {
g.kE(b, "WARNING")
}
;
this.Oa = null;
this.K = new g.cD;
this.ba = new g.cD;
this.da = new N1(this.ba);
this.da.pause();
this.g = new PU(this);
g.N(this, this.g);
this.J = new PU(this,1);
g.N(this, this.J);
this.F = new bZ(this);
g.N(this, this.F);
this.O = 1;
this.Va = {};
this.M = this.Z.storeUserVolume ? Cja() : {
volume: 100,
muted: this.Z.mute
};
this.aa = this.Z.Fb ? new YJ(this,1) : new bJ(this,1);
g.N(this, this.aa);
this.D = null;
this.Ra = {};
d = {};
this.xb = (d.internalAbandon = this.RL,
d.internalvideodatachange = this.QL,
d.playbackready = this.SL,
d.playbackstarted = this.TL,
d.statechange = this.UL,
d.signatureexpired = this.YO,
d);
this.A = Lna(this);
g.N(this, this.A);
this.G = new zP(this.Z,"",this.A);
this.o = Mna(this);
d = {};
this.tc = (d.airplayactivechange = this.HL,
d.airplayavailabilitychange = this.IL,
d.beginseeking = this.cM,
d.endseeking = this.QM,
d.internalAbandon = this.iN,
d.internalaudioformatchange = this.WL,
d.internalvideodatachange = this.vr,
d.internalvideoformatchange = this.BP,
d.liveviewshift = this.oN,
d.playbackstalledatstart = this.eP,
d.progresssync = this.RI,
d.seekto = this.SI,
d.onLoadProgress = this.pN,
d.onVideoProgress = this.VI,
d.playbackready = this.lO,
d.statechange = this.cA,
d.connectionissue = this.AM,
d.newelementrequired = this.SN,
d.heartbeatparams = this.OI,
d.videoelementevent = this.TI,
d);
this.C = null;
this.ra = new zZ(5,function(a) {
a != g.WU(c, a.getPlayerType()) && a.dispose()
}
);
g.N(this, this.ra);
this.zb = this.Bb = -1;
this.sb = new g.nt(this.F.Zf,16,this.F);
g.N(this, this.sb);
this.tb = !1;
this.fa = !0;
this.sa = this.Na = this.B = null;
this.Hb = !1;
this.Tb = this.sc = null;
this.ob = this.ga = 0;
this.ka = this.Ja = !1;
this.Fa = this.ha = null;
this.P.T(this.g, "crn_appapi", this.OL);
this.P.T(this.g, "crx_appapi", this.PL);
this.P.T(this.g, "crn_appad", this.mz);
this.P.T(this.g, "crx_appad", this.mz);
this.P.T(this.g, "presentingplayerstatechange", this.QI);
this.P.T(this.g, "resize", this.IO);
this.F.Ia(g.ae(a));
this.Xb = this.Z.experiments.g("html5_enable_embedded_player_visibility_signals") && this.Z.A ? new BZ(this.F.element) : null;
g.N(this, this.Xb);
g.ND = this.Z.ba;
Nna(this);
this.G.o("fs");
Ona(this);
this.Fa = new L1(this.g);
this.A.C = this.Fa;
this.Fa.init();
g.dV(this.J, "init")
}
```
The `g` variable is an alias for `_yt_player`.
We can monkey patch `g.WU` since it's passed the "c = this" variable as it's first argument.
```js
g.WU=function(a,b){return b?1==b?a.o:a.Ra[b]||null:a.C}; // Chrome
g.ZU=function(a,b){return b?1==b?a.o:a.Ra[b]||null:a.C}; // Firefox
```
We then take that instance and patch `app[key1][key2]()`
where the value of `key1` has a property called element that points to `#movie_player`
```js
app[key1].element = #movie_player`
```
The value of `key2` is the function we need to patch.
We use regex detect if it's source looks like the following.
```js
function(){var a=this.app.Z,b=g.pF()==this.element;if(b&&IE())return new g.Vd(window.outerWidth,window.outerHeight);if(b||a.mi){if(window.matchMedia){a="(width: "+window.innerWidth+"px) and (height: "+window.innerHeight+"px)";this.C&&this.C.media==a||(this.C=window.matchMedia(a));var c=this.C&&this.C.matches}if(c)return new g.Vd(window.innerWidth,window.innerHeight)}else if(this.P&&!this.app.oa)for(a=0;a
Changelog
## v139 - April 10, 2024
* Fix page top margin as certain elements seem to ignore the CSS properties completely (Issue #88)
## v138 - January 9, 2024
* Bind toggle to `keydown` instead of `keyup` so that pressing `Ctrl+W` to close a tab does not trigger the YTWP toggle when you then focus on a Youtube tab.
## v137 - November 1, 2023
* Bind to `yt-page-data-fetched` and `yt-navigate-finish` to fix the back button not cleaning up the window view since `yt-navigate-start` does not always fire (Issue #72 and #76)
* Bind `keyup` not `keypress` (which is deprecated). Also cancel event during `keydown`. This fixes the `w` key also changing the caption box style. It should also fix changing the toggle key to `Escape` (Issue #71)
## v136 - August 30, 2023
* Attempt to fix `ytd-watch-grid` papercuts (Issue #81)
## v135 - August 30, 2023
* Attempt to fix `ytd-watch-grid` (Issue #81)
## v134 - August 22, 2023
* Fix video container getting shifted again after YT update caused by new `full-bleed-player` layout. Thanks again @Vamael for the fix. (Issue #79)
## v133 - August 18, 2023
* Fix video container getting shifted after YT update caused by new `full-bleed-player` layout. Thanks @Vamael for the fix. (Issue #79)
## v132 - June 29, 2023
* Fix video container getting shifted after YT update (Issue #77)
* Fix nav moving around when guide is open.
* Added `background-color: black` to `#movie_player` so it looks better in light mode.
## 131 - March 11, 2023
* Fix theater mode toggle. `ytd-watch-flexy` DOM is weird. (Issue #75)
* Listen for `yt-navigate-start` and `yt-navigate-finish` events.
## 130 - April 19, 2022
* Add quick boolean toggle for enableOnLoad (Issue #67 and #69)
* Fix video cropping caused by object-fit:cover (Issue #70)
* Make it easy to change script toggle keybinding as it'll need to change (Issue #71)
## 129 - March 9, 2022
* Fix toggling theater mode as YouTube moved the button into the settings cog menu (Issue #66)
## 128 - December 25, 2021
* Disable script when an unavailable video is detected
* Remove some logging
## 127 - April 5, 2021
* Resize the video faster by styling the `#player-wrap` element.
## 126 - April 5, 2021
* Fix scrollbar not being hidden in Chrome.
## 125 - May 5, 2020
* Bind `w` key to toggle off script on current page.
* Prep toggle code for firefox extension.
## 124 - November 6, 2019
* Fix autogenerated gaming channel "live channels" page like https://www.youtube.com/channel/UCZtmNrG53nmbq-Ww2VJrxEQ/live (Issue #46)
## 123 - June 24, 2019
* Support `/user/channelName/live` url paths like https://www.youtube.com/user/pokemon/live (Issue #29)
## 122 - January 30, 2019
* Fix hidden video bug when fullscreen (Issue #43)
## 121 - November 18, 2018
* Fix miniplayer video getting positioned offscreen.
## 120 - November 13, 2018
* Add experimental support for hiding scrollbar in Firefox v63. Go to `about:config` and set `layout.css.scrollbar-width.enabled` to `true`, then restart Firefox.
## 119 - August 22, 2018
* Fix the current video thumbnail not showing up when autoplay is disabled.
* Fix the black bg showing a white section when the miniplayer is active.
## 118 - May 19, 2018
* Support (one of) the new "flexy" youtube interface.
## 117 - April 21, 2018
* Slightly fix the playlist area positioning in the old youtube layout.
## 116 - April 19, 2018
* Use a 32px icon so that it looks better in various browser extensions.
* Support YouTube's experimental MiniPlayer Bar.
* Fix onScroll event not triggering in firefox.
## 115 - December 8, 2017
* Fix script not loading error when the page has only loaded halfway.
## 114 - December 8, 2017
* Use !important to fix compatibility with Youtube+ on the old Youtube layout.
## 113 - December 5, 2017
* Fix the autocomplete popup when the video is still visible.
## 112 - December 2, 2017
* Fix the positioning of the search box's autocomplete popup (it was previously hidden).
* Attempt to cleanup the player every 2.5sec instead of every 1sec, as well as the first 150 frames on page load.
## 111 - November 10, 2017
* Constantly attempt to enter Theater mode every second if we don't enter it right away.
* Support entering theater mode in the old layout.
## 110 - October 6, 2017
* Focus on video on page load.
* Support Youtube+'s successor script (Iridium)'s "Video always visible" feature.
## 109 - September 19, 2017
* Fix seekbar resizing when the window is less than ___px wide.
* Fix scrolling jitter on load caused by the search box getting focus.
## 108 - September 12, 2017
* Toggle theater mode to fix the progressbar since it works consistently.
## 107 - August 30, 2017
* Fix videos on channel pages when first visiting a video page.
## 106 - July 4, 2017
* Enable script on `/c/ChannelName/live` and `/channel/ChannelId/live` pages.
## 105 - June 28, 2017
* Fix update loop not starting.
## 104 - June 27, 2017
* Don't start another fix loop when one is in progress.
## 103 - June 27, 2017
* Reattempt fix 10 more times on page load (shit solution but it works).
## 102 - June 18, 2017
* Fix regex checks in FF v54.
* Attempt to fix resizing the progressbar after a few vidoes have played.
* Fix detection for video -> video page changes.
* Keep track of the player size instead of querying the element every time it's looked up (which is a lot).
## 101 - May 11, 2017
* Finish the last regex for applying the control bar fix on page load, control bar should now work in firefox.
## 100 - May 11, 2017
* Patch the player with a newer method to retrieve the app instance. Works for Chrome, but firefox needs one more regex update. Will push a final fix for firefox later today.
## 99 - May 10, 2017
* Undo the update for the control bar since it can cause a second instance of the player.
## 98 - May 8, 2017
* Quick update for the control bar monkey patch. We need to reinit the player so it's slightly slower than normal. Unfortunately the list of players isn't exposed anymore.
## 97 - May 8, 2017
* Fix the info card button in the top right. Example of button: https://www.youtube.com/watch?v=XGu-WCyiaEY
* Make it easy to edit the script to set the player to a fixed height.
## 96 - April 25, 2017
* Fix Material UI bug. Don't use pubsub anymore since Material UI keeps fucking around with it's API. Just use a periodic timer.
## 95 - April 16, 2017
* TempFix for detecting page transition for the Material UI. Check the URL every 500ms and see if it's changed. A proper fix will come when I find a better solution.
## 94 - April 15, 2017
* Fix high CPU usage caused by binding listeners over and over due to an error (and my bad code).
## 93 - April 4, 2017
* Don't run on `/shared` pages anymore.
## 92 - March 21, 2017
* Fix content positioning in the Material Design css.
* Fix some error spam caused by the pubsub/pubsub2 subscribe() function getting moved.
## 91 - March 2, 2017
* Update CSS to support new beta of the Material Design layout (tested by adding `&f6=4` to the `PREFS` cookie).
## 90 - February 12, 2017
* Support `/shared` pages.
## 89 - January 24, 2017
* Hide the scrollbar on video pages (webkit browsers).
* No longer promote Stylish to hide scrollbars now that the extension spies on you by default.
## 88 - October 25, 2016
* Add support for the Material Design UI experiment.
## 87 - September 3, 2016
* Rewrite the previous fix since it caused problems.
## 86 - September 3, 2016
* Fix empty space when closing the share widget.
## 85 - July 14, 2016
* Fix seekbar fix regex.
## 84 - July 7, 2016
* Don't run script in youtube.com video iframes, or iframes on youtube.com. Now compatible with "Simple YouTube MP3 Button".
* Fix videos on channel pages when first visiting a video url.
## 83 - Mar 27, 2016
* Force width to 100% on the `#player-api` element to fix compatibility with Youtube+.
## 82 - Mar 1, 2016
* Prevent script from running on channel pages.
## 81 - Feb 20, 2016
* Proper fix for the player ui not resizing before being clicked.
## 80 - Feb 20, 2016
* Tempfix the player ui not resizing before being clicked.
## 79 - Feb 16, 2016
* Tempfix the player ui not resizing before being clicked.
* Stop duplicating the stylesheet every page.
* Target `body[data-spf-name="watch"]` if spf is enabled so the player remains the same size when changing video.
## 78 - Jan 18, 2016
* Fix a few errors.
## 77 - Dec 24, 2015
* Fix the autoplay UI not being shown.
## 76 - Dec 24, 2015
* Cleanup cached varibles when changing pages. Should fix the seekbar width breaking after a few videos.
* Make compatible with Youtube+'s "Player always visible when reading comments" feature.
## 75 - Dec 19, 2015
* Trigger resizing the player controls after patching it's size function.
## 74 - Dec 17, 2015
* Fix the Skip Ad UI getting hidden.
## 73 - Dec 13, 2015
* Reenable the html5 seekbar fix since apparently the problem is unrelated to my script.
## 72 - Dec 12, 2015
* Disable the html5 seekbar fix (for now). My technique appears to break everything (comment loading/autoplay/buttons) on occasion.
* Fix playlist widget overlaying sidebar.
## 71 - Nov 24, 2015
* Fix html5 seekbar.
## 70 - Aug 19, 2015
* Fix playlist overlaying the rest of the sidebar.
* Fix playlist overlaying the video description when using Youtube+.
## 69 - July 26, 2015
* Make script slightly compatible with Youtube+ after clicking another video.
## 68 - June 19, 2015
* Update HTML5 fix for the old player. `Objects.keys(obj.constructor.prototype)` was skipping the property, so used `for (var k in obj){}`.
## 67 - June 17, 2015
* Make script slightly compatible with Youtube+
## 66 - June 14, 2015
* Fix player offset when the window is really small.
## 65 - May 28, 2015
* Update HTML5 fix for old player.
## 64 - May 7, 2015
* Fix removing transition on the masthead. YT Center has another rule with `!important`.
* Fix the playlist widget getting hidden beneath the player.
## 63 - May 6, 2015
* Update HTML5 fix.
* Remove transition on the masthead.
## 62 - May 6, 2015
* Fix the height on new `.html5-video-container` element.
## 61 - Apr 30, 2015
* Update HTML5 fix.
## 60 - Apr 29, 2015
* Prevent offset on `.player-api` when in theater mode.
## 59 - Apr 29, 2015
* Update HTML5 fix regexes.
## 58 - Apr 29, 2015
* Hide the `#placeholder-player` element.
## 57 - Mar 16, 2015
* Update HTML5 fix regexes.
## 56 - Mar 2, 2015
* Update HTML5 fix regexes.
## 55 - Feb 24, 2015
* Update HTML5 fix regexes.
## 54 - Feb 23, 2015
* Fix double audio bug after clicking a video on the homepage/search page.
* No longer reloading the html5 player to get the `playerInstance`. We are instead creating an unused dummy `playerInstance` to get the reference to it's constructor, which has a static list of the list of active `playerInstances`.
* Reattempt to subscribe to `pubsub` events 1 second later if we get an error.
## 53 - Feb 12, 2015
* Fix double audio due to not doing a null check.
* Hide `Skip navigation` text that overlays the video.
## 52 - Jan 28, 2015
* Search with regex for function that need replacing in HTML5 player.
## 1.51 - Jan 27, 2015
* Update HTML5 fix variables and check in case things have changed.
## 1.50 - Jan 24, 2015
* New HTML5 player fix method which should fix any weird video => video navigation bugs.
## 1.49 - Jan 9, 2015
* Update to the new "detailpage" variable for the HTML5 fix.
## 1.48 - Dec 20, 2014
* Update to the new "detailpage" variable for the HTML5 fix.
## 1.47 - Dec 11, 2014
* Fix bug when visiting a non /watch page first before navigation to the watch video page.
* Update to the new "detailpage" variable for the HTML5 fix.
## 1.46 - Nov 15, 2014
* Remote undoing the HTML5 player fix before navigating to a new video as it isn't needed.
## 1.45 - Nov 12, 2014
* Re fix the progress bar scaling issue.
* Undo the HTML5 player fix before navigating to a new video in order to also load the video description / comments.
## 1.44 - Oct 31, 2014
* Fix a second video player getting loaded when running this script along Youtube Center, this reintroduces the progressbar bug for users with YT Center. Please use the [dev build of YT Center](https://github.com/YePpHa/YouTubeCenter/raw/master/dist/YouTubeCenter.user.js) until the author pushes the fix to the main build.
## 1.43 - Oct 30, 2014
* Fix HTML5 progress bar not resizing. Thanks to [YePpHa](https://github.com/YePpHa/) for re-solving this bug in YoutubeCenter [Issue #1083](https://github.com/YePpHa/YouTubeCenter/issues/1083).
* Completely hide the Player controls on the HTML5 player since we're reloading the player anyways.
## 1.42 - Aug 18, 2014
* Fix HTML5 progress bar not resizing. Thanks to [YePpHa](https://github.com/YePpHa/) for solving this bug in YoutubeCenter. [[Screenshot](https://i.imgur.com/FcLISVq.png)]
* Fix the player getting right aligned in some cases. [[Screenshot]](https://greasyfork.org/forum/uploads/FileUpload/95/4d455197513c65d1aa243a0d800133.jpg)
* Prevent the script from running twice on the same page.
## 1.41 - Aug 11, 2014
* Remove poorly done HTML5 fix. The HTML5 progress bar will remain unfixed until a Youtube update provides the ability to resize it.
* Use CSS absolutly positioning to move the player. This should fix playback restarting while moving the player.
## 1.40 - July 23, 2014
* Attempt to fix the html5 player. The seek bar & annotations might not scale properly.
## 1.39 - July 12, 2014
* Remove debugging code that broke the script due to a raise in javascript execution security.
## 1.38 - June 17, 2014
* Style `#watch7-sidebar {top: 0 !important; }` to fix the sidebar overlapping the player.
* Fix the guide from being off position when viewing the video.
1.37 - May 13, 2014
#player-mole-container element. It had a height of 0, which was hiding the player.
.watch-small, .watch-medium or .watch-large from the #player element.
appbar-guide-delay-load event. It should be called on every single page however, unlike the other events.../watch? page before runnning.
player-added event simply because it (should) be after YT Center is up and running.
init-watch and dispose-watch events rather than the ones used before (player-added and navigate).
-legacy.window.location.href for /watch? to run the script. The old way no longer works (checking for #player-api) as it's now pregenerated even on the homepage.#watch7-content so that it fits in seemlessly [Screenshot].
#player-api → #player-api-legacy.
#player element.
#player-api element had a float: left; on it. The UI in general doesn't seem to have had the update Chrome does (no fixed header + guide).
window.yt not yet existing when the script gets run in NinjaKit on Safari. Will possibly cause this bug to resurface when using safari.
window.yt object reference by changing all references to window to unsafeWindow.
player-added event.
window.history.pushState didn't seem to work. On a further look, it also seems like I should have tried wrapping replaceState as well. Instead of wrapping ytspf.config like Youtube Center, I've found yt.pubsub.instance_.subscribe(eventName, callback). The bugs listed in 1.17 are fixed.
navigate event which is triggered before the page loads through AJAX in order to perform a cleanup (delete the video player as it's out of position).player-ready event in order to move the player.
body.ytwp-window-player to html.ytwp-window-player body. Navigating to a new page through ajax will clear all classes attached to the body element.
console.log().
ytwp-viewing-video to the body element when doing so.
padding and margin-top override on #player.
#playlist-main-container to #playlist.!important when settings margin-top on the sidebar due to it being set at element level (only on non-playlist pages).
#watch7-video-container became #player, #watch7-video became #player-api.z-index of the #watch7-creator-bar due to the #guide overlaying it and making the buttons unclickable. This is most likely a side effect of the last patch because the #watch7-creator-bar was a child of #watch7-video-container and therafor was no longer moved with the video (speculation). The creator bar currently looks like so.
#watch7-video instead of the #watch7-video-container element due to Youtube's new update which will move the #watch7-playlist-container element above the #watch7-video-container element. An example of this new bug can be seen here.
body tag so people can style around this effects of this script. Use body.ytwp-window-player with your selector(s).