Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* Bug 1956165 - Fix picture-in-picture mode on Mobile YouTube
*
* YouTube does not play well with our picture in picture implementation, and
* effectively cancels it. We can work around this conflict with this site patch.
*/
if (!window.__firefoxPiPFix) {
Object.defineProperty(window, "__firefoxPiPFix", {
configurable: false,
value: true,
});
console.info(
"exitFullscreen and window.outerWidth|Height have been overridden for compatibility reasons. See https://bugzilla.mozilla.org/show_bug.cgi?id=1956165 for details."
);
const outerWidthDesc = Object.getOwnPropertyDescriptor(window, "outerWidth");
const outerHeightDesc = Object.getOwnPropertyDescriptor(
window,
"outerHeight"
);
const originalOuterWidth = outerWidthDesc.get;
const originalOuterHeight = outerHeightDesc.get;
// This is the logic YouTube uses to detect the app backgrounding to enter picture in picture mode mode (as of May 28 2025).
const getRatio = (() => {
let cachedRatio;
return function () {
if (cachedRatio === undefined) {
const cfg = window.ytcfg.get("WEB_PLAYER_CONTEXT_CONFIGS");
const experiment =
cfg?.WEB_PLAYER_CONTEXT_CONFIG_ID_MWEB_WATCH?.serializedExperimentFlags?.match(
/html5_picture_in_picture_logging_onresize_ratio=(\d+(\.\d+)?)/
)?.[1];
cachedRatio = parseFloat(experiment) || 0.33;
}
return cachedRatio;
};
})();
const inPipMode = (() => {
let o_ = 0;
return function () {
const l = window.screen.width * window.screen.height;
const M = originalOuterWidth() * originalOuterHeight();
o_ = Math.max(o_, l, M);
return M / o_ < getRatio();
};
})();
outerWidthDesc.get = function () {
if (inPipMode()) {
return screen.width;
}
return originalOuterWidth();
};
outerHeightDesc.get = () => {
if (inPipMode()) {
return screen.height;
}
return originalOuterHeight();
};
Object.defineProperty(window, "outerWidth", outerWidthDesc);
Object.defineProperty(window, "outerHeight", outerHeightDesc);
const originalExitFullscreen = window.Document.prototype.exitFullscreen;
const newExitFullscreen = function () {
if (inPipMode()) {
return undefined;
}
return originalExitFullscreen.apply(this);
};
Object.defineProperty(window.Document.prototype, "exitFullscreen", {
value: newExitFullscreen,
writable: true,
configurable: true,
});
}