Resize YT To Window Size

Moves the video to the top of the website and resizes it to the screen size.

当前为 2014-08-11 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Resize YT To Window Size
  3. // @description Moves the video to the top of the website and resizes it to the screen size.
  4. // @author Chris H (Zren / Shade)
  5. // @icon http://youtube.com/favicon.ico
  6. // @homepageURL https://github.com/Zren/ResizeYoutubePlayerToWindowSize/
  7. // @namespace http://xshade.ca
  8. // @version 1.41
  9. // @include http*://*.youtube.com/*
  10. // @include http*://youtube.com/*
  11. // @include http*://*.youtu.be/*
  12. // @include http*://youtu.be/*
  13. // ==/UserScript==
  14.  
  15. // Github: https://github.com/Zren/ResizeYoutubePlayerToWindowSize
  16. // GreasyFork: https://gf.qytechs.cn/scripts/811-resize-yt-to-window-size
  17. // OpenUserJS.org: https://openuserjs.org/scripts/zren/httpxshade.ca/Resize_YT_To_Window_Size
  18. // Userscripts.org: http://userscripts.org:8080/scripts/show/153699
  19.  
  20. (function (window) {
  21. "use strict";
  22.  
  23. //--- Imported Globals
  24. var yt = window.yt;
  25.  
  26. //--- Utils
  27. function isStringType(obj) { return typeof obj === 'string'; }
  28. function isArrayType(obj) { return obj instanceof Array; }
  29. function isObjectType(obj) { return typeof obj === 'object'; }
  30. function isUndefined(obj) { return typeof obj === 'undefined'; }
  31. function buildVenderPropertyDict(propertyNames, value) {
  32. var d = {};
  33. for (var i in propertyNames)
  34. d[propertyNames[i]] = value;
  35. return d;
  36. }
  37.  
  38. //--- jQuery
  39. // Based on jQuery
  40. // https://github.com/jquery/jquery/blob/master/src/manipulation.js
  41. var core_rnotwhite = /\S+/g;
  42. var rclass = /[\t\r\n\f]/g;
  43. var rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g;
  44.  
  45. var jQuery = {
  46. trim: function( text ) {
  47. return (text || "").replace( rtrim, "" );
  48. },
  49. addClass: function( elem, value ) {
  50. var classes, cur, clazz, j,
  51. proceed = typeof value === "string" && value;
  52.  
  53. if ( proceed ) {
  54. // The disjunction here is for better compressibility (see removeClass)
  55. classes = ( value || "" ).match( core_rnotwhite ) || [];
  56.  
  57. cur = elem.nodeType === 1 && ( elem.className ?
  58. ( " " + elem.className + " " ).replace( rclass, " " ) :
  59. " "
  60. );
  61.  
  62. if ( cur ) {
  63. j = 0;
  64. while ( (clazz = classes[j++]) ) {
  65. if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
  66. cur += clazz + " ";
  67. }
  68. }
  69. elem.className = jQuery.trim( cur );
  70. }
  71. }
  72. },
  73. removeClass: function( elem, value ) {
  74. var classes, cur, clazz, j,
  75. proceed = arguments.length === 0 || typeof value === "string" && value;
  76.  
  77. if ( proceed ) {
  78. classes = ( value || "" ).match( core_rnotwhite ) || [];
  79.  
  80. // This expression is here for better compressibility (see addClass)
  81. cur = elem.nodeType === 1 && ( elem.className ?
  82. ( " " + elem.className + " " ).replace( rclass, " " ) :
  83. ""
  84. );
  85.  
  86. if ( cur ) {
  87. j = 0;
  88. while ( (clazz = classes[j++]) ) {
  89. // Remove *all* instances
  90. while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
  91. cur = cur.replace( " " + clazz + " ", " " );
  92. }
  93. }
  94. elem.className = value ? jQuery.trim( cur ) : "";
  95. }
  96. }
  97. }
  98. };
  99.  
  100.  
  101. //--- Stylesheet
  102. var JSStyleSheet = function(id) {
  103. this.id = id;
  104. this.stylesheet = '';
  105. };
  106.  
  107. JSStyleSheet.prototype.buildRule = function(selector, styles) {
  108. var s = "";
  109. for (var key in styles) {
  110. s += "\t" + key + ": " + styles[key] + ";\n";
  111. }
  112. return selector + " {\n" + s + "}\n";
  113. };
  114.  
  115. JSStyleSheet.prototype.appendRule = function(selector, k, v) {
  116. if (isArrayType(selector))
  117. selector = selector.join(',\n');
  118. var newStyle;
  119. if (!isUndefined(k) && !isUndefined(v) && isStringType(k)) { // v can be any type (as we stringify it).
  120. // appendRule('#blarg', 'display', 'none');
  121. var d = {};
  122. d[k] = v;
  123. newStyle = this.buildRule(selector, d);
  124. } else if (!isUndefined(k) && isUndefined(v) && isObjectType(k)) {
  125. // appendRule('#blarg', {'display': 'none'});
  126. newStyle = this.buildRule(selector, k);
  127. } else {
  128. // Invalid Arguments
  129. console.log('Illegal arguments', arguments);
  130. return;
  131. }
  132.  
  133. this.stylesheet += newStyle;
  134. };
  135.  
  136. JSStyleSheet.injectIntoHeader = function(injectedStyleId, stylesheet) {
  137. var styleElement = document.getElementById(injectedStyleId);
  138. if (!styleElement) {
  139. styleElement = document.createElement('style');
  140. styleElement.type = 'text/css';
  141. styleElement.id = injectedStyleId;
  142. document.getElementsByTagName('head')[0].appendChild(styleElement);
  143. }
  144. styleElement.appendChild(document.createTextNode(stylesheet));
  145. };
  146.  
  147. JSStyleSheet.prototype.injectIntoHeader = function(injectedStyleId, stylesheet) {
  148. JSStyleSheet.injectIntoHeader(this.id, this.stylesheet);
  149. };
  150.  
  151. //--- Constants
  152. var scriptShortName = 'ytwp'; // YT Window Player
  153. var scriptStyleId = scriptShortName + '-style'; // ytwp-style
  154. var scriptBodyClassId = scriptShortName + '-window-player'; // .ytwp-window-player
  155. var viewingVideoClassId = scriptShortName + '-viewing-video'; // .ytwp-viewing-video
  156. var topOfPageClassId = scriptShortName + '-scrolltop'; // .ytwp-scrolltop
  157. var scriptBodyClassSelector = 'body.' + scriptBodyClassId; // body.ytwp-window-player
  158.  
  159. var videoContainerId = 'player';
  160. var videoContainerPlacemarkerId = scriptShortName + '-placemarker'; // ytwp-placemarker
  161.  
  162. var transitionProperties = ["transition", "-ms-transition", "-moz-transition", "-webkit-transition", "-o-transition"];
  163.  
  164. //--- YTWP
  165. var ytwp = window.ytwp = {
  166. scriptShortName: scriptShortName, // YT Window Player
  167. log_: function(logger, args) { logger.apply(console, ['[' + this.scriptShortName + '] '].concat(Array.prototype.slice.call(args))); return 1; },
  168. log: function() { return this.log_(console.log, arguments); },
  169. error: function() { return this.log_(console.error, arguments); },
  170.  
  171. initialized: false,
  172. pageReady: false,
  173. watchPage: false,
  174. };
  175.  
  176. ytwp.util = {
  177. isWatchUrl: function (url) {
  178. if (!url)
  179. url = window.location.href;
  180. return url.match(/https?:\/\/(www\.)?youtube.com\/watch\?/);
  181. }
  182. };
  183.  
  184. ytwp.event = {
  185. init: function() {
  186. ytwp.log('init');
  187. if (ytwp.initialized) return;
  188.  
  189. ytwp.isWatchPage = ytwp.util.isWatchUrl();
  190. if (!ytwp.isWatchPage) return;
  191.  
  192. ytwp.event.initStyle();
  193. ytwp.event.initScroller();
  194. ytwp.initialized = true;
  195. ytwp.pageReady = false;
  196. },
  197. initScroller: function() {
  198. // Register listener & Call it now.
  199. unsafeWindow.addEventListener('scroll', ytwp.event.onScroll, false);
  200. unsafeWindow.addEventListener('resize', ytwp.event.onScroll, false);
  201. ytwp.event.onScroll();
  202. },
  203. onScroll: function() {
  204. var viewportHeight = document.documentElement.clientHeight;
  205.  
  206. // topOfPageClassId
  207. if (unsafeWindow.scrollY == 0) {
  208. jQuery.addClass(document.body, topOfPageClassId);
  209. } else {
  210. jQuery.removeClass(document.body, topOfPageClassId);
  211. }
  212.  
  213. // viewingVideoClassId
  214. if (unsafeWindow.scrollY <= viewportHeight) {
  215. jQuery.addClass(document.body, viewingVideoClassId);
  216. } else {
  217. jQuery.removeClass(document.body, viewingVideoClassId);
  218. }
  219. },
  220. initStyle: function() {
  221. ytwp.log('initStyle');
  222. ytwp.style = new JSStyleSheet(scriptStyleId);
  223. ytwp.event.buildStylesheet();
  224. ytwp.style.injectIntoHeader();
  225. },
  226. buildStylesheet: function() {
  227. ytwp.log('buildStylesheet');
  228. //--- Video Player
  229.  
  230. //
  231. var d;
  232. d = buildVenderPropertyDict(transitionProperties, 'left 0s linear, padding-left 0s linear');
  233. d['padding'] = '0 !important';
  234. d['margin'] = '0 !important';
  235. ytwp.style.appendRule([
  236. scriptBodyClassSelector + ' #player',
  237. scriptBodyClassSelector + '.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible #player',
  238. scriptBodyClassSelector + '.ltr.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible.guide-collapsed #player',
  239. scriptBodyClassSelector + '.ltr.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible.guide-collapsed #player-legacy',
  240. scriptBodyClassSelector + '.ltr.ytcenter-site-center.ytcenter-non-resize.ytcenter-guide-visible.guide-collapsed #watch7-main-container',
  241. ], d);
  242. //
  243. d = buildVenderPropertyDict(transitionProperties, 'width 0s linear, left 0s linear');
  244.  
  245. // Bugfix for Firefox
  246. // Parts of the header (search box) are hidden under the player.
  247. // Firefox doesn't seem to be using the fixed header+guide yet.
  248. d['float'] = 'initial';
  249.  
  250. ytwp.style.appendRule(scriptBodyClassSelector + ' #player-api', d);
  251.  
  252. // !important is mainly for simplicity, but is needed to override the !important styling when the Guide is open due to:
  253. // .sidebar-collapsed #watch7-video, .sidebar-collapsed #watch7-main, .sidebar-collapsed .watch7-playlist { width: 945px!important; }
  254. // Also, Youtube Center resizes #player at element level.
  255. ytwp.style.appendRule(
  256. [
  257. scriptBodyClassSelector + ' #player',
  258. scriptBodyClassSelector + ' #movie_player',
  259. scriptBodyClassSelector + ' #player-mole-container',
  260. scriptBodyClassSelector + ' .html5-video-content',
  261. scriptBodyClassSelector + ' .html5-main-video',
  262. ],
  263. {
  264. 'width': '100% !important',
  265. 'min-width': '100% !important',
  266. 'max-width': '100% !important',
  267. 'height': '100% !important',
  268. 'min-height': '100% !important',
  269. 'max-height': '100% !important',
  270. }
  271. );
  272. // Resize #player-unavailable, #player-api
  273. // Using min/max width/height will keep
  274. ytwp.style.appendRule(scriptBodyClassSelector + ' #player .player-width', 'width', '100% !important');
  275. ytwp.style.appendRule(scriptBodyClassSelector + ' #player .player-height', 'height', '100% !important');
  276.  
  277. //--- Move Video Player
  278. ytwp.style.appendRule(scriptBodyClassSelector + ' #player', {
  279. 'position': 'absolute',
  280. 'top': '0',
  281. 'left': '0',
  282. });
  283. ytwp.style.appendRule(scriptBodyClassSelector, { // body
  284. 'margin-top': '100vh',
  285. });
  286.  
  287.  
  288. //--- Sidebar
  289. // Remove the transition delay as you can see it moving on page load.
  290. d = buildVenderPropertyDict(transitionProperties, 'margin-top 0s linear, padding-top 0s linear');
  291. d['margin-top'] = '0 !important';
  292. d['top'] = '0 !important';
  293. ytwp.style.appendRule(scriptBodyClassSelector + ' #watch7-sidebar', d);
  294.  
  295. ytwp.style.appendRule(scriptBodyClassSelector + '.cardified-page #watch7-sidebar-contents', 'padding-top', '0');
  296.  
  297. //--- Absolutely position the fixed header.
  298. // Masthead
  299. ytwp.style.appendRule(scriptBodyClassSelector + '.' + viewingVideoClassId + ' #masthead-positioner', {
  300. 'position': 'absolute',
  301. 'top': '100% !important'
  302. });
  303.  
  304. // Guide
  305. // When watching the video, we need to line it up with the masthead.
  306. ytwp.style.appendRule(scriptBodyClassSelector + '.' + viewingVideoClassId + ' #appbar-guide-menu', {
  307. 'display': 'initial',
  308. 'position': 'absolute',
  309. 'top': '100% !important' // Masthead height
  310. });
  311. ytwp.style.appendRule(scriptBodyClassSelector + '.' + viewingVideoClassId + ' #page.watch #guide', {
  312. 'display': 'initial',
  313. 'margin': '0',
  314. 'position': 'initial'
  315. });
  316.  
  317. //---
  318. // Hide Scrollbars
  319. ytwp.style.appendRule(scriptBodyClassSelector + '.' + topOfPageClassId, 'overflow-x', 'hidden');
  320.  
  321.  
  322. //--- Fix Other Possible Style Issues
  323.  
  324. //--- Whitespace Leftover From Moving The Video
  325. ytwp.style.appendRule(scriptBodyClassSelector + ' #page.watch', 'padding-top', '0');
  326. ytwp.style.appendRule(scriptBodyClassSelector + ' .player-branded-banner', 'height', '0');
  327.  
  328. //--- Playlist Bar
  329. //ytwp.style.appendRule(scriptBodyClassSelector + ' #watch7-playlist-tray-container', "margin", "-15px -10px 20px -10px");
  330. ytwp.style.appendRule(scriptBodyClassSelector + ' .watch7-playlist-bar-left', 'width', '640px !important'); // Same width as .watch-content
  331. ytwp.style.appendRule([
  332. scriptBodyClassSelector + ' .playlist',
  333. scriptBodyClassSelector + ' .playlist .watch7-playlist-bar',
  334. ], 'max-width', '1040px'); // Same width as .watch-content (640px) + .watch-sidebar (300-400px).
  335. ytwp.style.appendRule(scriptBodyClassSelector + ' #watch7-playlist-tray-container', {
  336. "margin-top": "-15px",
  337. "height": "287px !important", // 65 (playlist tile) * 4 + 27 (trim on bottom)
  338. "margin-bottom": "15px"
  339. });
  340. ytwp.style.appendRule([
  341. scriptBodyClassSelector + '.cardified-page #watch7-playlist-tray-container + #watch7-sidebar-contents', // Pre Oct 26
  342. scriptBodyClassSelector + '.cardified-page #watch-appbar-playlist + #watch7-sidebar-contents', // Post Oct 26
  343. ], 'padding-top', '15px');
  344.  
  345. // YT Center
  346. ytwp.style.appendRule(scriptBodyClassSelector + ' #player', 'margin-bottom', '0 !important');
  347. ytwp.style.appendRule(scriptBodyClassSelector + ' #watch7-playlist-tray-container', {
  348. 'left': 'initial !important',
  349. 'width': 'initial !important'
  350. });
  351. ytwp.style.appendRule(scriptBodyClassSelector + ' .watch7-playlist-bar-right', 'width', '363px !important');
  352. },
  353. onWatchInit: function() {
  354. ytwp.log('onWatchInit');
  355. if (!ytwp.initialized) return;
  356. if (ytwp.pageReady) return;
  357.  
  358. ytwp.event.addBodyClass();
  359. ytwp.pageReady = true;
  360. },
  361. onDispose: function() {
  362. ytwp.initialized = false;
  363. ytwp.pageReady = false;
  364. ytwp.isWatchPage = false;
  365. },
  366. addBodyClass: function() {
  367. // Insert CSS Into the body so people can style around the effects of this script.
  368. jQuery.addClass(document.body, scriptBodyClassId);
  369. ytwp.log('Applied ' + scriptBodyClassSelector);
  370. },
  371. };
  372.  
  373.  
  374. ytwp.pubsubListeners = {
  375. 'init': function() { // Not always called
  376. ytwp.event.init();
  377. ytwp.event.onWatchInit();
  378. },
  379. 'init-watch': function() { // Not always called
  380. ytwp.event.init();
  381. ytwp.event.onWatchInit();
  382. },
  383. 'player-added': function() { // Not always called
  384. // Usually called after init-watch, however this is called before init when going from channel -> watch page.
  385. // The init event is when the body element resets all it's classes.
  386. ytwp.event.init();
  387. ytwp.event.onWatchInit();
  388. },
  389. // 'player-resize': function() {},
  390. // 'player-playback-start': function() {},
  391. 'appbar-guide-delay-load': function() {
  392. // Listen to a later event that is always called in case the others are missed.
  393. ytwp.event.init();
  394. ytwp.event.onWatchInit();
  395.  
  396. // Channel -> /watch
  397. if (ytwp.util.isWatchUrl())
  398. ytwp.event.addBodyClass();
  399. },
  400. // 'dispose-watch': function() {},
  401. 'dispose': function() {
  402. ytwp.event.onDispose();
  403. }
  404. };
  405.  
  406. ytwp.initLogging = function() {
  407.  
  408. };
  409.  
  410. ytwp.registerYoutubeListeners = function() {
  411. // ytwp.registerYoutubePlayerApiListeners();
  412. ytwp.registerYoutubePubSubListeners();
  413. };
  414.  
  415. ytwp.registerYoutubePlayerApiListeners = function() {
  416. var onYouTubePlayerReady_old = onYouTubePlayerReady;
  417. onYouTubePlayerReady = function() {
  418. onYouTubePlayerReady_old.apply(this, arguments);
  419. };
  420. };
  421.  
  422. ytwp.registerYoutubePubSubListeners = function() {
  423. // Subscribe
  424. for (var eventName in ytwp.pubsubListeners) {
  425. var eventListener = ytwp.pubsubListeners[eventName];
  426. yt.pubsub.instance_.subscribe(eventName, eventListener);
  427. }
  428. };
  429.  
  430. ytwp.main = function() {
  431. ytwp.initLogging();
  432. try {
  433. ytwp.registerYoutubeListeners();
  434. } catch(e) {
  435. ytwp.error("Could not hook yt.pubsub");
  436. }
  437. };
  438.  
  439. ytwp.main();
  440. })(unsafeWindow);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址