From 6607e3c5aff17dcbef342fb4673259d2d77f68d4 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Mon, 21 Mar 2022 17:59:18 +0100 Subject: [PATCH] feat: add chrome extension --- chrome/assets/js/script.js | 87 ++++++++++++++++++++++++++++++ chrome/manifest.json | 13 +++++ disneyplus_pip.js => userscript.js | 0 3 files changed, 100 insertions(+) create mode 100644 chrome/assets/js/script.js create mode 100644 chrome/manifest.json rename disneyplus_pip.js => userscript.js (100%) diff --git a/chrome/assets/js/script.js b/chrome/assets/js/script.js new file mode 100644 index 0000000..d41189c --- /dev/null +++ b/chrome/assets/js/script.js @@ -0,0 +1,87 @@ +class PIPController { + constructor() { + this.element = null; + + const config = { + childList: true, + subtree: true + } + + const mutationTimeout = 500; + let mutating = null; + let prevHref = null; + + // SPA navigation handler + this.observer = new MutationObserver(() => { + if (this.isPlayerPage()) { + clearTimeout(mutating); + + // Wait for mutation to stop + mutating = setTimeout(() => { + // Attempt to inject PIP controls + if (prevHref !== window.location.href) { + this.injectPipControls(); + prevHref = window.location.href; + } + }, mutationTimeout); + } else { + prevHref = window.location.href; + } + }); + + this.observer.observe(window.document.body, config); + } + + // Returns true if the page is /video/ + isPlayerPage() { + const url = new URL(window.location); + const pathname = url.pathname.split("/"); + + return pathname[1] === "video" ? true : false; + } + + // Enter/exit PIP mode + togglePictureInPicture() { + if (document.pictureInPictureElement) { + document.exitPictureInPicture(); + } else { + if (document.pictureInPictureEnabled) { + this.element.requestPictureInPicture(); + } + } + } + + // Generate the PIP toggle button from existing SVG icons on Disney+ + createPipButton() { + const type = "button"; + + const pip = document.createElement(type); + pip.type = type; + pip.role = type; + pip.tabindex = "0"; + pip.classList = "control-icon-btn fullscreen-icon"; + + pip.innerHTML = `
`; + + pip.addEventListener("click", () => this.togglePictureInPicture()); + + return pip; + } + + // Insert the PIP toggle button and enable PIP on the video element + injectPipControls() { + this.element = document.getElementsByTagName("video")[0]; + + if (!this.isPlayerPage() || !this.element) { + return false; + } + + this.element.disablePictureInPicture = false; + + // Inject the PIP toggle button + const target = document.querySelector("#hudson-wrapper .controls__right"); + target.insertAdjacentElement("afterbegin", this.createPipButton()); + } +} + +window.addEventListener("load", () => new PIPController(), { once: true }); \ No newline at end of file diff --git a/chrome/manifest.json b/chrome/manifest.json new file mode 100644 index 0000000..7823956 --- /dev/null +++ b/chrome/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "Disney+ PIP", + "description": "Adds Picture-in-Picture (PIP) support for Disney+", + "version": "1.0", + "manifest_version": 3, + "permissions": [ + "activeTab" + ], + "content_scripts": [{ + "matches": ["https://*.disneyplus.com/*"], + "js": ["assets/js/script.js"] + }] +} \ No newline at end of file diff --git a/disneyplus_pip.js b/userscript.js similarity index 100% rename from disneyplus_pip.js rename to userscript.js