Space-efficient Youtube

AKA: "Wide Youtube", AKA: "Wide video container" - Uses the page space on youtube more efficiently (especially good for high resolutions)

当前为 2020-08-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Space-efficient Youtube
  3. // @namespace 1N07
  4. // @author 1N07
  5. // @icon https://i.imgur.com/VgEiyi3.png
  6. // @description AKA: "Wide Youtube", AKA: "Wide video container" - Uses the page space on youtube more efficiently (especially good for high resolutions)
  7. // @include https://www.youtube.com/*
  8. // @version 2.0
  9. // @grant GM_registerMenuCommand
  10. // @grant GM_unregisterMenuCommand
  11. // @grant GM_getValue
  12. // @grant GM_setValue
  13. // ==/UserScript==
  14.  
  15. (function() {
  16.  
  17. //===== SETTINGS =====//
  18. var FPPHandle;
  19. var FPPCompOn = GM_getValue("FPPCompOn", false);
  20. SetFPPHandle();
  21.  
  22. var ForceCSSHandle;
  23. var ForceCSSOn = GM_getValue("ForceCSSOn", false);
  24. SetForceCSSHandle();
  25.  
  26. var HomeVideoContainerWidthHandle;
  27. var HomeVideoContainerWidth = GM_getValue("HomeVideoContainerWidth", "360px");
  28. SetHomeVideoContainerWidthHandle();
  29.  
  30. var ShowChannelIconNextToVideosOnHomePageHandle;
  31. var ShowChannelIconNextToVideosOnHomePage = GM_getValue("ShowChannelIconNextToVideosOnHomePage", true);
  32. SetShowChannelIconNextToVideosOnHomePageHandle();
  33.  
  34. var SubVideoContainerWidthHandle;
  35. var SubVideoContainerWidth = GM_getValue("SubVideoContainerWidth", "210px");
  36. SetSubVideoContainerWidthHandle();
  37.  
  38. var HQTNHandle;
  39. var HQTN = GM_getValue("HQTN", false);
  40. SetHQTNHandle();
  41.  
  42. var TrendingVideoContainerWidthHandle;
  43. var TrendingVideoContainerWidth = GM_getValue("TrendingVideoContainerWidth", "600px");
  44. SetTrendingVideoContainerWidthHandle();
  45.  
  46. var VideoContainerHorMarginHandle;
  47. var VideoContainerHorMargin = GM_getValue("VideoContainerHorMargin", "4px");
  48. SetVideoContainerHorMarginHandle();
  49.  
  50. var VideoContainerVerMarginHandle;
  51. var VideoContainerVerMargin = GM_getValue("VideoContainerVerMargin", "24px");
  52. SetVideoContainerVerMarginHandle();
  53.  
  54. var AutoExpandChannelVidContainersHandle;
  55. var AutoExpandChannelVidContainers = GM_getValue("AutoExpandChannelVidContainers", true);
  56. SetAutoExpandChannelVidContainersHandle();
  57.  
  58. var LessenVideoTitleTopMarginOnHomePage = true;
  59.  
  60. //===== SETTINGS END =====//
  61.  
  62.  
  63. var screenWidth = screen.width;
  64. if(!!document.getElementById("early-body")) { //if old youtube
  65. document.getElementById("content").setAttribute("style", "width: 99%;");
  66. } else { //new youtube
  67. addGlobalStyle(`
  68. ytd-app #page-manager > ytd-browse:not([page-subtype="playlist"]):not([page-subtype="home"]) ytd-two-column-browse-results-renderer.ytd-browse
  69. {
  70. box-sizing: border-box`+(ForceCSSOn ? `!important`:``)+`;
  71. width: calc(100% - 25px) !important;
  72. margin: 10px`+(ForceCSSOn ? `!important`:``)+`;
  73. max-width: none;
  74. }
  75.  
  76. #items.ytd-grid-renderer > ytd-grid-video-renderer.ytd-grid-renderer,
  77. #items.ytd-grid-renderer > ytd-grid-radio-renderer.ytd-grid-renderer,
  78. #items.ytd-grid-renderer > ytd-grid-channel-renderer.ytd-grid-renderer,
  79. #items.ytd-grid-renderer > ytd-grid-playlist-renderer.ytd-grid-renderer,
  80. #items.ytd-grid-renderer > ytd-grid-movie-playlist-renderer.ytd-grid-renderer,
  81. #items.ytd-grid-renderer > ytd-grid-movie-renderer.ytd-grid-renderer,
  82. #items.ytd-grid-renderer > ytd-grid-show-renderer.ytd-grid-renderer,
  83. #items.ytd-grid-renderer > ytd-game-card-renderer.ytd-grid-renderer,
  84. ytd-grid-video-renderer
  85. {
  86. width: `+SubVideoContainerWidth+`;
  87. margin-left: 0;
  88. margin-top: 0;
  89. margin-right: `+VideoContainerHorMargin+`;
  90. margin-bottom: `+VideoContainerVerMargin+`;
  91. }
  92. ytd-thumbnail.ytd-grid-video-renderer
  93. {
  94. width: `+SubVideoContainerWidth+`;
  95. height: calc(`+SubVideoContainerWidth+` * 0.5625);
  96. }
  97. ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail
  98. {
  99. width: 100%;
  100. height: 100%;
  101. }
  102. img.yt-img-shadow
  103. {
  104. max-width: 100%;
  105. max-height: 100%;
  106. margin-left: 0;
  107. margin-right: 0;
  108. width: 100%;
  109. height: 100%;
  110. }
  111.  
  112. /*channels page rules*/
  113. ytd-app #page-manager > ytd-browse[page-subtype="channels"] ytd-two-column-browse-results-renderer.ytd-browse ytd-item-section-renderer.ytd-section-list-renderer
  114. {
  115. width: calc(100% - 20px);
  116. max-width: none;
  117. }
  118. /*for some reason the arrows sometimes dont show up, so now forcing them to*/
  119. ytd-app #page-manager > ytd-browse[page-subtype="channels"] ytd-two-column-browse-results-renderer.ytd-browse ytd-item-section-renderer.ytd-section-list-renderer ytd-button-renderer.yt-horizontal-list-renderer.arrow
  120. {
  121. opacity: 1;
  122. display: flex;
  123. }
  124.  
  125. /*trending page rules*/
  126. ytd-app #page-manager > ytd-browse:not([page-subtype]) #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer,
  127. ytd-app #page-manager > ytd-browse:not([page-subtype]) #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer > .ytd-video-renderer
  128. {
  129. max-width: `+TrendingVideoContainerWidth+`;
  130. }
  131. ytd-app #page-manager > ytd-browse:not([page-subtype]) ytd-video-renderer.ytd-expanded-shelf-contents-renderer,
  132. ytd-app #page-manager > ytd-browse:not([page-subtype]) ytd-video-renderer.ytd-expanded-shelf-contents-renderer:not(:last-child)
  133. {
  134. padding-right: 3px;
  135. margin-left: 0;
  136. margin-top: 0;
  137. margin-right: `+VideoContainerHorMargin+`;
  138. margin-bottom: `+VideoContainerVerMargin+`;
  139. }
  140. ytd-app #page-manager > ytd-browse:not([page-subtype]) ytd-thumbnail.ytd-video-renderer
  141. {
  142. margin-right: 10px;
  143. }
  144.  
  145. /*Playlist page rules*/
  146. ytd-browse[page-subtype="playlist"] ytd-two-column-browse-results-renderer.ytd-browse
  147. {
  148. max-width: none;
  149. }
  150.  
  151. /*home page rules*/
  152. ytd-rich-item-renderer {
  153. width: `+HomeVideoContainerWidth+`;
  154. margin-left: 0;
  155. margin-top: 0;
  156. margin-right: `+VideoContainerHorMargin+`;
  157. margin-bottom: `+VideoContainerVerMargin+`;
  158. }
  159. `);
  160. console.log("Youtube Wide video container style added to DOM");
  161.  
  162. if(!ShowChannelIconNextToVideosOnHomePage)
  163. {
  164. addGlobalStyle(`
  165. #avatar-link.ytd-rich-grid-video-renderer
  166. {
  167. display: none;
  168. }
  169. `);
  170. }
  171.  
  172. if(HQTN)
  173. {
  174. addGlobalStyle(`
  175. img.yt-img-shadow:not([src*='?'])
  176. {
  177. object-fit: cover;
  178. }
  179. `);
  180. }
  181.  
  182. if(LessenVideoTitleTopMarginOnHomePage)
  183. {
  184. addGlobalStyle(`
  185. h3.ytd-rich-grid-video-renderer
  186. {
  187. margin-top: 6px;
  188. }
  189. `);
  190. }
  191.  
  192. if(FPPCompOn) {
  193. addGlobalStyle(`
  194. /*========== Fade++ Compatibility ==========*/
  195. ytd-app #page-manager > ytd-browse:not([page-subtype="playlist"]) {
  196. display: block;
  197. }
  198. ytd-app[guide-persistent-and-visible] #page-manager > ytd-browse:not([page-subtype="playlist"]) ytd-two-column-browse-results-renderer.ytd-browse
  199. {
  200. margin-left: 250px !important;
  201. }
  202. `);
  203. console.log("Youtube Wide video container Fade++ compatibilty style added to DOM");
  204. }
  205. }
  206.  
  207. if(AutoExpandChannelVidContainers || HQTN)
  208. {
  209. var lastCheckedURL = window.location.href;
  210. URLChanged(); //for initial page load
  211.  
  212. //poll for url changes
  213. setInterval(function(){
  214. if(lastCheckedURL != window.location.href)
  215. {
  216. lastCheckedURL = window.location.href;
  217. URLChanged();
  218. }
  219. }, 200);
  220. var waitForArrows, waitForSubsThumbnails;
  221. }
  222. /*============================================================*/
  223.  
  224. function AutoExpandContainers()
  225. {
  226. clearInterval(waitForArrows);
  227.  
  228. //=== clear potential old containers ===//
  229. let expandedEls = document.getElementsByClassName("expanded-wwc");
  230. //console.log("expanded els found: " + expandedEls.length);
  231. let numRemoved = 0;
  232.  
  233. //seems to always remove exactly half of them only, for some reason. So I guess do this until all have been removed
  234. while(expandedEls.length > 0)
  235. {
  236. for(let x = 0; x < expandedEls.length; x++)
  237. {
  238. if(!!expandedEls[x])
  239. {
  240. expandedEls[x].classList.remove("expanded-wwc");
  241. //console.log(++numRemoved + " cleared");
  242. }
  243. }
  244. expandedEls = document.getElementsByClassName("expanded-wwc");
  245. }
  246. //=== old containers cleared ===//
  247.  
  248. //=== unmark container arrows marked as clicked ===//
  249. numRemoved = 0;
  250. let clickedArrows = document.getElementsByClassName("clicked");
  251. //console.log("clicked found: " + clickedArrows.length);
  252. while(clickedArrows.length > 0)
  253. {
  254. for(let x = 0; x < clickedArrows.length; x++)
  255. {
  256. if(!!clickedArrows[x])
  257. {
  258. clickedArrows[x].classList.remove("clicked");
  259. //console.log(++numRemoved + " cleared");
  260. }
  261. }
  262. clickedArrows = document.getElementsByClassName("clicked");
  263. }
  264. //=== all arrows unmarked ===//
  265. //console.log("-expandedclear-");
  266.  
  267. //check that we are on a page that can have containers
  268. if(lastCheckedURL.includes("/user/") || lastCheckedURL.includes("/channel/"))
  269. {
  270. //poll for untouched containers
  271. waitForArrows = setInterval(function(){
  272. //console.log("-searching...-");
  273. let arrowsRight = document.querySelectorAll("yt-horizontal-list-renderer:not(.expanded-wwc) > #right-arrow > ytd-button-renderer.arrow");
  274. let arrowsLeft = document.querySelectorAll("yt-horizontal-list-renderer:not(.expanded-wwc) > #left-arrow > ytd-button-renderer.arrow");
  275. if(!!arrowsRight && arrowsRight.length > 0 && !!arrowsLeft && arrowsLeft.length > 0)
  276. {
  277. //console.log("-found-");
  278. //do the thing for found untouched containers and mark them
  279. for(let i = 0; i < arrowsRight.length; i++)
  280. {
  281. if(!!arrowsRight[i] && arrowsRight[i].offsetParent !== null && !!arrowsLeft[i] && arrowsLeft[i].offsetParent !== null)
  282. {
  283. arrowsRight[i].parentElement.parentElement.classList.add("expanded-wwc");
  284. arrowsRight[i].click();
  285. //console.log("simulated click on right arrow");
  286. arrowsRight[i].classList.add("clicked");
  287. arrowsLeft[i].click();
  288. //console.log("simulated click on left arrow");
  289. arrowsLeft[i].classList.add("clicked");
  290. }
  291. }
  292. }
  293. }, 250);
  294. }
  295. }
  296.  
  297. function SwapSubsVidThumbnailsHQ()
  298. {
  299. clearInterval(waitForSubsThumbnails);
  300. if(lastCheckedURL.includes("/subscriptions"))
  301. {
  302. waitForSubsThumbnails = setInterval(function(){
  303. let nails = document.querySelectorAll("img.yt-img-shadow[src*='hqdefault.jpg?']");
  304. //console.log("found " + nails.length + " LQ nails");
  305. for(let i = 0; i < nails.length; i++)
  306. nails[i].src = nails[i].src.split("?")[0];
  307. }, 200);
  308. }
  309. }
  310.  
  311. function URLChanged()
  312. {
  313. console.log("-urlchanged-");
  314.  
  315. if(AutoExpandChannelVidContainers)
  316. AutoExpandContainers();
  317.  
  318. if(HQTN)
  319. SwapSubsVidThumbnailsHQ();
  320. }
  321. function CleanCSSValue(val)
  322. {
  323. val = val.trim();
  324.  
  325. //if only numbers...
  326. if(/^\d+$/.test(val))
  327. val += "px"; //...add px
  328.  
  329. return val;
  330. }
  331. function addGlobalStyle(css)
  332. {
  333. var head, style;
  334. head = document.getElementsByTagName('head')[0];
  335. if (!head) { return; }
  336. style = document.createElement('style');
  337. style.type = 'text/css';
  338. style.innerHTML = css;
  339. head.appendChild(style);
  340. }
  341.  
  342. //=== SETTINGS HANDLE FUCTIONS ===//
  343. function SetFPPHandle() {
  344. GM_unregisterMenuCommand(FPPHandle);
  345.  
  346. FPPHandle = GM_registerMenuCommand("Fade++ Compatibility mode (" + (FPPCompOn ? "On" : "Off") + ") -click to change-", function(){
  347. FPPCompOn = !FPPCompOn;
  348. GM_setValue("FPPCompOn", FPPCompOn);
  349. SetFPPHandle();
  350.  
  351. if(confirm('Press "OK" to refresh the page to apply new settings'))
  352. location.reload();
  353. });
  354. }
  355. function SetForceCSSHandle() {
  356. GM_unregisterMenuCommand(ForceCSSHandle);
  357.  
  358. ForceCSSHandle = GM_registerMenuCommand("CSS important rule mode (" + (ForceCSSOn ? "On" : "Off") + ") -click to change-", function(){
  359. ForceCSSOn = !ForceCSSOn;
  360. GM_setValue("ForceCSSOn", ForceCSSOn);
  361. SetForceCSSHandle();
  362.  
  363. if(confirm('Press "OK" to refresh the page to apply new settings'))
  364. location.reload();
  365. });
  366. }
  367. function SetHomeVideoContainerWidthHandle() {
  368. GM_unregisterMenuCommand(HomeVideoContainerWidthHandle);
  369.  
  370. HomeVideoContainerWidthHandle = GM_registerMenuCommand("[home-page] Video-renderer width (" + HomeVideoContainerWidth + ") -click to change-", function(){
  371. HomeVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nThe current value is: '" + HomeVideoContainerWidth + "'"));
  372. GM_setValue("HomeVideoContainerWidth", HomeVideoContainerWidth);
  373. SetHomeVideoContainerWidthHandle();
  374.  
  375. if(confirm('Press "OK" to refresh the page to apply new settings'))
  376. location.reload();
  377. });
  378. }
  379. function SetHQTNHandle() {
  380. GM_unregisterMenuCommand(HQTNHandle);
  381.  
  382. HQTNHandle = GM_registerMenuCommand("[subs-page] Load HQ thumbnails (" + (HQTN ? "On" : "Off") + ") -click to change-", function(){
  383. HQTN = !HQTN;
  384. GM_setValue("HQTN", HQTN);
  385. SetHQTNHandle();
  386.  
  387. if(confirm('Press "OK" to refresh the page to apply new settings'))
  388. location.reload();
  389. });
  390. }
  391. function SetSubVideoContainerWidthHandle() {
  392. GM_unregisterMenuCommand(SubVideoContainerWidthHandle);
  393.  
  394. SubVideoContainerWidthHandle = GM_registerMenuCommand("[subs-page] Video-renderer width (" + SubVideoContainerWidth + ") -click to change-", function(){
  395. SubVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nNote: Currently values larger than the default (210px) make the thumbnails blurry, as youtube only loads 210px resolution images. I might make a workaround for this later.\nThe current value is: '" + SubVideoContainerWidth + "'"));
  396. GM_setValue("SubVideoContainerWidth", SubVideoContainerWidth);
  397. SetSubVideoContainerWidthHandle();
  398.  
  399. if(confirm('Press "OK" to refresh the page to apply new settings'))
  400. location.reload();
  401. });
  402. }
  403. function SetTrendingVideoContainerWidthHandle() {
  404. GM_unregisterMenuCommand(TrendingVideoContainerWidthHandle);
  405.  
  406. TrendingVideoContainerWidthHandle = GM_registerMenuCommand("[trending-page] Video-renderer width (" + TrendingVideoContainerWidth + ") -click to change-", function(){
  407. TrendingVideoContainerWidth = CleanCSSValue(prompt("Set the width of a single video renderer on the page (use CSS units)\nThe current value is: '" + TrendingVideoContainerWidth + "'"));
  408. GM_setValue("TrendingVideoContainerWidth", TrendingVideoContainerWidth);
  409. SetTrendingVideoContainerWidthHandle();
  410.  
  411. if(confirm('Press "OK" to refresh the page to apply new settings'))
  412. location.reload();
  413. });
  414. }
  415. function SetVideoContainerHorMarginHandle() {
  416. GM_unregisterMenuCommand(VideoContainerHorMarginHandle);
  417.  
  418. VideoContainerHorMarginHandle = GM_registerMenuCommand("[all pages] Video-renderer horizontal margin (" + VideoContainerHorMargin + ") -click to change-", function(){
  419. VideoContainerHorMargin = CleanCSSValue(prompt("Set the horizontal margin of a single video renderer on the page. i.e. the space between videos (use CSS units)\nThe current value is: '" + VideoContainerHorMargin + "'"));
  420. GM_setValue("VideoContainerHorMargin", VideoContainerHorMargin);
  421. SetVideoContainerHorMarginHandle();
  422.  
  423. if(confirm('Press "OK" to refresh the page to apply new settings'))
  424. location.reload();
  425. });
  426. }
  427. function SetVideoContainerVerMarginHandle() {
  428. GM_unregisterMenuCommand(VideoContainerVerMarginHandle);
  429.  
  430. VideoContainerVerMarginHandle = GM_registerMenuCommand("[all pages] Video-renderer vertical margin (" + VideoContainerVerMargin + ") -click to change-", function(){
  431. VideoContainerVerMargin = CleanCSSValue(prompt("Set the vertical margin of a single video renderer on the page. i.e. the space between videos (use CSS units)\nThe current value is: '" + VideoContainerVerMargin + "'"));
  432. GM_setValue("VideoContainerVerMargin", VideoContainerVerMargin);
  433. SetVideoContainerVerMarginHandle();
  434.  
  435. if(confirm('Press "OK" to refresh the page to apply new settings'))
  436. location.reload();
  437. });
  438. }
  439. function SetShowChannelIconNextToVideosOnHomePageHandle() {
  440. GM_unregisterMenuCommand(ShowChannelIconNextToVideosOnHomePageHandle);
  441.  
  442. ShowChannelIconNextToVideosOnHomePageHandle = GM_registerMenuCommand("[homepage] Show channel icons next to videos (" + (ShowChannelIconNextToVideosOnHomePage ? "Yes" : "No") + ") -click to change-", function(){
  443. ShowChannelIconNextToVideosOnHomePage = !ShowChannelIconNextToVideosOnHomePage;
  444. GM_setValue("ShowChannelIconNextToVideosOnHomePage", ShowChannelIconNextToVideosOnHomePage);
  445. SetShowChannelIconNextToVideosOnHomePageHandle();
  446.  
  447. if(confirm('Press "OK" to refresh the page to apply new settings'))
  448. location.reload();
  449. });
  450. }
  451. function SetAutoExpandChannelVidContainersHandle() {
  452. GM_unregisterMenuCommand(AutoExpandChannelVidContainersHandle);
  453.  
  454. AutoExpandChannelVidContainersHandle = GM_registerMenuCommand("[channel-page] Auto-expand horizontal video lists (" + (AutoExpandChannelVidContainers ? "Yes" : "No") + ") -click to change-", function(){
  455. AutoExpandChannelVidContainers = !AutoExpandChannelVidContainers;
  456. GM_setValue("AutoExpandChannelVidContainers", AutoExpandChannelVidContainers);
  457. SetAutoExpandChannelVidContainersHandle();
  458.  
  459. if(confirm('Press "OK" to refresh the page to apply new settings'))
  460. location.reload();
  461. });
  462. }
  463. })();

QingJ © 2025

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