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 });