dbfdg PK !<#erع--$data/picture_in_picture_overrides.js/* 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"; /* globals browser */ let AVAILABLE_PIP_OVERRIDES; { // See PictureInPictureControls.sys.mjs for these values. // eslint-disable-next-line no-unused-vars const TOGGLE_POLICIES = browser.pictureInPictureChild.getPolicies(); const KEYBOARD_CONTROLS = browser.pictureInPictureChild.getKeyboardControls(); AVAILABLE_PIP_OVERRIDES = { // The keys of this object are match patterns for URLs, as documented in // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns // // Example: // const KEYBOARD_CONTROLS = browser.pictureInPictureChild.getKeyboardControls(); // // // "https://*.youtube.com/*": { // policy: TOGGLE_POLICIES.THREE_QUARTERS, // disabledKeyboardControls: KEYBOARD_CONTROLS.PLAY_PAUSE | KEYBOARD_CONTROLS.VOLUME, // }, // "https://*.twitch.tv/mikeconley_dot_ca/*": { // policy: TOGGLE_POLICIES.TOP, // disabledKeyboardControls: KEYBOARD_CONTROLS.ALL, // }, tests: { // FOR TESTS ONLY! "https://mochitest.youtube.com/*browser/browser/extensions/pictureinpicture/tests/browser/test-mock-wrapper.html": { videoWrapperScriptPath: "video-wrappers/mock-wrapper.js", }, "https://mochitest.youtube.com/*browser/browser/extensions/pictureinpicture/tests/browser/test-toggle-visibility.html": { videoWrapperScriptPath: "video-wrappers/mock-wrapper.js", }, }, abcnews: { "https://*.abcnews.go.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, airmozilla: { "https://*.mozilla.hosted.panopto.com/*": { videoWrapperScriptPath: "video-wrappers/airmozilla.js", }, }, aol: { "https://*.aol.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, arte: { "https://*.arte.tv/*": { videoWrapperScriptPath: "video-wrappers/arte.js", }, }, bbc: { "https://*.bbc.com/*": { videoWrapperScriptPath: "video-wrappers/bbc.js", }, "https://*.bbc.co.uk/*": { videoWrapperScriptPath: "video-wrappers/bbc.js", }, }, brightcove: { "https://*.brightcove.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, canalplus: { "https://*.canalplus.com/live/*": { videoWrapperScriptPath: "video-wrappers/canalplus.js", disabledKeyboardControls: KEYBOARD_CONTROLS.LIVE_SEEK, }, "https://*.canalplus.com/*": { videoWrapperScriptPath: "video-wrappers/canalplus.js", }, }, cbc: { "https://*.cbc.ca/*": { videoWrapperScriptPath: "video-wrappers/cbc.js", }, }, cnbc: { "https://*.cnbc.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, cpac: { "https://*.cpac.ca/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, cspan: { "https://*.c-span.org/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, dailymotion: { "https://*.dailymotion.com/*": { videoWrapperScriptPath: "video-wrappers/dailymotion.js", }, }, disneyplus: { "https://*.disneyplus.com/*": { videoWrapperScriptPath: "video-wrappers/disneyplus.js", }, }, edx: { "https://*.edx.org/*": { videoWrapperScriptPath: "video-wrappers/edx.js", }, }, fandom: { "https://*.fandom.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, fastcompany: { "https://*.fastcompany.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, frontendMasters: { "https://*.frontendmasters.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, funimation: { "https://*.funimation.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, fuse: { "https://*.fuse.tv/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, hbomax: { "https://play.hbomax.com/page/*": { policy: TOGGLE_POLICIES.HIDDEN }, "https://play.hbomax.com/player/*": { videoWrapperScriptPath: "video-wrappers/hbomax.js", }, }, hotstar: { "https://*.hotstar.com/*": { videoWrapperScriptPath: "video-wrappers/hotstar.js", }, }, hulu: { "https://www.hulu.com/watch/*": { videoWrapperScriptPath: "video-wrappers/hulu.js", }, }, imdb: { "https://*.imdb.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, indpendentuk: { "https://*.independent.co.uk/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, indy100: { "https://*.indy100.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, instagram: { "https://www.instagram.com/*": { policy: TOGGLE_POLICIES.ONE_QUARTER }, }, internetArchive: { "https://*.archive.org/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, laracasts: { "https://*.laracasts.com/*": { policy: TOGGLE_POLICIES.ONE_QUARTER }, }, msn: { "https://*.msn.com/*": { visibilityThreshold: 0.7, }, }, msnbc: { "https://*.msnbc.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, mxplayer: { "https://*.mxplayer.in/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, nbcnews: { "https://*.nbcnews.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, nbcUniversal: { "https://*.nbcuni.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, nebula: { "https://*.nebula.app/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, netflix: { "https://*.netflix.com/*": { videoWrapperScriptPath: "video-wrappers/netflix.js", }, "https://*.netflix.com/browse*": { policy: TOGGLE_POLICIES.HIDDEN }, "https://*.netflix.com/latest*": { policy: TOGGLE_POLICIES.HIDDEN }, "https://*.netflix.com/Kids*": { policy: TOGGLE_POLICIES.HIDDEN }, "https://*.netflix.com/title*": { policy: TOGGLE_POLICIES.HIDDEN }, "https://*.netflix.com/notification*": { policy: TOGGLE_POLICIES.HIDDEN }, "https://*.netflix.com/search*": { policy: TOGGLE_POLICIES.HIDDEN }, }, nytimes: { "https://*.nytimes.com/*": { videoWrapperScriptPath: "video-wrappers/nytimes.js", }, }, pbs: { "https://*.pbs.org/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, "https://*.pbskids.org/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, piped: { "https://*.piped.kavin.rocks/*": { videoWrapperScriptPath: "video-wrappers/piped.js", }, "https://*.piped.silkky.cloud/*": { videoWrapperScriptPath: "video-wrappers/piped.js", }, }, primeVideo: { "https://*.primevideo.com/*": { visibilityThreshold: 0.9, videoWrapperScriptPath: "video-wrappers/primeVideo.js", }, "https://*.amazon.com/*": { visibilityThreshold: 0.9, videoWrapperScriptPath: "video-wrappers/primeVideo.js", }, }, radiocanada: { "https://*.ici.radio-canada.ca/*": { videoWrapperScriptPath: "video-wrappers/radiocanada.js", }, }, reddit: { "https://*.reddit.com/*": { policy: TOGGLE_POLICIES.ONE_QUARTER }, }, reuters: { "https://*.reuters.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, sonyliv: { "https://*.sonyliv.com/*": { videoWrapperScriptPath: "video-wrappers/sonyliv.js", }, }, syfy: { "https://*.syfy.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, ted: { "https://*.ted.com/*": { showHiddenTextTracks: true, }, }, time: { "https://*.time.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, timvision: { "https://*.timvision.it/TV/*": { videoWrapperScriptPath: "video-wrappers/canalplus.js", disabledKeyboardControls: KEYBOARD_CONTROLS.LIVE_SEEK, }, "https://*.timvision.it/*": { videoWrapperScriptPath: "video-wrappers/canalplus.js", }, }, tubi: { "https://*.tubitv.com/live*": { videoWrapperScriptPath: "video-wrappers/tubilive.js", }, "https://*.tubitv.com/movies*": { videoWrapperScriptPath: "video-wrappers/tubi.js", }, "https://*.tubitv.com/tv-shows*": { videoWrapperScriptPath: "video-wrappers/tubi.js", }, }, twitch: { "https://*.twitch.tv/*": { videoWrapperScriptPath: "video-wrappers/twitch.js", policy: TOGGLE_POLICIES.ONE_QUARTER, disabledKeyboardControls: KEYBOARD_CONTROLS.LIVE_SEEK, }, "https://*.twitch.tech/*": { videoWrapperScriptPath: "video-wrappers/twitch.js", policy: TOGGLE_POLICIES.ONE_QUARTER, disabledKeyboardControls: KEYBOARD_CONTROLS.LIVE_SEEK, }, "https://*.twitch.a2z.com/*": { videoWrapperScriptPath: "video-wrappers/twitch.js", policy: TOGGLE_POLICIES.ONE_QUARTER, disabledKeyboardControls: KEYBOARD_CONTROLS.LIVE_SEEK, }, }, udemy: { "https://*.udemy.com/*": { videoWrapperScriptPath: "video-wrappers/udemy.js", policy: TOGGLE_POLICIES.ONE_QUARTER, }, }, univision: { "https://*.univision.com/*": { videoWrapperScriptPath: "video-wrappers/jwplayerWrapper.js", }, }, viki: { "https://*.viki.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, vimeo: { "https://*.vimeo.com/*": { showHiddenTextTracks: true, }, }, voot: { "https://*.voot.com/*": { videoWrapperScriptPath: "video-wrappers/voot.js", }, }, wired: { "https://*.wired.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, yahoo: { "https://*.s.yimg.com/*": { videoWrapperScriptPath: "video-wrappers/videojsWrapper.js", }, }, youtube: { /** * The threshold of 0.7 is so that users can click on the "Skip Ads" * button on the YouTube site player without accidentally triggering * PiP. */ "https://*.youtube.com/*": { visibilityThreshold: 0.7, videoWrapperScriptPath: "video-wrappers/youtube.js", }, "https://*.youtube-nocookie.com/*": { visibilityThreshold: 0.9, videoWrapperScriptPath: "video-wrappers/youtube.js", }, }, washingtonpost: { "https://*.washingtonpost.com/*": { videoWrapperScriptPath: "video-wrappers/washingtonpost.js", }, }, }; } PK ! { const prefName = `${extensionPrefNameBase}${name}`; const callback = () => { fire.async(name).catch(() => {}); // ignore Message Manager disconnects }; Services.prefs.addObserver(prefName, callback); return () => { Services.prefs.removeObserver(prefName, callback); }; }, }).api(), /** * Calls `Services.prefs.getBoolPref` to get a preference * * @param {string} name The name of the preference to get; will be prefixed with this extension's branch * @returns {boolean|undefined} the preference, or undefined */ async getPref(name) { try { return Services.prefs.getBoolPref( `${extensionPrefNameBase}${name}` ); } catch (_) { return undefined; } }, /** * Calls `Services.prefs.setBoolPref` to set a preference * * @param {string} name the name of the preference to set; will be prefixed with this extension's branch * @param {boolean} value the bool value to save in the pref */ async setPref(name, value) { Services.prefs.setBoolPref(`${extensionPrefNameBase}${name}`, value); }, }, }; } }; PK !<cYY(experiment-apis/aboutConfigPipPrefs.json[ { "namespace": "aboutConfigPipPrefs", "description": "experimental API extension to allow access to about:config preferences", "events": [ { "name": "onPrefChange", "type": "function", "parameters": [ { "name": "name", "type": "string", "description": "The preference which changed" } ], "extraParameters": [ { "name": "name", "type": "string", "description": "The preference to monitor" } ] } ], "functions": [ { "name": "getPref", "type": "function", "description": "Get a preference's value", "parameters": [ { "name": "name", "type": "string", "description": "The preference name" } ], "async": true }, { "name": "setPref", "type": "function", "description": "Set a preference's value", "parameters": [ { "name": "name", "type": "string", "description": "The preference name" }, { "name": "value", "type": "boolean", "description": "The new value" } ], "async": true } ] } ] PK ! { if (value === false) { this._enabled = false; } else { if (value === undefined) { browser.aboutConfigPipPrefs.setPref(this.pref, true); } this._enabled = true; } }); } /** * Checks the status of a specified override, and updates the set, `this._prefEnabledOverrides`, accordingly * * @param {string} id the id of the specific override contained in `this._availableOverrides` * @param {string} pref the specific preference to check, in the form `disabled_picture_in_picture_overrides.${id}` */ async _checkSpecificOverridePref(id, pref) { const isDisabled = await browser.aboutConfigPipPrefs.getPref(pref); if (isDisabled === true) { this._prefEnabledOverrides.delete(id); } else { this._prefEnabledOverrides.add(id); } } /** * The function that `run.js` calls to begin checking for changes to the PiP overrides */ bootup() { const checkGlobal = async () => { await this._checkGlobalPref(); this._onAvailableOverridesChanged(); }; browser.aboutConfigPipPrefs.onPrefChange.addListener( checkGlobal, this.pref ); const bootupPrefCheckPromises = [this._checkGlobalPref()]; for (const id of Object.keys(this._availableOverrides)) { const pref = `disabled_picture_in_picture_overrides.${id}`; const checkSingle = async () => { await this._checkSpecificOverridePref(id, pref); this._onAvailableOverridesChanged(); }; browser.aboutConfigPipPrefs.onPrefChange.addListener(checkSingle, pref); bootupPrefCheckPromises.push(this._checkSpecificOverridePref(id, pref)); } Promise.all(bootupPrefCheckPromises).then(() => { this._onAvailableOverridesChanged(); }); } /** * Sets pictureInPictureParent's overrides */ async _onAvailableOverridesChanged() { const policies = await this.policies; let enabledOverrides = {}; for (const [id, override] of Object.entries(this._availableOverrides)) { const enabled = this._enabled && this._prefEnabledOverrides.has(id); for (const [url, policy] of Object.entries(override)) { enabledOverrides[url] = enabled ? policy : policies.DEFAULT; } } browser.pictureInPictureParent.setOverrides(enabledOverrides); } } PK !<. manifest.json{ "manifest_version": 2, "name": "Picture-In-Picture", "description": "Fixes for web compatibility with Picture-in-Picture", "version": "1.0.0", "browser_specific_settings": { "gecko": { "id": "pictureinpicture@mozilla.org", "strict_min_version": "88.0a1" } }, "experiment_apis": { "aboutConfigPipPrefs": { "schema": "experiment-apis/aboutConfigPipPrefs.json", "parent": { "scopes": ["addon_parent"], "script": "experiment-apis/aboutConfigPipPrefs.js", "paths": [["aboutConfigPipPrefs"]] } }, "pictureInPictureChild": { "schema": "experiment-apis/pictureInPicture.json", "child": { "scopes": ["addon_child"], "script": "experiment-apis/pictureInPicture.js", "paths": [["pictureInPictureChild"]] } }, "pictureInPictureParent": { "schema": "experiment-apis/pictureInPicture.json", "parent": { "scopes": ["addon_parent"], "script": "experiment-apis/pictureInPicture.js", "paths": [["pictureInPictureParent"]] } } }, "background": { "scripts": [ "data/picture_in_picture_overrides.js", "lib/picture_in_picture_overrides.js", "run.js" ] } } PK !<2run.js/* 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"; /* globals AVAILABLE_PIP_OVERRIDES, PictureInPictureOverrides */ const pipOverrides = new PictureInPictureOverrides(AVAILABLE_PIP_OVERRIDES); pipOverrides.bootup(); PK !<+aavideo-wrappers/airmozilla.js/* 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"; class PictureInPictureVideoWrapper { play(video) { let playPauseButton = document.querySelector( "#transportControls #playButton" ); if (video.paused) { playPauseButton?.click(); } } pause(video) { let playPauseButton = document.querySelector( "#transportControls #playButton" ); if (!video.paused) { playPauseButton?.click(); } } setMuted(video, shouldMute) { let muteButton = document.querySelector("#transportControls #muteButton"); if (video.muted !== shouldMute && muteButton) { muteButton.click(); } } setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document.querySelector("#absoluteControls"); if (container) { updateCaptionsFunction(""); const callback = function () { let text = container?.querySelector("#overlayCaption").innerText; if (!text) { updateCaptionsFunction(""); return; } updateCaptionsFunction(text); }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<--video-wrappers/arte.js/* 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"; class PictureInPictureVideoWrapper { setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document.querySelector(".avp-captions"); if (container) { updateCaptionsFunction(""); const callback = function () { let textNodeList = container.querySelectorAll(".avp-captions-line"); if (!textNodeList.length) { updateCaptionsFunction(""); return; } updateCaptionsFunction( Array.from(textNodeList, x => x.textContent).join("\n") ); }; callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK ! x.innerText).join("\n") ); }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<10video-wrappers/disneyplus.js/* 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"; class PictureInPictureVideoWrapper { setCaptionContainerObserver(video, updateCaptionsFunction) { // Handle Disney+ (US) let container = document.querySelector(".dss-hls-subtitle-overlay"); if (container) { const callback = () => { let textNodeList = container.querySelectorAll( ".dss-subtitle-renderer-line" ); if (!textNodeList.length) { updateCaptionsFunction(""); return; } updateCaptionsFunction( Array.from(textNodeList, x => x.textContent).join("\n") ); }; // immediately invoke the callback function to add subtitles to the PiP window callback(); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); return; } // Handle Disney+ (non US version) container = document.querySelector(".shaka-text-container"); if (container) { updateCaptionsFunction(""); const callback = function () { let textNodeList = container?.querySelectorAll("span"); if (!textNodeList) { updateCaptionsFunction(""); return; } updateCaptionsFunction( Array.from(textNodeList, x => x.textContent).join("\n") ); }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<{video-wrappers/edx.js/* 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"; class PictureInPictureVideoWrapper { setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document.querySelector(".video-wrapper"); if (container) { updateCaptionsFunction(""); const callback = function () { let text = container.querySelector( ".closed-captions.is-visible" )?.innerText; updateCaptionsFunction(text); }; callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: true, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<Dvideo-wrappers/hbomax.js/* 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"; class PictureInPictureVideoWrapper { setVolume(video, volume) { video.volume = volume; } isMuted(video) { return video.volume === 0; } setMuted(video, shouldMute) { if (shouldMute) { this.setVolume(video, 0); } else { this.setVolume(video, 1); } } setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document.querySelector( '[data-testid="CueBoxContainer"]' ).parentElement; if (container) { updateCaptionsFunction(""); const callback = function () { let text = container.querySelector( '[data-testid="CueBoxContainer"]' )?.innerText; updateCaptionsFunction(text); }; callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK ! x.textContent).join("\n") ); }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<մuuvideo-wrappers/hulu.js/* 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"; class PictureInPictureVideoWrapper { constructor(video) { this.player = video.wrappedJSObject.__HuluDashPlayer__; } play() { this.player.play(); } pause() { this.player.pause(); } isMuted(video) { return video.volume === 0; } setMuted(video, shouldMute) { let muteButton = document.querySelector(".VolumeControl > div"); if (this.isMuted(video) !== shouldMute) { muteButton.click(); } } setCurrentTime(video, position) { this.player.currentTime = position; } setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document.querySelector(".ClosedCaption"); if (container) { updateCaptionsFunction(""); const callback = function () { // This will get the subtitles for both live and regular playback videos // and combine them to display. liveVideoText should be an empty string // when the video is regular playback and vice versa. If both // liveVideoText and regularVideoText are non empty strings, which // doesn't seem to be the case, they will both show. let liveVideoText = Array.from( container.querySelectorAll( "#inband-closed-caption > div > div > div" ), x => x.textContent.trim() ) .filter(String) .join("\n"); let regularVideoText = container.querySelector(".CaptionBox").innerText; updateCaptionsFunction(liveVideoText + regularVideoText); }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } getDuration() { return this.player.duration; } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<Ӡ;;!video-wrappers/jwplayerWrapper.js/* 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"; // This wrapper supports multiple sites that use JWPlayer class PictureInPictureVideoWrapper { setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document.querySelector(".jw-captions"); if (container) { updateCaptionsFunction(""); const callback = function () { let text = container.innerText; if (!text) { updateCaptionsFunction(""); return; } updateCaptionsFunction(text); }; // immediately invoke the callback function to add subtitles to the PiP window callback(); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<video-wrappers/mock-wrapper.js/* 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"; class PictureInPictureVideoWrapper { play() { let playPauseButton = document.querySelector("#player .play-pause-button"); playPauseButton.click(); } pause() { let invalidSelector = "#player .pause-button"; let playPauseButton = document.querySelector(invalidSelector); playPauseButton.click(); } setMuted(video, shouldMute) { let muteButton = document.querySelector("#player .mute-button"); if (video.muted !== shouldMute && muteButton) { muteButton.click(); } else { video.muted = shouldMute; } } shouldHideToggle() { let video = document.getElementById("mock-video-controls"); return !!video.classList.contains("mock-preview-video"); } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK ! x.textContent).join("\n") ); }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK ! { video.play(); }); } /** * Seeking large amounts of time can cause the video readyState to * HAVE_METADATA (1) and it will throw an error when trying to play the video. * To combat this, after seeking we check if the readyState changed and if so, * we will play to video to "load" the video at the new time and then play or * pause the video depending on if the video was playing before we seeked. * * @param {HTMLVideoElement} video * The original video element * @param {number} position * The new time to set the video to * @param {boolean} wasPlaying * True if the video was playing before seeking else false */ setCurrentTime(video, position, wasPlaying) { if (wasPlaying === undefined) { this.wasPlaying = !video.paused; } video.currentTime = position; if (video.readyState < video.HAVE_CURRENT_DATA) { video .play() .then(() => { if (!wasPlaying) { video.pause(); } }) .catch(() => { if (wasPlaying) { this.play(video); } }); } } setCaptionContainerObserver(video, updateCaptionsFunction) { let container = document?.querySelector("#dv-web-player"); if (container) { updateCaptionsFunction(""); const callback = function (mutationsList) { // eslint-disable-next-line no-unused-vars for (const mutation of mutationsList) { let text; // windows, mac if (container?.querySelector(".atvwebplayersdk-player-container")) { text = container ?.querySelector(".f35bt6a") ?.querySelector(".atvwebplayersdk-captions-text")?.innerText; } else { // linux text = container ?.querySelector(".persistentPanel") ?.querySelector("span")?.innerText; } if (!text) { updateCaptionsFunction(""); return; } updateCaptionsFunction(text); } }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: true, childList: true, subtree: true, }); } } shouldHideToggle(video) { return !!video.classList.contains("tst-video-overlay-player-html5"); } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK ! button" ); if (video.muted !== shouldMute && muteButton) { muteButton.click(); } } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK ! x.textContent).join("\n") ); } }; // immediately invoke the callback function to add subtitles to the PiP window callback([1], null); let captionsObserver = new MutationObserver(callback); captionsObserver.observe(container, { attributes: false, childList: true, subtree: true, }); } } shouldHideToggle(video) { return !!video.closest(".ytd-video-preview"); } setVolume(video, volume) { if (this.player) { this.player.setVolume(volume * 100); } else { video.volume = volume; } } getVolume(video) { if (this.player) { return this.player.getVolume() / 100; } return video.volume; } } this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper; PK !<#erع--$data/picture_in_picture_overrides.jsPK !