Space-efficient Youtube

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

当前为 2022-09-18 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Space-efficient Youtube
  3. // @namespace 1N07
  4. // @author 1N07
  5. // @icon https://i.imgur.com/VgEiyi3.png
  6. // @icon64 https://i.imgur.com/VgEiyi3.png
  7. // @description AKA: "Wide Youtube", AKA: "Wide video container" - Uses the page space on youtube more efficiently (especially good for high resolutions)
  8. // @license unlicense
  9. // @include https://www.youtube.com/*
  10. // @version 2.4.3
  11. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  12. // @grant GM_registerMenuCommand
  13. // @grant GM_unregisterMenuCommand
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @noframes
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. if(true)
  21. {
  22. var configCSS = `
  23. #SEYConfig {
  24. width: 320px !important;
  25. height: auto !important;
  26. max-height: 100% !important;
  27. border: none !important;
  28. border-radius: 0 0 0 20px !important;
  29. box-shadow: black -1px 1px 20px;
  30. position: fixed !important;
  31. top: 0 !important;
  32. right: 0 !important;
  33. left: unset !important;
  34. background: #383838 !important;
  35. }
  36.  
  37. #SEYConfig_wrapper
  38. {
  39. padding: 10px;
  40. background-color: #212121;
  41. color: white;
  42. background-color: transparent;
  43. }
  44.  
  45. #SEYConfig .config_var
  46. {
  47. padding: 1px 20px;
  48. }
  49.  
  50. #SEYConfig input
  51. {
  52. background-color: #181818;
  53. color: white;
  54. border: none;
  55. float: left;
  56. margin-right: 5px;
  57. }
  58.  
  59. #SEYConfig input[type="text"]
  60. {
  61. width: 40px;
  62. text-align: center;
  63. }
  64.  
  65. #SEYConfig input[type="checkbox"]
  66. {
  67. filter: invert(90%);
  68. }
  69.  
  70. #SEYConfig .saveclose_buttons
  71. {
  72. background-color: #181818;
  73. color: white;
  74. border-color: gray;
  75. margin: 16px 5px 5px;
  76. }
  77.  
  78. #SEYConfig .section_header {
  79. background: #202020;
  80. margin-bottom: 5px;
  81. }
  82.  
  83. #SEYConfig .section_header_holder {
  84. margin-top: 8px;
  85. background-color: rgba(0,0,0,0.3);
  86. padding: 0 0 5px 0;
  87. border-radius: 0 0 10px 10px;
  88. }
  89.  
  90. #SEYConfig_resetLink { color: white !important; }
  91. `;
  92. }
  93.  
  94. var frame = document.createElement('div');
  95. frame.id = "SEYConf";
  96. document.body.appendChild(frame);
  97.  
  98. GM_config.init(
  99. {
  100. 'id': 'SEYConfig', // The id used for this instance of GM_config
  101. 'title': 'Space-efficient Youtube Config',
  102. 'fields': // Fields object
  103. {
  104. 'FPPCompOn': // This is the id of the field
  105. {
  106. 'section': 'Fade++',
  107. 'label': 'Fade++ compatibility mode', // Appears next to field
  108. 'type': 'checkbox', // Makes this setting a text field
  109. 'default': false // Default value if user doesn't change it
  110. },
  111.  
  112. 'HomeVideoContainerWidthEnabled':
  113. {
  114. 'section': 'Home page',
  115. 'label': 'Video container size mod enabled',
  116. 'title': 'Enables the video sizing modification below. This is disabled by default for now, due to a change in how YT renders videos on the home page. Might fix later. Enabling this will cause the video containers to be sized as set below, but the empty space is not properly used.',
  117. 'type': 'checkbox',
  118. 'default': false
  119. },
  120. 'HomeVideoContainerWidth':
  121. {
  122. 'label': 'Video container width',
  123. 'title': 'The width of the container which includes both the thumbnail and the title/other info',
  124. 'type': 'unsigned float',
  125. 'default': '360'
  126. },
  127. 'HideChannelIconNextToVideosOnHomePage':
  128. {
  129. 'label': 'Hide channel icon in video container',
  130. 'type': 'checkbox',
  131. 'default': false
  132. },
  133.  
  134. 'SubVideoContainerWidth':
  135. {
  136. 'section': 'Subscriptions page',
  137. 'label': 'Video container width',
  138. 'title': 'The width of the container which includes both the thumbnail and the title/other info',
  139. 'type': 'unsigned float',
  140. 'default': '210'
  141. },
  142.  
  143. 'TrendingVideoContainerWidth':
  144. {
  145. 'section': 'Trending page',
  146. 'label': 'Video container width',
  147. 'title': 'The width of the container which includes both the thumbnail and the title/other info',
  148. 'type': 'unsigned float',
  149. 'default': '600'
  150. },
  151. 'TrendingVideoContainerHeight':
  152. {
  153. 'label': 'Video container height',
  154. 'title': 'The height of the container. This directly affects thumnail size and how much space is left for the other info',
  155. 'type': 'unsigned float',
  156. 'default': '138'
  157. },
  158.  
  159. 'HQTN':
  160. {
  161. 'section': 'Subscriptions & Trending pages',
  162. 'label': 'Load high quality thumbnails',
  163. 'title': 'The default thumbnail resolution is fitted for the default video container size, so if you use defaults(or smaller) there is no need to enable this.',
  164. 'type': 'checkbox',
  165. 'default': false
  166. },
  167.  
  168. 'SearchVideoContainerWidth':
  169. {
  170. 'section': 'Search results page',
  171. 'label': 'Video container width',
  172. 'title': 'The width of the container which includes both the thumbnail and the title/other info',
  173. 'type': 'unsigned float',
  174. 'default': '600'
  175. },
  176. 'SearchVideoContainerHeight':
  177. {
  178. 'label': 'Video container height',
  179. 'title': 'The height of the container. This directly affects thumnail size and how much space is left for the other info',
  180. 'type': 'unsigned float',
  181. 'default': '150'
  182. },
  183. 'HideSearchVideoBadges':
  184. {
  185. 'label': 'Hide video badges',
  186. 'title': 'Hides the little badges like New/4K/CC etc. on the video containers leaving more space for the description',
  187. 'type': 'checkbox',
  188. 'default': false
  189. },
  190.  
  191. 'VPRecommendedSectionWidth':
  192. {
  193. 'section': 'Video Page Recommended',
  194. 'label': 'Recommended section width',
  195. 'title': 'The width of the recommended section holding the video containers. [Theater mode only]',
  196. 'type': 'unsigned float',
  197. 'default': '426'
  198. },
  199. 'VPRecommendedVideoContainerHeight':
  200. {
  201. 'label': 'Video height',
  202. 'title': 'The height of the container. This directly affects thumnail size and how much space is left for the other info [Theater mode only]',
  203. 'type': 'unsigned float',
  204. 'default': '94'
  205. },
  206. 'VPRecommendedColumnCount':
  207. {
  208. 'label': 'Video column count',
  209. 'title': 'How many columns of videos to display. This directly affects the video container width of each video. e.g. 2 = 2 columns where video container width is 50% of the section width [Theater mode only]',
  210. 'type': 'unsigned float',
  211. 'default': '1'
  212. },
  213.  
  214. 'AutoExpandChannelVidContainers':
  215. {
  216. 'section': 'Channel pages',
  217. 'label': 'Auto-expand horizontal video lists',
  218. 'type': 'checkbox',
  219. 'default': false
  220. }
  221. },
  222. 'frame': frame,
  223. 'css': configCSS
  224. }
  225. );
  226.  
  227. var refreshAfterSave = false;
  228. GM_config.onOpen = function(doc, win, frame) {
  229. let saveBtn = frame.querySelector("#SEYConfig_saveBtn");
  230. let clone = saveBtn.cloneNode();
  231. clone.id = "SEYConfig_saveRefreshBtn";
  232. clone.textContent = "Save & Refresh";
  233. saveBtn.parentNode.insertBefore(clone, saveBtn);
  234. clone.onclick = function(){
  235. refreshAfterSave = true;
  236. saveBtn.click();
  237. };
  238. };
  239. GM_config.onSave = function(){
  240. if(refreshAfterSave)
  241. location.reload();
  242. };
  243.  
  244. var FPPCompOn = GM_config.get('FPPCompOn');
  245. var HomeVideoContainerWidthEnabled = GM_config.get('HomeVideoContainerWidthEnabled');
  246. var HomeVideoContainerWidth = CleanNumber(GM_config.get('HomeVideoContainerWidth'));
  247. var HideChannelIconNextToVideosOnHomePage = GM_config.get('HideChannelIconNextToVideosOnHomePage');
  248. var SubVideoContainerWidth = CleanNumber(GM_config.get("SubVideoContainerWidth"));
  249. var TrendingVideoContainerWidth = CleanNumber(GM_config.get('TrendingVideoContainerWidth'));
  250. var TrendingVideoContainerHeight = CleanNumber(GM_config.get('TrendingVideoContainerHeight'));
  251. var HQTN = GM_config.get('HQTN');
  252. var SearchVideoContainerWidth = CleanNumber(GM_config.get('SearchVideoContainerWidth'));
  253. var SearchVideoContainerHeight = CleanNumber(GM_config.get('SearchVideoContainerHeight'));
  254. var HideSearchVideoBadges = GM_config.get('HideSearchVideoBadges');
  255. var AutoExpandChannelVidContainers = GM_config.get('AutoExpandChannelVidContainers');
  256. var VPRecommendedSectionWidth = CleanNumber(GM_config.get('VPRecommendedSectionWidth'));
  257. var VPRecommendedVideoContainerHeight = CleanNumber(GM_config.get('VPRecommendedVideoContainerHeight'));
  258. var VPRecommendedColumnCount = CleanNumber(GM_config.get('VPRecommendedColumnCount'));
  259.  
  260.  
  261. GM_registerMenuCommand("Settings", () => {
  262. if(!GM_config.isOpen)
  263. GM_config.open();
  264. });
  265.  
  266. const ratioMultiplier = 16 / 9;
  267. var screenWidth = screen.width;
  268. if(!!document.getElementById("early-body")) { //if old youtube
  269. document.getElementById("content").setAttribute("style", "width: 99%;");
  270. } else { //new youtube
  271. //Main container width and padding
  272. if(true) {
  273. addGlobalStyle(`
  274. /*search*/
  275. ytd-search ytd-two-column-search-results-renderer.ytd-search,
  276. ytd-search ytd-two-column-search-results-renderer.ytd-search > #primary,
  277. /*home*/
  278. ytd-browse[page-subtype="home"] #contents.ytd-rich-grid-renderer,
  279. /*video*/
  280. #content [role="main"][theater-requested_] #columns,
  281. /*other*/
  282. ytd-browse > ytd-two-column-browse-results-renderer.ytd-browse
  283. {
  284. width: 100% !important;
  285. max-width: 100% !important;
  286. }
  287.  
  288. ytd-browse > ytd-two-column-browse-results-renderer.ytd-browse > #primary,
  289. ytd-search,
  290. #columns
  291. {
  292. padding: 0 16px;
  293. }
  294.  
  295. #content [role="main"][theater-requested_] #columns {
  296. box-sizing: border-box;
  297. }
  298. `);
  299. }
  300.  
  301. //page-manager element tends to sometimes be a few pixels too large for some reason...
  302. //...so hiding overflow
  303. if(true) {
  304. addGlobalStyle(`
  305. ytd-page-manager#page-manager { overflow: hidden; }
  306. `);
  307. }
  308.  
  309. //vertical lists to horizontal grid / video container sizing
  310. if(true) {
  311. //trending
  312. if(true) {
  313. addGlobalStyle(`
  314. /*container*/
  315. #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer
  316. {
  317. display: inline-block;
  318. width: `+TrendingVideoContainerWidth+`px;
  319. height: `+TrendingVideoContainerHeight+`px;
  320. }
  321. #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer > #dismissable
  322. {
  323. width: 100%;
  324. height: 100%;
  325. }
  326.  
  327. /*thumnail container*/
  328. #grid-container.ytd-expanded-shelf-contents-renderer > ytd-video-renderer:not([use-prominent-thumbs]) ytd-thumbnail.ytd-video-renderer,
  329. #grid-container.ytd-expanded-shelf-contents-renderer > ytd-video-renderer:not([use-prominent-thumbs]) ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail
  330. {
  331. height: 100%;
  332. width: `+(TrendingVideoContainerHeight * ratioMultiplier)+`px;
  333. }
  334.  
  335. /*thumnail shadow and image*/
  336. #grid-container.ytd-expanded-shelf-contents-renderer > ytd-video-renderer:not([use-prominent-thumbs]) ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail > img
  337. {
  338. height: 100% !important;
  339. width: 100% !important;
  340. }
  341. `);
  342. }
  343.  
  344. //search
  345. if(true) {
  346. addGlobalStyle(`
  347. /*container*/
  348. ytd-search ytd-video-renderer, ytd-search ytd-channel-renderer, ytd-search ytd-radio-renderer, ytd-search ytd-playlist-renderer
  349. {
  350. display: inline-block;
  351. width: `+SearchVideoContainerWidth+`px;
  352. height: `+SearchVideoContainerHeight+`px;
  353. box-sizing: border-box;
  354. }
  355. ytd-search ytd-video-renderer > #dismissable
  356. {
  357. width: 100%;
  358. height: 100%;
  359. }
  360.  
  361. /*thumnail container*/
  362. ytd-search ytd-video-renderer[use-prominent-thumbs] ytd-thumbnail.ytd-video-renderer,
  363. ytd-search ytd-radio-renderer[use-prominent-thumbs] ytd-thumbnail.ytd-radio-renderer,
  364. ytd-search ytd-playlist-renderer[use-prominent-thumbs] ytd-playlist-thumbnail.ytd-playlist-renderer
  365. {
  366. max-width: none;
  367. min-width: none;
  368. height: 100%;
  369. width: `+(SearchVideoContainerHeight * ratioMultiplier)+`px;
  370. -ms-flex: none;
  371. -webkit-flex: none;
  372. flex: none;
  373. }
  374. ytd-search ytd-radio-renderer.ytd-item-section-renderer,
  375. ytd-search ytd-playlist-renderer.ytd-item-section-renderer
  376. {
  377. display: flex;
  378. }
  379.  
  380. /*thumnail shadow and image*/
  381. ytd-search ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail,
  382. ytd-search ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail > img
  383. {
  384. width: 100%;
  385. height: 100%;
  386. }
  387.  
  388. /*other*/
  389. ytd-search #description-text.ytd-video-renderer
  390. {
  391. margin-bottom: 2px;
  392. }
  393. ytd-search ytd-video-renderer > #dismissable #channel-info
  394. {
  395. padding: 2px 0 0 0;
  396. }
  397. ytd-search #description-text.ytd-video-renderer
  398. {
  399. max-height: none;
  400. }
  401. `+(HideSearchVideoBadges ? `ytd-search ytd-badge-supported-renderer { display: none; }` : ``)+`
  402.  
  403. /*channel thumnail container*/
  404. ytd-search #avatar.ytd-channel-renderer,
  405. ytd-search ytd-channel-renderer[use-prominent-thumbs] #avatar-section.ytd-channel-renderer .channel-link.ytd-channel-renderer,
  406. ytd-search ytd-channel-renderer[use-prominent-thumbs] #avatar-section.ytd-channel-renderer
  407. {
  408. width: min-content;
  409. width: -moz-min-content;
  410. flex: none;
  411. max-width: none;
  412. min-width: 0;
  413. }
  414.  
  415. ytd-search div.ytd-video-renderer[id="channel-info"] { padding: 3px 0 0 0 !important; }
  416.  
  417. yt-showing-results-for-renderer { display: block; }
  418. `);
  419. }
  420.  
  421. //home
  422. if(true) {
  423. if(HomeVideoContainerWidthEnabled) {
  424. addGlobalStyle(`
  425. /*container*/
  426. ytd-browse[page-subtype="home"] ytd-rich-item-renderer
  427. {
  428. width: `+HomeVideoContainerWidth+`px;
  429. }
  430. `);
  431. }
  432. if(HideChannelIconNextToVideosOnHomePage) {
  433. addGlobalStyle(`ytd-browse[page-subtype="home"] #avatar-link.ytd-rich-grid-media { display: none; }`);
  434. }
  435. }
  436.  
  437. //subs
  438. if(true) {
  439. addGlobalStyle(`
  440. /*container*/
  441. ytd-browse[page-subtype="subscriptions"] #items.ytd-grid-renderer > ytd-grid-video-renderer.ytd-grid-renderer
  442. {
  443. width: `+SubVideoContainerWidth+`px;
  444. }
  445.  
  446. /*thumnail container*/
  447. ytd-browse[page-subtype="subscriptions"] ytd-thumbnail.ytd-grid-video-renderer
  448. {
  449. width: `+SubVideoContainerWidth+`px;
  450. height: `+(SubVideoContainerWidth / ratioMultiplier)+`px;
  451. }
  452.  
  453. /*thumnail shadow and image*/
  454. ytd-browse[page-subtype="subscriptions"] ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail,
  455. ytd-browse[page-subtype="subscriptions"] ytd-thumbnail #thumbnail.ytd-thumbnail yt-img-shadow.ytd-thumbnail > img
  456. {
  457. width: 100%;
  458. height: 100%;
  459. }
  460.  
  461. /*List layout vid container*/
  462. ytd-browse[page-subtype="subscriptions"] #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer
  463. { width: 100%; }
  464. ytd-browse[page-subtype="subscriptions"] #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer div.text-wrapper
  465. { max-width: none; }
  466. `);
  467. }
  468.  
  469. //video page
  470. if(true) {
  471. addGlobalStyle(`
  472. /*thumnail container*/
  473. #content [role="main"][theater-requested_] #columns #secondary #items > ytd-item-section-renderer > #contents > .ytd-item-section-renderer
  474. {
  475. display: inline-block;
  476. width: calc(`+(100 / VPRecommendedColumnCount)+`% - 5px);
  477. height: `+VPRecommendedVideoContainerHeight+`px;
  478. margin: 0;
  479. flex-grow: 1;
  480. box-sizing: border-box;
  481. }
  482.  
  483. #content [role="main"][theater-requested_] #columns #secondary #items > ytd-item-section-renderer > #contents > .ytd-item-section-renderer > #dismissible
  484. {
  485. width: 100%;
  486. height: 100%;
  487. }
  488.  
  489. /*thumnail container*/
  490. [role="main"][theater-requested_] .ytd-item-section-renderer ytd-thumbnail,
  491. [role="main"][theater-requested_] .ytd-item-section-renderer ytd-thumbnail yt-img-shadow.ytd-thumbnail
  492. {
  493. height: 100%;
  494. width: `+(VPRecommendedVideoContainerHeight * ratioMultiplier)+`px;
  495. }
  496.  
  497. /*thumnail shadow and image*/
  498. [role="main"][theater-requested_] .ytd-item-section-renderer ytd-thumbnail yt-img-shadow.ytd-thumbnail > img
  499. {
  500. width: 100%;
  501. height: 100%;
  502. }
  503. `);
  504. }
  505.  
  506. //multiple
  507. if(true) {
  508. addGlobalStyle(`#dismissible.ytd-video-renderer { height: 100%; }`);
  509. }
  510. }
  511.  
  512. //video container padding/margin
  513. if(true) {
  514. //trending
  515. if(true) {
  516. addGlobalStyle(`
  517. #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer
  518. {
  519. padding: 0 10px 0 0;
  520. }
  521. #grid-container.ytd-expanded-shelf-contents-renderer > .ytd-expanded-shelf-contents-renderer:not(:last-child)
  522. {
  523. margin: 0 0 10px 0;
  524. }
  525. `);
  526. }
  527.  
  528. //search
  529. if(true) {
  530. addGlobalStyle(`
  531. ytd-search ytd-video-renderer.ytd-item-section-renderer,
  532. ytd-search ytd-channel-renderer.ytd-item-section-renderer,
  533. ytd-search ytd-radio-renderer.ytd-item-section-renderer,
  534. ytd-search ytd-playlist-renderer.ytd-item-section-renderer,
  535. ytd-search #items.ytd-vertical-list-renderer > .ytd-vertical-list-renderer
  536. {
  537. padding: 0 10px 0 0;
  538. margin: 10px 0 0 0;
  539. }
  540. ytd-search ytd-shelf-renderer.ytd-item-section-renderer
  541. {
  542. margin: 10px 0 0 0;
  543. }
  544. `);
  545. }
  546.  
  547. //home
  548. if(true) {
  549. addGlobalStyle(`
  550. ytd-browse[page-subtype="home"] ytd-rich-item-renderer
  551. {
  552. margin: 0 5px 20px 5px;
  553. }
  554. ytd-browse[page-subtype="home"] ytd-rich-section-renderer
  555. {
  556. margin: 0;
  557. }
  558. `);
  559. }
  560.  
  561. //subs
  562. if(true) {
  563. addGlobalStyle(`
  564. ytd-browse[page-subtype="subscriptions"] #items.ytd-grid-renderer > ytd-grid-video-renderer.ytd-grid-renderer
  565. {
  566. margin: 0 5px 15px 0;
  567. }
  568. `);
  569. }
  570.  
  571. //video page
  572. if(true) {
  573. addGlobalStyle(`
  574. #content [role="main"][theater-requested_] #columns > #secondary
  575. {
  576. width: `+VPRecommendedSectionWidth+`px;
  577. }
  578. #content [role="main"][theater-requested_] #columns > #secondary #items #contents {
  579. display: flex;
  580. flex-wrap: wrap;
  581. gap: 8px 1px;
  582. }
  583. `);
  584. }
  585. }
  586.  
  587. //channel page horizontal list arrow visibility
  588. if(true) {
  589. addGlobalStyle(`
  590. yt-horizontal-list-renderer[at-start] #left-arrow.yt-horizontal-list-renderer .arrow.yt-horizontal-list-renderer,
  591. yt-horizontal-list-renderer[at-end] #right-arrow.yt-horizontal-list-renderer .arrow.yt-horizontal-list-renderer
  592. {
  593. display: block;
  594. opacity: 1;
  595. }
  596. `+(!!window.chrome ? `
  597. #left-arrow.yt-horizontal-list-renderer { left: 20px; }
  598. #right-arrow.yt-horizontal-list-renderer { right: 20px; }
  599. ` : `
  600. #left-arrow.yt-horizontal-list-renderer { left: 0px; }
  601. #right-arrow.yt-horizontal-list-renderer { right: 40px; }
  602. `)
  603. );
  604. }
  605.  
  606. if(HQTN) {
  607. addGlobalStyle(`
  608. img.yt-img-shadow:not([src*='?'])
  609. {
  610. object-fit: cover;
  611. }
  612. `);
  613. }
  614. if(FPPCompOn) {
  615. addGlobalStyle(`
  616. /*========== Fade++ Compatibility ==========*/
  617. ytd-app #page-manager > ytd-browse:not([page-subtype="playlist"]) {
  618. display: block;
  619. }
  620. ytd-app[guide-persistent-and-visible] #page-manager > ytd-browse:not([page-subtype="playlist"]) ytd-two-column-browse-results-renderer.ytd-browse
  621. {
  622. margin-left: 250px !important;
  623. }
  624. `);
  625. //console.log("Youtube Wide video container Fade++ compatibilty style added to DOM");
  626. }
  627. }
  628.  
  629. if(AutoExpandChannelVidContainers || HQTN)
  630. {
  631. var lastCheckedURL = window.location.href;
  632. URLChanged(); //for initial page load
  633.  
  634. //poll for url changes
  635. setInterval(function(){
  636. if(lastCheckedURL != window.location.href)
  637. {
  638. lastCheckedURL = window.location.href;
  639. URLChanged();
  640. }
  641. }, 200);
  642. var waitForArrows, waitForSubsThumbnails;
  643. }
  644. /*============================================================*/
  645.  
  646. function AutoExpandContainers()
  647. {
  648. clearInterval(waitForArrows);
  649.  
  650. //=== clear potential old containers ===//
  651. let expandedEls = document.getElementsByClassName("expanded-wwc");
  652. //console.log("expanded els found: " + expandedEls.length);
  653. let numRemoved = 0;
  654.  
  655. //seems to always remove exactly half of them only, for some reason. So I guess do this until all have been removed
  656. while(expandedEls.length > 0)
  657. {
  658. for(let x = 0; x < expandedEls.length; x++)
  659. {
  660. if(!!expandedEls[x])
  661. {
  662. expandedEls[x].classList.remove("expanded-wwc");
  663. //console.log(++numRemoved + " cleared");
  664. }
  665. }
  666. expandedEls = document.getElementsByClassName("expanded-wwc");
  667. }
  668. //=== old containers cleared ===//
  669.  
  670. //=== unmark container arrows marked as clicked ===//
  671. numRemoved = 0;
  672. let clickedArrows = document.getElementsByClassName("clicked");
  673. //console.log("clicked found: " + clickedArrows.length);
  674. while(clickedArrows.length > 0)
  675. {
  676. for(let x = 0; x < clickedArrows.length; x++)
  677. {
  678. if(!!clickedArrows[x])
  679. {
  680. clickedArrows[x].classList.remove("clicked");
  681. //console.log(++numRemoved + " cleared");
  682. }
  683. }
  684. clickedArrows = document.getElementsByClassName("clicked");
  685. }
  686. //=== all arrows unmarked ===//
  687. //console.log("-expandedclear-");
  688.  
  689. //check that we are on a page that can have containers
  690. if(lastCheckedURL.includes("/user/") || lastCheckedURL.includes("/channel/") || lastCheckedURL.includes("/c/"))
  691. {
  692. //poll for untouched containers
  693. waitForArrows = setInterval(function(){
  694. //console.log("-searching...-");
  695. let arrowsRight = document.querySelectorAll("yt-horizontal-list-renderer:not(.expanded-wwc) > #right-arrow > ytd-button-renderer.arrow");
  696. let arrowsLeft = document.querySelectorAll("yt-horizontal-list-renderer:not(.expanded-wwc) > #left-arrow > ytd-button-renderer.arrow");
  697. if(!!arrowsRight && arrowsRight.length > 0 && !!arrowsLeft && arrowsLeft.length > 0)
  698. {
  699. //console.log("-found "+arrowsRight.length+"-");
  700. //do the thing for found untouched containers and mark them
  701. for(let i = 0; i < arrowsRight.length; i++)
  702. {
  703. if(!!arrowsRight[i] && arrowsRight[i].offsetParent !== null && !!arrowsLeft[i] && arrowsLeft[i].offsetParent !== null)
  704. {
  705. arrowsRight[i].parentElement.parentElement.classList.add("expanded-wwc");
  706. arrowsRight[i].click();
  707. //console.log("simulated click on right arrow");
  708. arrowsRight[i].classList.add("clicked");
  709. arrowsLeft[i].click();
  710. //console.log("simulated click on left arrow");
  711. arrowsLeft[i].classList.add("clicked");
  712. }
  713. }
  714. }
  715. }, 250);
  716. }
  717. }
  718.  
  719. function SwapSubsVidThumbnailsHQ()
  720. {
  721. clearInterval(waitForSubsThumbnails);
  722. if(lastCheckedURL.includes("/subscriptions") || lastCheckedURL.includes("/trending"))
  723. {
  724. waitForSubsThumbnails = setInterval(function(){
  725. let nails = document.querySelectorAll("img.yt-img-shadow[src*='hqdefault.jpg?']");
  726. //console.log("found " + nails.length + " LQ nails");
  727. for(let i = 0; i < nails.length; i++)
  728. nails[i].src = nails[i].src.split("?")[0];
  729. }, 200);
  730. }
  731. }
  732.  
  733. function URLChanged()
  734. {
  735. if(AutoExpandChannelVidContainers)
  736. AutoExpandContainers();
  737.  
  738. if(HQTN)
  739. SwapSubsVidThumbnailsHQ();
  740. }
  741. function CleanCSSValue(val)
  742. {
  743. val = val.trim();
  744.  
  745. //if only numbers...
  746. if(/^\d+$/.test(val))
  747. val += "px"; //...add px
  748.  
  749. return val;
  750. }
  751. function CleanNumber(val)
  752. {
  753. val = parseFloat(val);
  754.  
  755. return val;
  756. }
  757.  
  758. function addGlobalStyle(css)
  759. {
  760. var head, style;
  761. head = document.getElementsByTagName('head')[0];
  762. if (!head) { return; }
  763. style = document.createElement('style');
  764. style.type = 'text/css';
  765. style.innerHTML = css;
  766. head.appendChild(style);
  767. }
  768.  
  769. })();

QingJ © 2025

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