tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

bug1956165-www.youtube.com-picture-in-picture-fix.js (2607B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 /**
      8 * Bug 1956165 - Fix picture-in-picture mode on Mobile YouTube
      9 *
     10 * YouTube does not play well with our picture in picture implementation, and
     11 * effectively cancels it. We can work around this conflict with this site patch.
     12 */
     13 
     14 /* globals exportFunction */
     15 
     16 console.info(
     17  "exitFullscreen and window.outerWidth|Height have been overridden for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1956165 for details."
     18 );
     19 
     20 const win = window.wrappedJSObject;
     21 const outerWidthDesc = Object.getOwnPropertyDescriptor(win, "outerWidth");
     22 const outerHeightDesc = Object.getOwnPropertyDescriptor(win, "outerHeight");
     23 const originalOuterWidth = outerWidthDesc.get;
     24 const originalOuterHeight = outerHeightDesc.get;
     25 
     26 // This is the logic YouTube uses to detect the app backgrounding to enter picture in picture mode mode (as of May 28 2025).
     27 
     28 const getRatio = (() => {
     29  let cachedRatio;
     30  return function () {
     31    if (cachedRatio === undefined) {
     32      const cfg = window.wrappedJSObject.ytcfg.get(
     33        "WEB_PLAYER_CONTEXT_CONFIGS"
     34      );
     35      const experiment =
     36        cfg?.WEB_PLAYER_CONTEXT_CONFIG_ID_MWEB_WATCH?.serializedExperimentFlags?.match(
     37          /html5_picture_in_picture_logging_onresize_ratio=(\d+(\.\d+)?)/
     38        )?.[1];
     39      cachedRatio = parseFloat(experiment) || 0.33;
     40    }
     41    return cachedRatio;
     42  };
     43 })();
     44 
     45 const inPipMode = (() => {
     46  let o_ = 0;
     47  return function () {
     48    const l = window.screen.width * window.screen.height;
     49    const M = originalOuterWidth() * originalOuterHeight();
     50    o_ = Math.max(o_, l, M);
     51    return M / o_ < getRatio();
     52  };
     53 })();
     54 
     55 outerWidthDesc.get = exportFunction(function () {
     56  if (inPipMode()) {
     57    return screen.width;
     58  }
     59  return originalOuterWidth();
     60 }, window);
     61 outerHeightDesc.get = exportFunction(() => {
     62  if (inPipMode()) {
     63    return screen.height;
     64  }
     65  return originalOuterHeight();
     66 }, window);
     67 Object.defineProperty(win, "outerWidth", outerWidthDesc);
     68 Object.defineProperty(win, "outerHeight", outerHeightDesc);
     69 
     70 const originalExitFullscreen = win.Document.prototype.exitFullscreen;
     71 
     72 const newExitFullscreen = exportFunction(function () {
     73  if (inPipMode()) {
     74    return undefined;
     75  }
     76  return originalExitFullscreen.apply(this);
     77 }, window);
     78 
     79 Object.defineProperty(win.Document.prototype, "exitFullscreen", {
     80  value: newExitFullscreen,
     81  writable: true,
     82  configurable: true,
     83 });