YouTube: Force Single Column Mode

8/17/2023, 1:51:20 AM

当前为 2023-08-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name YouTube: Force Single Column Mode
  3. // @namespace UserScripts
  4. // @match https://www.youtube.com/*
  5. // @grant none
  6. // @unwrap
  7. // @inject-into page
  8. // @version 1.1.0
  9. // @author CY Fung
  10. // @description 8/17/2023, 1:51:20 AM
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. (() => {
  15.  
  16. const VIDEO_WH_RATIO_REFERENCE = 16 / 9; // 1.78
  17. const ENABLE_WHEN_CONTENT_OCCUPY_MORE_THAN = 0.2 // 20% or more of other content can be displayed in your browser
  18.  
  19.  
  20. let ytPreferredMode = null; // true for two-columns_; min-width of side panel = 380px
  21.  
  22. function getShouldSingleColumn() {
  23. if (ytPreferredMode === false) return true;
  24. const { clientHeight, clientWidth } = document.documentElement;
  25. if (clientHeight > clientWidth) {
  26. let referenceVideoHeight = clientWidth / (VIDEO_WH_RATIO_REFERENCE);
  27. let belowSpace = clientHeight - referenceVideoHeight;
  28. if (belowSpace > -1e-3) {
  29. if (belowSpace - ENABLE_WHEN_CONTENT_OCCUPY_MORE_THAN * clientHeight >= -1e-3) {
  30. return true;
  31. }
  32. }
  33. }
  34. return false;
  35. }
  36.  
  37. let isShouldSingleColumn = null;
  38.  
  39. const Promise = (async () => { })().constructor;
  40. const { setInterval, clearInterval } = window;
  41.  
  42. if (location.pathname.indexOf('live_chat') >= 0) return;
  43.  
  44. let resizeBusy = false;
  45. let resizeQuene = Promise.resolve();
  46.  
  47.  
  48. function setIsTwoColumns_(ywf) {
  49.  
  50. if (typeof isShouldSingleColumn === 'boolean' && 'isTwoColumns_' in ((ywf || 0).ytdWatchBehavior || 0)) {
  51. ywf.ytdWatchBehavior.isTwoColumns_ = !isShouldSingleColumn;
  52. }
  53.  
  54. }
  55. let cid = setInterval.call(window, () => {
  56. const ywf = document.querySelector('ytd-watch-flexy');
  57. if (ywf && isShouldSingleColumn === null) {
  58. isShouldSingleColumn = getShouldSingleColumn();
  59. Window.prototype.addEventListener.call(window, 'resize', function () {
  60. if (resizeBusy) return;
  61. resizeBusy = true;
  62. const ywf = document.querySelector('ytd-watch-flexy');
  63. resizeQuene = resizeQuene.then(() => {
  64. const p = isShouldSingleColumn;
  65. isShouldSingleColumn = getShouldSingleColumn();
  66. resizeBusy = false;
  67. return isShouldSingleColumn !== p
  68. }).then(k => {
  69. if (k) setIsTwoColumns_(ywf);
  70. });
  71. }, { capture: false, passive: true });
  72.  
  73. if (isShouldSingleColumn) {
  74. ywf.removeAttribute('is-two-columns_');
  75. } else {
  76. ywf.setAttribute('is-two-columns_', '');
  77. }
  78. if (typeof ywf.updateIsTwoColumnsFromBinding === 'function' && ('isTwoColumns_' in (ywf.ytdWatchBehavior || 0))) {
  79.  
  80. ywf.updateIsTwoColumnsFromBinding = function (a) {
  81. let b = null;
  82. try {
  83. b = a.detail.value;
  84. } catch (e) { }
  85. if (typeof b === 'boolean') ytPreferredMode = b;
  86. };
  87.  
  88. }
  89. Promise.resolve(ywf).then(setIsTwoColumns_)
  90. clearInterval.call(window, cid);
  91. }
  92.  
  93. }, 1);
  94.  
  95. })();