From 4932fc6f45f58f4dbd90d24377336ff100999f17 Mon Sep 17 00:00:00 2001 From: Ajay Ramachandran Date: Wed, 9 Jun 2021 14:26:20 -0400 Subject: [PATCH] Fix skipping on Firefox for Android Resolves https://github.com/ajayyy/SponsorBlock/issues/659 and https://github.com/ajayyy/SponsorBlock/issues/588 --- README.md | 2 ++ package.json | 2 ++ src/content.ts | 82 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 0a404c57..48398c67 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,8 @@ The result is in `dist`. This can be loaded as an unpacked extension Run `npm run dev` to run the extension using a clean browser profile with hot reloading. Use `npm run dev:firefox` for Firefox. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands). Known chromium bug: Extension is not loaded properly on first start. Visit `chrome://extensions/` and reload the extension. +For Firefox for Android, use `npm run dev:firefox-android --adb-device `. See the [Firefox documentation](https://extensionworkshop.com/documentation/develop/developing-extensions-for-firefox-for-android/#debug-your-extension) for more information. + ### Attribution Generation If you contribute and add a dependency, update the attribution file using the following steps: diff --git a/package.json b/package.json index 36161a3d..c127356f 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "web-run": "npm run web-run:chrome", "web-sign": "web-ext sign -s dist", "web-run:firefox": "cd dist && web-ext run --start-url https://addons.mozilla.org/firefox/addon/ublock-origin/", + "web-run:firefox-android": "cd dist && web-ext run -t firefox-android --firefox-apk org.mozilla.fenix", "web-run:chrome": "cd dist && web-ext run --start-url https://chrome.google.com/webstore/detail/ublock-origin/cjpalhdlnbpafiamejdnhcphjbkeiagm -t chromium", "build": "npm run build:chrome", "build:chrome": "webpack --env.browser=chrome --config webpack/webpack.prod.js", @@ -50,6 +51,7 @@ "build:watch:firefox": "webpack --env.browser=firefox --config webpack/webpack.dev.js --watch", "dev": "npm run build:dev && concurrently \"npm run web-run\" \"npm run build:watch\"", "dev:firefox": "npm run build:dev:firefox && concurrently \"npm run web-run:firefox\" \"npm run build:watch:firefox\"", + "dev:firefox-android": "npm run build:dev:firefox && concurrently \"npm run web-run:firefox-android\" \"npm run build:watch:firefox\"", "clean": "rimraf dist", "test": "npx jest", "lint": "eslint src", diff --git a/src/content.ts b/src/content.ts index 26318c45..4822eff1 100644 --- a/src/content.ts +++ b/src/content.ts @@ -42,6 +42,7 @@ let sponsorSkipped: boolean[] = []; //the video let video: HTMLVideoElement; +let videoMutationObserver: MutationObserver = null; // List of videos that have had event listeners added to them const videoRootsWithEventListeners: HTMLDivElement[] = []; @@ -51,9 +52,6 @@ let onMobileYouTube; //the video id of the last preview bar update let lastPreviewBarUpdate; -//whether the duration listener listening for the duration changes of the video has been setup yet -let durationListenerSetUp = false; - // Is the video currently being switched let switchingVideos = null; @@ -477,48 +475,54 @@ function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boole } } -async function sponsorsLookup(id: string) { - video = document.querySelector('video') // Youtube video player - //there is no video here - if (video == null) { - setTimeout(() => sponsorsLookup(id), 100); - return; - } +function setupMobileVideoMutationListener() { + const videoContainer = document.querySelector(".html5-video-container"); + if (!videoContainer || videoMutationObserver !== null) return; - addHotkeyListener(); + videoMutationObserver = new MutationObserver(() => { + const newVideo = document.querySelector('video'); + if (newVideo && newVideo !== video) { + video = newVideo; + setupVideoListeners(); + } + }); - if (!durationListenerSetUp) { - durationListenerSetUp = true; + videoMutationObserver.observe(videoContainer, { + attributes: true, + childList: true, + subtree: true + }); +} - //wait until it is loaded - video.addEventListener('durationchange', durationChangeListener); - } +function setupVideoListeners() { + //wait until it is loaded + video.addEventListener('durationchange', durationChangeListener); - if (!seekListenerSetUp && !Config.config.disableSkipping) { - seekListenerSetUp = true; + + if (!Config.config.disableSkipping) { switchingVideos = false; video.addEventListener('play', () => { switchingVideos = false; - + // If it is not the first event, then the only way to get to 0 is if there is a seek event // This check makes sure that changing the video resolution doesn't cause the extension to think it // gone back to the begining if (!firstEvent && video.currentTime === 0) return; firstEvent = false; - + // Check if an ad is playing updateAdFlag(); - + // Make sure it doesn't get double called with the playing event if (Math.abs(lastCheckVideoTime - video.currentTime) > 0.3 || (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)) { lastCheckTime = Date.now(); lastCheckVideoTime = video.currentTime; - + startSponsorSchedule(); } - + }); video.addEventListener('playing', () => { // Make sure it doesn't get double called with the play event @@ -526,7 +530,7 @@ async function sponsorsLookup(id: string) { || (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)) { lastCheckTime = Date.now(); lastCheckVideoTime = video.currentTime; - + startSponsorSchedule(); } }); @@ -535,7 +539,7 @@ async function sponsorsLookup(id: string) { // Reset lastCheckVideoTime lastCheckTime = Date.now(); lastCheckVideoTime = video.currentTime; - + startSponsorSchedule(); } }); @@ -546,12 +550,30 @@ async function sponsorsLookup(id: string) { // Reset lastCheckVideoTime lastCheckVideoTime = -1; lastCheckTime = 0; - + cancelSponsorSchedule(); }); - + startSponsorSchedule(); } +} + +async function sponsorsLookup(id: string) { + video = document.querySelector('video'); // Youtube video player + //there is no video here + if (video == null) { + setTimeout(() => sponsorsLookup(id), 100); + return; + } + + if (onMobileYouTube) setupMobileVideoMutationListener(); + + addHotkeyListener(); + + if (!seekListenerSetUp && !Config.config.disableSkipping) { + seekListenerSetUp = true; + setupVideoListeners(); + } //check database for sponsor times //made true once a setTimeout has been created to try again after a server error @@ -589,7 +611,7 @@ async function sponsorsLookup(id: string) { } } - const oldSegments = sponsorTimes; + const oldSegments = sponsorTimes || []; sponsorTimes = recievedSegments; // Hide all submissions smaller than the minimum duration @@ -1099,7 +1121,7 @@ async function createButtons(): Promise { /** Creates any missing buttons on the player and updates their visiblity. */ async function updateVisibilityOfPlayerControlsButton(): Promise { // Not on a proper video yet - if (!sponsorVideoID) return; + if (!sponsorVideoID || onMobileYouTube) return; await createButtons(); @@ -1116,7 +1138,7 @@ async function updateVisibilityOfPlayerControlsButton(): Promise { /** Updates the visibility of buttons on the player related to creating segments. */ function updateEditButtonsOnPlayer(): void { // Don't try to update the buttons if we aren't on a YouTube video page - if (!sponsorVideoID) return; + if (!sponsorVideoID || onMobileYouTube) return; const buttonsEnabled = !Config.config.hideVideoPlayerControls && !onInvidious;