diff --git a/manifest/manifest.json b/manifest/manifest.json index 1b486f92de..04d9c8a91b 100644 --- a/manifest/manifest.json +++ b/manifest/manifest.json @@ -81,7 +81,8 @@ ], "permissions": [ "storage", - "https://sponsor.ajay.app/*" + "https://sponsor.ajay.app/*", + "https://*.youtube.com/*" ], "optional_permissions": [ "*://*/*", diff --git a/maze-utils b/maze-utils index 5945ad4aa1..b3572eaeff 160000 --- a/maze-utils +++ b/maze-utils @@ -1 +1 @@ -Subproject commit 5945ad4aa1a19f8f10164dfb562c8cb22b06d52d +Subproject commit b3572eaeff9235c6d4f8bd8b89540c2c5686b925 diff --git a/src/background.ts b/src/background.ts index 382bfd8968..a915b199df 100644 --- a/src/background.ts +++ b/src/background.ts @@ -13,6 +13,9 @@ window.SB = Config; import Utils from "./utils"; import { getExtensionIdsToImportFrom } from "./utils/crossExtension"; +import { isFirefoxOrSafari } from "./maze-utils"; +import { injectUpdatedScripts } from "./maze-utils/cleanup"; +import { logWarn } from "./utils/logger"; const utils = new Utils({ registerFirefoxContentScript, unregisterFirefoxContentScript @@ -132,6 +135,11 @@ chrome.runtime.onInstalled.addListener(function () { } } }, 1500); + + // Only do this once the old version understands how to clean itself up + if (!isFirefoxOrSafari() && chrome.runtime.getManifest().version !== "5.4.13") { + injectUpdatedScripts().catch(logWarn); + } }); /** diff --git a/src/content.ts b/src/content.ts index 36ff849816..379d28d03d 100644 --- a/src/content.ts +++ b/src/content.ts @@ -46,6 +46,7 @@ import { Tooltip } from "./render/Tooltip"; import { isDeArrowInstalled } from "./utils/crossExtension"; import { runCompatibilityChecks } from "./utils/compatibility"; import { cleanPage } from "./utils/pageCleaner"; +import { addCleanupListener } from "./maze-utils/cleanup"; cleanPage(); @@ -476,6 +477,8 @@ function videoIDChange(): void { } function handleMobileControlsMutations(): void { + if (!chrome.runtime?.id) return; + updateVisibilityOfPlayerControlsButton(); skipButtonControlBar?.updateMobileControls(); @@ -815,18 +818,26 @@ function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boole } } +let setupVideoListenersFirstTime = true; function setupVideoListeners() { //wait until it is loaded getVideo().addEventListener('loadstart', videoOnReadyListener) getVideo().addEventListener('durationchange', durationChangeListener); + if (setupVideoListenersFirstTime) { + addCleanupListener(() => { + getVideo().removeEventListener('loadstart', videoOnReadyListener); + getVideo().removeEventListener('durationchange', durationChangeListener); + }); + } + if (!Config.config.disableSkipping) { switchingVideos = false; let startedWaiting = false; let lastPausedAtZero = true; - getVideo().addEventListener('play', () => { + const playListener = () => { // 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 @@ -857,8 +868,10 @@ function setupVideoListeners() { startSponsorSchedule(); } - }); - getVideo().addEventListener('playing', () => { + }; + getVideo().addEventListener('play', playListener); + + const playingListener = () => { updateVirtualTime(); lastPausedAtZero = false; @@ -884,8 +897,10 @@ function setupVideoListeners() { startSponsorSchedule(); } - }); - getVideo().addEventListener('seeking', () => { + }; + getVideo().addEventListener('playing', playingListener); + + const seekingListener = () => { lastKnownVideoTime.fromPause = false; if (!getVideo().paused){ @@ -909,20 +924,19 @@ function setupVideoListeners() { lastPausedAtZero = true; } } - }); - getVideo().addEventListener('ratechange', () => { + }; + getVideo().addEventListener('seeking', seekingListener); + + const rateChangeListener = () => { updateVirtualTime(); clearWaitingTime(); startSponsorSchedule(); - }); + }; + getVideo().addEventListener('ratechange', () => rateChangeListener); // Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740) - getVideo().addEventListener('videoSpeed_ratechange', () => { - updateVirtualTime(); - clearWaitingTime(); + getVideo().addEventListener('videoSpeed_ratechange', rateChangeListener); - startSponsorSchedule(); - }); const stoppedPlayback = () => { // Reset lastCheckVideoTime lastCheckVideoTime = -1; @@ -934,20 +948,36 @@ function setupVideoListeners() { cancelSponsorSchedule(); }; - getVideo().addEventListener('pause', () => { + const pauseListener = () => { lastKnownVideoTime.fromPause = true; stoppedPlayback(); - }); - getVideo().addEventListener('waiting', () => { + }; + getVideo().addEventListener('pause', pauseListener); + const waitingListener = () => { logDebug("[SB] Not skipping due to buffering"); startedWaiting = true; stoppedPlayback(); - }); + }; + getVideo().addEventListener('waiting', waitingListener); startSponsorSchedule(); + + if (setupVideoListenersFirstTime) { + addCleanupListener(() => { + getVideo().removeEventListener('play', playListener); + getVideo().removeEventListener('playing', playingListener); + getVideo().removeEventListener('seeking', seekingListener); + getVideo().removeEventListener('ratechange', rateChangeListener); + getVideo().removeEventListener('videoSpeed_ratechange', rateChangeListener); + getVideo().removeEventListener('pause', pauseListener); + getVideo().removeEventListener('waiting', waitingListener); + }); + } } + + setupVideoListenersFirstTime = false; } function updateVirtualTime() { @@ -1626,9 +1656,10 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u beep.play(); beep.addEventListener("ended", () => { navigator.mediaSession.metadata = null; - setTimeout(() => - navigator.mediaSession.metadata = oldMetadata - ); + setTimeout(() => { + navigator.mediaSession.metadata = oldMetadata; + beep.remove(); + }); }) } @@ -2342,6 +2373,10 @@ function addHotkeyListener(): void { // Allow us to stop propagation to YouTube by being deeper document.removeEventListener("keydown", hotkeyListener); document.body.addEventListener("keydown", hotkeyListener); + + addCleanupListener(() => { + document.body.removeEventListener("keydown", hotkeyListener); + }); }; if (document.readyState === "complete") { diff --git a/src/js-components/previewBar.ts b/src/js-components/previewBar.ts index d88912b2ba..bcadbf3bf2 100644 --- a/src/js-components/previewBar.ts +++ b/src/js-components/previewBar.ts @@ -13,6 +13,7 @@ import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils"; import { normalizeChapterName } from "../utils/exporter"; import { getFormattedTimeToSeconds } from "../maze-utils/formating"; import { findValidElement } from "../maze-utils/dom"; +import { addCleanupListener } from "../maze-utils/cleanup"; const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible'; const MIN_CHAPTER_SIZE = 0.003; @@ -201,6 +202,10 @@ class PreviewBar { childList: true, subtree: true, }); + + addCleanupListener(() => { + observer.disconnect(); + }); } private setTooltipTitle(segment: PreviewBarSegment, tooltip: HTMLElement): void { @@ -626,6 +631,11 @@ class PreviewBar { childListObserver.observe(this.originalChapterBar, { childList: true }); + + addCleanupListener(() => { + attributeObserver.disconnect(); + childListObserver.disconnect(); + }); } private updateChapterAllMutation(originalChapterBar: HTMLElement, progressBar: HTMLElement, firstUpdate = false): void { diff --git a/src/render/CategoryPill.tsx b/src/render/CategoryPill.tsx index 1d66f57447..e30d196553 100644 --- a/src/render/CategoryPill.tsx +++ b/src/render/CategoryPill.tsx @@ -7,6 +7,7 @@ import { Category, SegmentUUID, SponsorTime } from "../types"; import { Tooltip } from "./Tooltip"; import { waitFor } from "../maze-utils"; import { getYouTubeTitleNode } from "../maze-utils/elements"; +import { addCleanupListener } from "../maze-utils/cleanup"; const id = "categoryPill"; @@ -24,6 +25,12 @@ export class CategoryPill { constructor() { this.ref = React.createRef(); + + addCleanupListener(() => { + if (this.mutationObserver) { + this.mutationObserver.disconnect(); + } + }); } async attachToPage(onMobileYouTube: boolean, onInvidious: boolean, diff --git a/src/utils/pageCleaner.ts b/src/utils/pageCleaner.ts index b853c0b528..0d2ad2b9c9 100644 --- a/src/utils/pageCleaner.ts +++ b/src/utils/pageCleaner.ts @@ -1,6 +1,8 @@ export function cleanPage() { // For live-updates - for (const element of document.querySelectorAll("#categoryPillParent, .playerButton, .sponsorThumbnailLabel, #submissionNoticeContainer, .sponsorSkipNoticeContainer, #sponsorBlockPopupContainer, .skipButtonControlBarContainer, #previewbar")) { - element.remove(); + if (document.readyState === "complete") { + for (const element of document.querySelectorAll("#categoryPillParent, .playerButton, .sponsorThumbnailLabel, #submissionNoticeContainer, .sponsorSkipNoticeContainer, #sponsorBlockPopupContainer, .skipButtonControlBarContainer, #previewbar, .sponsorBlockChapterBar")) { + element.remove(); + } } } \ No newline at end of file