%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /snap/firefox/current/usr/lib/firefox/browser/features/
Upload File :
Create Path :
Current File : //snap/firefox/current/usr/lib/firefox/browser/features/pictureinpicture@mozilla.org.xpi

�PK
!<�b���	�	&��
experiment-apis/aboutConfigPipPrefs.jsPK
!<����JJ#��experiment-apis/pictureInPicture.jsPK
!<{�\�-�-$���data/picture_in_picture_overrides.jsPK
!<�c�YY(���Mexperiment-apis/aboutConfigPipPrefs.jsonPK
!<ڷ$<<%��cSexperiment-apis/pictureInPicture.jsonPK
!<�0���#���Ylib/picture_in_picture_overrides.jsPK
!<��.��
��gmanifest.jsonPK
!<���2����lrun.jsPK
!<��B&�����mvideo-wrappers/airmozilla.jsPK
!<�S������tvideo-wrappers/arte.jsPK
!<�������hyvideo-wrappers/bbc.jsPK
!<��Poo��}video-wrappers/canalplus.jsPK
!<@U�EE��'�video-wrappers/cbc.jsPK
!<��wu������video-wrappers/dailymotion.jsPK
!<it����όvideo-wrappers/disneyplus.jsPK
!<������� �video-wrappers/edx.jsPK
!<*N"�**��K�video-wrappers/hbomax.jsPK
!<��]:������video-wrappers/hotstar.jsPK
!<Hb�������video-wrappers/hulu.jsPK
!<�zH��!����video-wrappers/jwplayerWrapper.jsPK
!<����������video-wrappers/mock-wrapper.jsPK
!<�&��



����video-wrappers/netflix.jsPK
!<H;�ދ�����video-wrappers/nytimes.jsPK
!<�8Y++����video-wrappers/piped.jsPK
!<j�B>�����video-wrappers/primeVideo.jsPK
!<t1������video-wrappers/radiocanada.jsPK
!<��g������video-wrappers/sonyliv.jsPK
!<�\��pp����video-wrappers/tubi.jsPK
!<w��@qq����video-wrappers/tubilive.jsPK
!<�'�W����:�video-wrappers/twitch.jsPK
!<_>�����n�video-wrappers/udemy.jsPK
!<^�	-�� ��z�video-wrappers/videojsWrapper.jsPK
!<y�(S����{�video-wrappers/voot.jsPK
!<b�TT ��:�video-wrappers/washingtonpost.jsPK
!<Y�lU�	�	���video-wrappers/youtube.jsPK##�	PK
!<�b���	�	&experiment-apis/aboutConfigPipPrefs.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";

/* global ExtensionAPI, ExtensionCommon, Services, XPCOMUtils */

/**
 * Class extending the ExtensionAPI, ensures we can set/get preferences
 */
this.aboutConfigPipPrefs = class extends ExtensionAPI {
  /**
   * Override ExtensionAPI with PiP override's specific preference API, prefixed by `disabled_picture_in_picture_overrides`
   *
   * @param {ExtensionContext} context the context of an extension
   * @returns {object} returns the necessary API structure required to manage prefs within this extension
   */
  getAPI(context) {
    const EventManager = ExtensionCommon.EventManager;
    const extensionIDBase = context.extension.id.split("@")[0];
    const extensionPrefNameBase = `extensions.${extensionIDBase}.`;

    return {
      aboutConfigPipPrefs: {
        onPrefChange: new EventManager({
          context,
          name: "aboutConfigPipPrefs.onSiteOverridesPrefChange",
          register: (fire, name) => {
            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
!<����JJ#experiment-apis/pictureInPicture.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";

/* global AppConstants, ChromeUtils, ExtensionAPI, Services */

ChromeUtils.defineESModuleGetters(this, {
  KEYBOARD_CONTROLS: "resource://gre/modules/PictureInPictureControls.sys.mjs",
  TOGGLE_POLICIES: "resource://gre/modules/PictureInPictureControls.sys.mjs",
});

const TOGGLE_ENABLED_PREF =
  "media.videocontrols.picture-in-picture.video-toggle.enabled";

/**
 * This API is expected to be running in the parent process.
 */
this.pictureInPictureParent = class extends ExtensionAPI {
  /**
   * Override ExtensionAPI with PiP override's specific API
   * Relays the site overrides to this extension's child process
   *
   * @returns {object} returns the necessary API structure required to manage sharedData in PictureInPictureParent
   */
  getAPI() {
    return {
      pictureInPictureParent: {
        setOverrides(overrides) {
          // The Picture-in-Picture toggle is only implemented for Desktop, so make
          // this a no-op for non-Desktop builds.
          if (AppConstants.platform == "android") {
            return;
          }

          Services.ppmm.sharedData.set(
            "PictureInPicture:SiteOverrides",
            overrides
          );
        },
      },
    };
  }
};

/**
 * This API is expected to be running in a content process - specifically,
 * the WebExtension content process that the background scripts run in. We
 * split these out so that they can return values synchronously to the
 * background scripts.
 */
this.pictureInPictureChild = class extends ExtensionAPI {
  /**
   * Override ExtensionAPI with PiP override's specific API
   * Clone constants into the Picture-in-Picture child process
   *
   * @param {ExtensionContext} context the context of our extension
   * @returns {object} returns the necessary API structure required to get data from PictureInPictureChild
   */
  getAPI(context) {
    return {
      pictureInPictureChild: {
        getKeyboardControls() {
          // The Picture-in-Picture toggle is only implemented for Desktop, so make
          // this return nothing for non-Desktop builds.
          if (AppConstants.platform == "android") {
            return Cu.cloneInto({}, context.cloneScope);
          }

          return Cu.cloneInto(KEYBOARD_CONTROLS, context.cloneScope);
        },
        getPolicies() {
          // The Picture-in-Picture toggle is only implemented for Desktop, so make
          // this return nothing for non-Desktop builds.
          if (AppConstants.platform == "android") {
            return Cu.cloneInto({}, context.cloneScope);
          }

          return Cu.cloneInto(TOGGLE_POLICIES, context.cloneScope);
        },
      },
    };
  }
};
PK
!<{�\�-�-$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/*": {
        policy: TOGGLE_POLICIES.ONE_QUARTER,
        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
!<�c�YY(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
!<ڷ$<<%experiment-apis/pictureInPicture.json[
  {
    "namespace": "pictureInPictureParent",
    "description": "Parent process methods for controlling the Picture-in-Picture feature.",
    "functions": [
      {
        "name": "setOverrides",
        "type": "function",
        "description": "Set Picture-in-Picture toggle position overrides",
        "parameters": [
          {
            "name": "overrides",
            "type": "object",
            "additionalProperties": { "type": "any" },
            "description": "The Picture-in-Picture toggle position overrides to set"
          }
        ]
      }
    ]
  },
  {
    "namespace": "pictureInPictureChild",
    "description": "WebExtension process methods for querying the Picture-in-Picture feature.",
    "functions": [
      {
        "name": "getKeyboardControls",
        "type": "function",
        "description": "Get the Picture-in-Picture keyboard control override constants",
        "parameters": [],
        "returns": {
          "type": "object",
          "properties": {},
          "additionalProperties": { "type": "any" },
          "description": "The Picture-in-Picture keyboard control override constants"
        }
      },
      {
        "name": "getPolicies",
        "type": "function",
        "description": "Get the Picture-in-Picture toggle position override constants",
        "parameters": [],
        "returns": {
          "type": "object",
          "properties": {},
          "additionalProperties": { "type": "any" },
          "description": "The Picture-in-Picture toggle position override constants"
        }
      }
    ]
  }
]
PK
!<�0���#lib/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, module */

/**
 * Picture-in-Picture Overrides
 */
class PictureInPictureOverrides {
  /**
   * Class constructor
   *
   * @param {object} availableOverrides Contains all overrides provided in data/picture_in_picture_overrides.js
   */
  constructor(availableOverrides) {
    this.pref = "enable_picture_in_picture_overrides";
    this._prefEnabledOverrides = new Set();
    this._availableOverrides = availableOverrides;
    this.policies = browser.pictureInPictureChild.getPolicies();
  }

  /**
   * Ensures the "enable_picture_in_picture_overrides" pref is set; if it is undefined, sets the pref to true
   */
  async _checkGlobalPref() {
    await browser.aboutConfigPipPrefs.getPref(this.pref).then(value => {
      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
!<���2��run.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
!<��B&��video-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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<�S���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);

      this.captionsObserver = new MutationObserver(callback);
      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<�����video-wrappers/bbc.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(".p_subtitlesContainer");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector(".p_cueDirUniWrapper")?.innerText;
        updateCaptionsFunction(text);
      };

      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<��Poovideo-wrappers/canalplus.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 {
  isLive() {
    let documentURI = document.documentURI;
    return documentURI.includes("/live/") || documentURI.includes("/TV/");
  }

  getDuration(video) {
    if (this.isLive(video)) {
      return Infinity;
    }
    return video.duration;
  }

  setCaptionContainerObserver(video, updateCaptionsFunction) {
    let container =
      document.querySelector(`[data-testid="playerRoot"]`) ||
      document.querySelector(`[player-root="true"]`);

    if (container) {
      updateCaptionsFunction("");
      const callback = function (mutationsList) {
        // eslint-disable-next-line no-unused-vars
        for (const mutation of mutationsList) {
          let text = container.querySelector(
            ".rxp-texttrack-region"
          )?.innerText;
          if (!text) {
            updateCaptionsFunction("");
            return;
          }

          updateCaptionsFunction(text);
        }
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<@U�EEvideo-wrappers/cbc.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(".video-ui .play-button");
    if (video.paused) {
      playPauseButton?.click();
    }
  }

  pause(video) {
    let playPauseButton = document.querySelector(".video-ui .pause-button");
    if (!video.paused) {
      playPauseButton?.click();
    }
  }

  setMuted(video, shouldMute) {
    let muteButton = document.querySelector(".video-ui .muted-btn");
    if (video.muted !== shouldMute && muteButton) {
      muteButton.click();
    }
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<��wu��video-wrappers/dailymotion.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("#player");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let textNodeList = container
          ?.querySelector(".subtitles")
          ?.querySelectorAll("div");

        if (!textNodeList) {
          updateCaptionsFunction("");
          return;
        }

        updateCaptionsFunction(
          Array.from(textNodeList, x => x.innerText).join("\n")
        );
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<it��video-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();

      this.captionsObserver = new MutationObserver(callback);
      this.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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

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

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: true,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<*N"�**video-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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<��]:��video-wrappers/hotstar.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(".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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<Hb���video-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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }

  getDuration() {
    return this.player.duration;
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<�zH��!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();

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

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
!<�&��



video-wrappers/netflix.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() {
    let netflixPlayerAPI =
      window.wrappedJSObject.netflix.appContext.state.playerApp.getAPI()
        .videoPlayer;
    let sessionId = null;
    for (let id of netflixPlayerAPI.getAllPlayerSessionIds()) {
      if (id.startsWith("watch-")) {
        sessionId = id;
        break;
      }
    }
    this.player = netflixPlayerAPI.getVideoPlayerBySessionId(sessionId);
  }

  /**
   * The Netflix player returns the current time in milliseconds so we convert
   * to seconds before returning.
   *
   * @returns {number} The current time in seconds
   */
  getCurrentTime() {
    return this.player.getCurrentTime() / 1000;
  }

  /**
   * The Netflix player returns the duration in milliseconds so we convert to
   * seconds before returning.
   *
   * @returns {number} The duration in seconds
   */
  getDuration() {
    return this.player.getDuration() / 1000;
  }

  play() {
    this.player.play();
  }

  pause() {
    this.player.pause();
  }

  setCaptionContainerObserver(video, updateCaptionsFunction) {
    let container = document.querySelector(".watch-video");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector(".player-timedtext").innerText;
        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }

  /**
   * Set the current time of the video in milliseconds.
   *
   * @param {HTMLVideoElement} video The original video element
   * @param {number} position The new time in seconds
   */
  setCurrentTime(video, position) {
    this.player.seek(position * 1000);
  }

  setVolume(video, volume) {
    this.player.setVolume(volume);
  }

  getVolume() {
    return this.player.getVolume();
  }

  setMuted(video, shouldMute) {
    this.player.setMuted(shouldMute);
  }

  isMuted() {
    return this.player.isMuted();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<H;�ދ�video-wrappers/nytimes.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(".react-vhs-player");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector(".cueWrap-2P4Ue4VQ")?.innerText;
        if (!text) {
          updateCaptionsFunction("");
          return;
        }

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<�8Y++video-wrappers/piped.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(".player-container");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let textNodeList = container
          .querySelector(".shaka-text-wrapper")
          ?.querySelectorAll('span[style="background-color: black;"]');
        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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<j�B>��video-wrappers/primeVideo.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 {
  /**
   * Playing the video when the readyState is HAVE_METADATA (1) can cause play
   * to fail but it will load the video and trying to play again allows enough
   * time for the second play to successfully play the video.
   *
   * @param {HTMLVideoElement} video
   *  The original video element
   */
  play(video) {
    video.play().catch(() => {
      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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: true,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }

  shouldHideToggle(video) {
    return !!video.classList.contains("tst-video-overlay-player-html5");
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<t1���video-wrappers/radiocanada.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(
      ".rcplayer-btn.rcplayer-smallPlayPauseBtn"
    );
    if (video.paused) {
      playPauseButton.click();
    }
  }

  pause(video) {
    let playPauseButton = document.querySelector(
      ".rcplayer-btn.rcplayer-smallPlayPauseBtn"
    );
    if (!video.paused) {
      playPauseButton.click();
    }
  }

  setMuted(video, shouldMute) {
    let muteButton = document.querySelector(
      ".rcplayer-bouton-with-panel--volume > button"
    );
    if (video.muted !== shouldMute && muteButton) {
      muteButton.click();
    }
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<��g��video-wrappers/sonyliv.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(".player-ui-main-wrapper");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector(
          `.text-track-wrapper:not([style*="display: none"])`
        )?.innerText;
        if (!text) {
          updateCaptionsFunction("");
          return;
        }

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<�\��ppvideo-wrappers/tubi.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(`[data-id="hls"]`);

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container?.querySelector(
          `[data-id="captionsComponent"]:not([style="display: none;"])`
        )?.innerText;

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: true,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<w��@qqvideo-wrappers/tubilive.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 = video.parentElement;

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text =
          container.querySelector(`.tubi-text-track-container`)?.innerText ||
          container.querySelector(`.subtitleWindow`)?.innerText;

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: true,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<�'�W��video-wrappers/twitch.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 {
  isLive() {
    return !document.querySelector(".seekbar-bar");
  }

  getDuration(video) {
    if (this.isLive(video)) {
      return Infinity;
    }
    return video.duration;
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<_>���video-wrappers/udemy.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(
      `[data-purpose="play-button"]`
    );
    if (video.paused) {
      playPauseButton?.click();
    }
  }

  pause(video) {
    let playPauseButton = document.querySelector(
      `[data-purpose="pause-button"]`
    );
    if (!video.paused) {
      playPauseButton?.click();
    }
  }

  setMuted(video, shouldMute) {
    let muteButton = document.querySelector(
      `[data-purpose="volume-control-button"]`
    );
    if (video.muted !== shouldMute && muteButton) {
      muteButton.click();
    }
  }

  setCaptionContainerObserver(video, updateCaptionsFunction) {
    let container = video.parentElement;

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector(
          `[data-purpose="captions-cue-text"]`
        )?.innerText;
        if (!text) {
          updateCaptionsFunction("");
          return;
        }

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: true,
        childList: true,
        subtree: true,
      });
    }
  }
  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<^�	-�� video-wrappers/videojsWrapper.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 video.js player
class PictureInPictureVideoWrapper {
  setCaptionContainerObserver(video, updateCaptionsFunction) {
    let container = document.querySelector(".vjs-text-track-display");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector("div").innerText;
        if (!text) {
          updateCaptionsFunction("");
          return;
        }

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<y�(S��video-wrappers/voot.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(".playkit-container");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let text = container.querySelector(".playkit-subtitles").innerText;
        if (!text) {
          updateCaptionsFunction("");
          return;
        }

        updateCaptionsFunction(text);
      };

      // immediately invoke the callback function to add subtitles to the PiP window
      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }
  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<b�TT video-wrappers/washingtonpost.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(".powa");

    if (container) {
      updateCaptionsFunction("");
      const callback = function () {
        let subtitleElement = container.querySelector(".powa-sub-torpedo");
        if (!subtitleElement?.innerText) {
          updateCaptionsFunction("");
          return;
        }
        let subtitleElementClone = subtitleElement.cloneNode(true);
        let breaks = subtitleElementClone.getElementsByTagName("br");
        for (const element of breaks) {
          element.replaceWith("\n");
        }
        let text = subtitleElementClone.innerText;

        updateCaptionsFunction(text);
      };

      callback([1], null);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }
}

this.PictureInPictureVideoWrapper = PictureInPictureVideoWrapper;
PK
!<Y�lU�	�	video-wrappers/youtube.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) {
    // Use shorts player only if video is from YouTube Shorts.
    let shortsPlayer = video.closest("#shorts-player")?.wrappedJSObject;
    let isYTShorts = !!(video.baseURI.includes("shorts") && shortsPlayer);

    this.player = isYTShorts
      ? shortsPlayer
      : video.closest("#movie_player")?.wrappedJSObject;
  }

  isLive() {
    return !!document.querySelector(".ytp-live");
  }

  setMuted(video, shouldMute) {
    if (this.player) {
      if (shouldMute) {
        this.player.mute();
      } else {
        this.player.unMute();
      }
    } else {
      video.muted = shouldMute;
    }
  }

  getDuration(video) {
    if (this.isLive(video)) {
      return Infinity;
    }
    return video.duration;
  }

  setCaptionContainerObserver(video, updateCaptionsFunction) {
    let container = document.getElementById("ytp-caption-window-container");

    if (container) {
      updateCaptionsFunction("");
      const callback = function (mutationsList) {
        // eslint-disable-next-line no-unused-vars
        for (const mutation of mutationsList) {
          let textNodeList = container
            .querySelector(".captions-text")
            ?.querySelectorAll(".caption-visual-line");
          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);

      this.captionsObserver = new MutationObserver(callback);

      this.captionsObserver.observe(container, {
        attributes: false,
        childList: true,
        subtree: true,
      });
    }
  }

  removeCaptionContainerObserver() {
    this.captionsObserver?.disconnect();
  }

  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##�	

Zerion Mini Shell 1.0