From 927b4f93934d75cc74e16f9968cc0f4eced2a284 Mon Sep 17 00:00:00 2001 From: Megan Worley Date: Sat, 17 Feb 2024 15:04:10 -0800 Subject: [PATCH] Move Netflix player fetching to a custom hook --- .../components/VideoContainer.tsx | 40 ++++--------------- .../hooks/useNetflixControls.ts | 3 ++ src/content-scripts/hooks/useNetflixPlayer.ts | 40 +++++++++++++++++++ .../hooks/useNetflixSubtitleSuppressor.ts | 3 ++ 4 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 src/content-scripts/hooks/useNetflixPlayer.ts diff --git a/src/content-scripts/components/VideoContainer.tsx b/src/content-scripts/components/VideoContainer.tsx index 6164337..7695e49 100644 --- a/src/content-scripts/components/VideoContainer.tsx +++ b/src/content-scripts/components/VideoContainer.tsx @@ -1,15 +1,13 @@ -import React, { useState, useEffect } from "react"; +import React from "react"; import { createPortal } from "react-dom"; import { StorageType } from "../../storage/storage"; -import { querySelectorMutation, ChildMutationType } from "../util/util"; import Video from "./Video"; import { DBStatusResult } from "../../service-worker/database/dbstatus"; import { useStorage } from "../../common/hooks/useStorage"; import { useExtensionEnabled } from "../../common/hooks/useExtensionEnabled"; import { MovieId, useNetflixMetadata } from "../hooks/useNetflixMetadata"; +import { useNetflixPlayer } from "../hooks/useNetflixPlayer"; -const NETFLIX_PLAYER_CLASS = "watch-video--player-view"; -const NETFLIX_VIDEO_CLASS = `${NETFLIX_PLAYER_CLASS} video` const MOVIE_KEY = 'lastMovieId'; interface VideoContainerProps { @@ -20,33 +18,7 @@ function VideoContainer({ dbStatus }: VideoContainerProps) { const [currMovie] = useStorage(MOVIE_KEY, StorageType.Session, null); const [enabled] = useExtensionEnabled(false); const [subtitleData, currTrack] = useNetflixMetadata(); - const [netflixPlayer, setNetflixPlayer] = useState(document.querySelector(`.${NETFLIX_PLAYER_CLASS}`)); - const [videoElem, setVideoElem] = useState(document.querySelector(`.${NETFLIX_VIDEO_CLASS}`) as HTMLVideoElement | null); - - useEffect(() => { - // We insert our components into the Netflix DOM, but they constantly - // mutate it. Watch for changes so we know when to re-render. - const netflixObserver = new MutationObserver(mutationCallback); - function mutationCallback(mutationsList: MutationRecord[]) { - for (const mutation of mutationsList) { - if (mutation.type !== 'childList') { - continue; - } - const video = querySelectorMutation(mutation, `.${NETFLIX_VIDEO_CLASS}`); - if (video) { - setVideoElem(video.type === ChildMutationType.Added ? video.elem as HTMLVideoElement : null); - const player = document.querySelector(`.${NETFLIX_PLAYER_CLASS}`); - setNetflixPlayer(player); - } - } - } - const config = { attributes: false, childList: true, subtree: true }; - netflixObserver.observe(document.body, config); - - return () => { - netflixObserver.disconnect(); - }; - }, []); + const [netflixPlayer, videoElem] = useNetflixPlayer(); const subtitleTracks = currMovie ? subtitleData.get(currMovie) : undefined; const subtitles = subtitleTracks?.get(currTrack); @@ -60,7 +32,11 @@ function VideoContainer({ dbStatus }: VideoContainerProps) { <> { createPortal( - , + , netflixPlayer ) } diff --git a/src/content-scripts/hooks/useNetflixControls.ts b/src/content-scripts/hooks/useNetflixControls.ts index 5bc4a3a..8e15f20 100644 --- a/src/content-scripts/hooks/useNetflixControls.ts +++ b/src/content-scripts/hooks/useNetflixControls.ts @@ -1,6 +1,9 @@ import { useState, useEffect } from "react"; import { querySelectorMutation, ChildMutationType } from "../util/util"; +// todo: investigate performance of these kinds of hooks. currently using more than +// one MutationObserver just to keep things modular, which is probably not efficient. maybe combine them and broadcast out state changes in a better way + const NETFLIX_BOTTOM_CONTROLS_CLASS = 'watch-video--bottom-controls-container'; export function useNetflixControls(): Element | null { diff --git a/src/content-scripts/hooks/useNetflixPlayer.ts b/src/content-scripts/hooks/useNetflixPlayer.ts new file mode 100644 index 0000000..8d5248e --- /dev/null +++ b/src/content-scripts/hooks/useNetflixPlayer.ts @@ -0,0 +1,40 @@ +import { useState, useEffect } from "react"; +import { querySelectorMutation, ChildMutationType } from "../util/util"; + +// todo: investigate performance of these kinds of hooks. currently using more than +// one MutationObserver just to keep things modular, which is probably not efficient. maybe combine them and broadcast out state changes in a better way + +const NETFLIX_PLAYER_CLASS = "watch-video--player-view"; +const NETFLIX_VIDEO_CLASS = `${NETFLIX_PLAYER_CLASS} video` + +export function useNetflixPlayer(): [Element | null, HTMLVideoElement | null] { + const [netflixPlayer, setNetflixPlayer] = useState(document.querySelector(`.${NETFLIX_PLAYER_CLASS}`)); + const [videoElem, setVideoElem] = useState(document.querySelector(`.${NETFLIX_VIDEO_CLASS}`) as HTMLVideoElement | null); + + useEffect(() => { + // We insert our components into the Netflix DOM, but they constantly + // mutate it. Watch for changes so we know when to re-render. + const netflixObserver = new MutationObserver(mutationCallback); + function mutationCallback(mutationsList: MutationRecord[]) { + for (const mutation of mutationsList) { + if (mutation.type !== 'childList') { + continue; + } + const video = querySelectorMutation(mutation, `.${NETFLIX_VIDEO_CLASS}`); + if (video) { + setVideoElem(video.type === ChildMutationType.Added ? video.elem as HTMLVideoElement : null); + const player = document.querySelector(`.${NETFLIX_PLAYER_CLASS}`); + setNetflixPlayer(player); + } + } + } + const config = { attributes: false, childList: true, subtree: true }; + netflixObserver.observe(document.body, config); + + return () => { + netflixObserver.disconnect(); + }; + }, []); + + return [netflixPlayer, videoElem]; +} \ No newline at end of file diff --git a/src/content-scripts/hooks/useNetflixSubtitleSuppressor.ts b/src/content-scripts/hooks/useNetflixSubtitleSuppressor.ts index 27287dc..066366d 100644 --- a/src/content-scripts/hooks/useNetflixSubtitleSuppressor.ts +++ b/src/content-scripts/hooks/useNetflixSubtitleSuppressor.ts @@ -1,5 +1,8 @@ import { useState, useEffect } from "react"; +// todo: investigate performance of these kinds of hooks. currently using more than +// one MutationObserver just to keep things modular, which is probably not efficient. maybe combine them and broadcast out state changes in a better way + const NETFLIX_TEXT_SUBTITLE_CLASS = "player-timedtext"; const NETFLIX_IMAGE_SUBTITLE_CLASS = "image-based-timed-text";