Skip to content

Commit

Permalink
Move Netflix player fetching to a custom hook
Browse files Browse the repository at this point in the history
  • Loading branch information
mwhirls committed Feb 17, 2024
1 parent 450bb5a commit 927b4f9
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 32 deletions.
40 changes: 8 additions & 32 deletions src/content-scripts/components/VideoContainer.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -20,33 +18,7 @@ function VideoContainer({ dbStatus }: VideoContainerProps) {
const [currMovie] = useStorage<MovieId | null>(MOVIE_KEY, StorageType.Session, null);
const [enabled] = useExtensionEnabled(false);
const [subtitleData, currTrack] = useNetflixMetadata();
const [netflixPlayer, setNetflixPlayer] = useState<Element | null>(document.querySelector(`.${NETFLIX_PLAYER_CLASS}`));
const [videoElem, setVideoElem] = useState<HTMLVideoElement | null>(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);
Expand All @@ -60,7 +32,11 @@ function VideoContainer({ dbStatus }: VideoContainerProps) {
<>
{
createPortal(
<Video dbStatus={dbStatus} webvttSubtitles={subtitles} videoElem={videoElem}></Video>,
<Video
dbStatus={dbStatus}
webvttSubtitles={subtitles}
videoElem={videoElem}>
</Video>,
netflixPlayer
)
}
Expand Down
3 changes: 3 additions & 0 deletions src/content-scripts/hooks/useNetflixControls.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
40 changes: 40 additions & 0 deletions src/content-scripts/hooks/useNetflixPlayer.ts
Original file line number Diff line number Diff line change
@@ -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<Element | null>(document.querySelector(`.${NETFLIX_PLAYER_CLASS}`));
const [videoElem, setVideoElem] = useState<HTMLVideoElement | null>(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];
}
3 changes: 3 additions & 0 deletions src/content-scripts/hooks/useNetflixSubtitleSuppressor.ts
Original file line number Diff line number Diff line change
@@ -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";

Expand Down

0 comments on commit 927b4f9

Please sign in to comment.