diff --git a/src/components/video/DecoratedVideoPlayer.tsx b/src/components/video/DecoratedVideoPlayer.tsx index 6fd9e498..e34f51c0 100644 --- a/src/components/video/DecoratedVideoPlayer.tsx +++ b/src/components/video/DecoratedVideoPlayer.tsx @@ -14,6 +14,7 @@ import { ShowTitleControl } from "./controls/ShowTitleControl"; import { SkipTime } from "./controls/SkipTime"; import { TimeControl } from "./controls/TimeControl"; import { VolumeControl } from "./controls/VolumeControl"; +import { PageTitleControl } from "./controls/PageTitleControl"; import { VideoPlayerError } from "./parts/VideoPlayerError"; import { VideoPlayerHeader } from "./parts/VideoPlayerHeader"; import { useVideoPlayerState } from "./VideoContext"; @@ -67,6 +68,7 @@ export function DecoratedVideoPlayer( return ( <VideoPlayer autoPlay={props.autoPlay}> + <PageTitleControl media={props.media} /> <VideoPlayerError media={props.media} onGoBack={props.onGoBack}> <BackdropControl onBackdropChange={onBackdropChange}> <div className="absolute inset-0 flex items-center justify-center"> diff --git a/src/components/video/controls/PageTitleControl.tsx b/src/components/video/controls/PageTitleControl.tsx new file mode 100644 index 00000000..cbbee11f --- /dev/null +++ b/src/components/video/controls/PageTitleControl.tsx @@ -0,0 +1,23 @@ +import { MWMediaMeta } from "@/backend/metadata/types"; +import { Helmet } from "react-helmet"; +import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; + +interface PageTitleControlProps { + media?: MWMediaMeta; +} + +export function PageTitleControl(props: PageTitleControlProps) { + const { isSeries, episodeIdentifier } = useCurrentSeriesEpisodeInfo(); + + if (!props.media) return null; + + const title = isSeries + ? `${props.media.title} - ${episodeIdentifier}` + : props.media.title; + + return ( + <Helmet> + <title>{title}</title> + </Helmet> + ); +} diff --git a/src/components/video/controls/ShowTitleControl.tsx b/src/components/video/controls/ShowTitleControl.tsx index 2cb08420..37d76fad 100644 --- a/src/components/video/controls/ShowTitleControl.tsx +++ b/src/components/video/controls/ShowTitleControl.tsx @@ -1,29 +1,14 @@ -import { useMemo } from "react"; -import { useVideoPlayerState } from "../VideoContext"; +import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; export function ShowTitleControl() { - const { videoState } = useVideoPlayerState(); + const { isSeries, currentEpisodeInfo, episodeIdentifier } = + useCurrentSeriesEpisodeInfo(); - const { current, seasons } = videoState.seasonData; - - const currentSeasonInfo = useMemo(() => { - return seasons?.find((season) => season.id === current?.seasonId); - }, [seasons, current]); - - const currentEpisodeInfo = useMemo(() => { - return currentSeasonInfo?.episodes?.find( - (episode) => episode.id === current?.episodeId - ); - }, [currentSeasonInfo, current]); - - if (!videoState.seasonData.isSeries) return null; - if (!videoState.seasonData.current) return null; - - const selectedText = `S${currentSeasonInfo?.number} E${currentEpisodeInfo?.number}`; + if (!isSeries) return null; return ( <p className="ml-8 select-none space-x-2 text-white"> - <span>{selectedText}</span> + <span>{episodeIdentifier}</span> <span className="opacity-50">{currentEpisodeInfo?.title}</span> </p> ); diff --git a/src/components/video/hooks/useCurrentSeriesEpisodeInfo.ts b/src/components/video/hooks/useCurrentSeriesEpisodeInfo.ts new file mode 100644 index 00000000..e6b00c16 --- /dev/null +++ b/src/components/video/hooks/useCurrentSeriesEpisodeInfo.ts @@ -0,0 +1,33 @@ +import { useMemo } from "react"; +import { useVideoPlayerState } from "../VideoContext"; + +export function useCurrentSeriesEpisodeInfo() { + const { videoState } = useVideoPlayerState(); + + const { current, seasons } = videoState.seasonData; + + const currentSeasonInfo = useMemo(() => { + return seasons?.find((season) => season.id === current?.seasonId); + }, [seasons, current]); + + const currentEpisodeInfo = useMemo(() => { + return currentSeasonInfo?.episodes?.find( + (episode) => episode.id === current?.episodeId + ); + }, [currentSeasonInfo, current]); + + const isSeries = Boolean( + videoState.seasonData.isSeries && videoState.seasonData.current + ); + + if (!isSeries) return { isSeries: false }; + + const episodeIdentifier = `S${currentSeasonInfo?.number} E${currentEpisodeInfo?.number}`; + + return { + isSeries: true, + episodeIdentifier, + currentSeasonInfo, + currentEpisodeInfo, + }; +} diff --git a/src/views/media/MediaView.tsx b/src/views/media/MediaView.tsx index f63cc5ee..eedf7853 100644 --- a/src/views/media/MediaView.tsx +++ b/src/views/media/MediaView.tsx @@ -111,7 +111,6 @@ export function MediaViewPlayer(props: MediaViewPlayerProps) { return ( <div className="fixed top-0 left-0 h-[100dvh] w-screen"> <Helmet> - <title>{props.meta.meta.title}</title> <html data-full="true" /> </Helmet> <DecoratedVideoPlayer media={props.meta.meta} onGoBack={goBack} autoPlay>