YouTube: Force Single Column Mode

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

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name        YouTube: Force Single Column Mode
// @namespace   UserScripts
// @match       https://www.youtube.com/*
// @grant       none
// @unwrap
// @inject-into page
// @version     1.1.1
// @author      CY Fung
// @description 8/17/2023, 1:51:20 AM
// @license MIT
// ==/UserScript==

(() => {

  const VIDEO_WH_RATIO_REFERENCE = 16 / 9; // 1.78
  const ENABLE_WHEN_CONTENT_OCCUPY_MORE_THAN = 0.2 // 20% or more of other content can be displayed in your browser

  const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);


  let ytPreferredMode = null; // true for two-columns_; min-width of side panel = 380px

  function getShouldSingleColumn() {
    if (ytPreferredMode === false) return true;
    const { clientHeight, clientWidth } = document.documentElement;
    if (clientHeight > clientWidth) {
      let referenceVideoHeight = clientWidth / (VIDEO_WH_RATIO_REFERENCE);
      let belowSpace = clientHeight - referenceVideoHeight;
      if (belowSpace > -1e-3) {
        if (belowSpace - ENABLE_WHEN_CONTENT_OCCUPY_MORE_THAN * clientHeight >= -1e-3) {
          return true;
        }
      }
    }
    return false;
  }

  let isShouldSingleColumn = null;

  const Promise = (async () => { })().constructor;
  const { setInterval, clearInterval } = window;

  if (location.pathname.indexOf('live_chat') >= 0) return;

  let resizeBusy = false;
  let resizeQuene = Promise.resolve();


  function setIsTwoColumns_(ywf) {
    if (!ywf) return;
    const cnt = insp(ywf);
    const pnt = (cnt.ytdWatchBehavior ? cnt : ywf.ytdWatchBehavior ? ywf : 0) || 0;

    if (typeof isShouldSingleColumn === 'boolean' && 'isTwoColumns_' in (pnt.ytdWatchBehavior || 0)) {
      pnt.ytdWatchBehavior.isTwoColumns_ = !isShouldSingleColumn;
    }

  }
  let cid = setInterval.call(window, () => {
    const ywf = document.querySelector('ytd-watch-flexy');
    if (ywf && isShouldSingleColumn === null) {
      isShouldSingleColumn = getShouldSingleColumn();
      Window.prototype.addEventListener.call(window, 'resize', function () {
        if (resizeBusy) return;
        resizeBusy = true;
        const ywf = document.querySelector('ytd-watch-flexy');
        resizeQuene = resizeQuene.then(() => {
          const p = isShouldSingleColumn;
          isShouldSingleColumn = getShouldSingleColumn();
          resizeBusy = false;
          return isShouldSingleColumn !== p
        }).then(k => {
          if (k) setIsTwoColumns_(ywf);
        });
      }, { capture: false, passive: true });

      if (isShouldSingleColumn) {
        ywf.removeAttribute('is-two-columns_');
      } else {
        ywf.setAttribute('is-two-columns_', '');
      }

      const cnt = insp(ywf);
      const pnt = (cnt.ytdWatchBehavior ? cnt : ywf.ytdWatchBehavior ? ywf : 0) || 0;

      if (typeof cnt.updateIsTwoColumnsFromBinding === 'function' && ('isTwoColumns_' in (pnt.ytdWatchBehavior || 0))) {

        cnt.updateIsTwoColumnsFromBinding = function (a) {
          let b = null;
          try {
            b = a.detail.value;
          } catch (e) { }
          if (typeof b === 'boolean') ytPreferredMode = b;
        };

      }
      Promise.resolve(ywf).then(setIsTwoColumns_)
      clearInterval.call(window, cid);
    }

  }, 1);

})();