From bb14d63a9c8c0f49546312779c219117043ad5c2 Mon Sep 17 00:00:00 2001 From: Jelle van Snik Date: Sat, 4 Feb 2023 16:29:21 +0100 Subject: [PATCH] meta data in video player --- src/video/components/VideoPlayer.tsx | 129 +++++++++--------- src/video/components/actions/HeaderAction.tsx | 15 ++ .../components/actions/PageTitleAction.tsx | 19 +++ .../actions/QualityDisplayAction.tsx | 17 +++ .../components/actions/ShowTitleAction.tsx | 17 +++ .../components/controllers/MetaController.tsx | 19 +++ .../hooks/useCurrentSeriesEpisodeInfo.ts | 35 +++++ .../components/parts/VideoPlayerError.tsx | 37 +++++ .../components/parts/VideoPlayerHeader.tsx | 65 +++++++++ src/video/state/events.ts | 3 +- src/video/state/init.ts | 45 +++--- src/video/state/logic/controls.ts | 21 ++- src/video/state/logic/interface.ts | 8 +- src/video/state/logic/mediaplaying.ts | 12 +- src/video/state/logic/meta.ts | 35 +++++ src/video/state/logic/progress.ts | 6 +- .../state/providers/videoStateProvider.ts | 48 ++++--- src/video/state/types.ts | 85 +++++++----- src/views/TestView.tsx | 20 +-- src/views/media/MediaView.tsx | 24 ++-- 20 files changed, 492 insertions(+), 168 deletions(-) create mode 100644 src/video/components/actions/HeaderAction.tsx create mode 100644 src/video/components/actions/PageTitleAction.tsx create mode 100644 src/video/components/actions/QualityDisplayAction.tsx create mode 100644 src/video/components/actions/ShowTitleAction.tsx create mode 100644 src/video/components/controllers/MetaController.tsx create mode 100644 src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts create mode 100644 src/video/components/parts/VideoPlayerError.tsx create mode 100644 src/video/components/parts/VideoPlayerHeader.tsx create mode 100644 src/video/state/logic/meta.ts diff --git a/src/video/components/VideoPlayer.tsx b/src/video/components/VideoPlayer.tsx index 404db24b..67977b93 100644 --- a/src/video/components/VideoPlayer.tsx +++ b/src/video/components/VideoPlayer.tsx @@ -2,13 +2,18 @@ import { Transition } from "@/components/Transition"; import { useIsMobile } from "@/hooks/useIsMobile"; import { BackdropAction } from "@/video/components/actions/BackdropAction"; import { FullscreenAction } from "@/video/components/actions/FullscreenAction"; +import { HeaderAction } from "@/video/components/actions/HeaderAction"; import { LoadingAction } from "@/video/components/actions/LoadingAction"; import { MiddlePauseAction } from "@/video/components/actions/MiddlePauseAction"; import { MobileCenterAction } from "@/video/components/actions/MobileCenterAction"; +import { PageTitleAction } from "@/video/components/actions/PageTitleAction"; import { PauseAction } from "@/video/components/actions/PauseAction"; import { ProgressAction } from "@/video/components/actions/ProgressAction"; +import { QualityDisplayAction } from "@/video/components/actions/QualityDisplayAction"; +import { ShowTitleAction } from "@/video/components/actions/ShowTitleAction"; import { SkipTimeAction } from "@/video/components/actions/SkipTimeAction"; import { TimeAction } from "@/video/components/actions/TimeAction"; +import { VideoPlayerError } from "@/video/components/parts/VideoPlayerError"; import { VideoPlayerBase, VideoPlayerBaseProps, @@ -17,6 +22,10 @@ import { useVideoPlayerDescriptor } from "@/video/state/hooks"; import { useControls } from "@/video/state/logic/controls"; import { ReactNode, useCallback, useState } from "react"; +type Props = VideoPlayerBaseProps & { + onGoBack?: () => void; +}; + function CenterPosition(props: { children: ReactNode }) { return (
@@ -48,12 +57,12 @@ function LeftSideControls() { {/* */}
- {/* */} + ); } -export function VideoPlayer(props: VideoPlayerBaseProps) { +export function VideoPlayer(props: Props) { const [show, setShow] = useState(false); const { isMobile } = useIsMobile(); @@ -65,76 +74,72 @@ export function VideoPlayer(props: VideoPlayerBaseProps) { ); // TODO autoplay - // TODO meta data + // TODO safe area only if full screen or fill screen return ( - {/* */} - {/* */} - - - - - - - - {isMobile ? ( + + + + + + + + + + {isMobile ? ( + + + + ) : ( + "" + )} - + - ) : ( - "" - )} - - {/* */} - - -
- {isMobile && } - -
-
- {isMobile ? ( -
-
-
- {/* */} - {/* */} + +
+ {isMobile && } + +
+
+ {isMobile ? ( +
+
+
+ {/* */} + {/* */} +
+
- -
- ) : ( - <> - -
- {/* - + ) : ( + <> + +
+ + {/* */} - - - )} -
- - - {props.children} - {/* */} + + + )} +
+ + + {props.children} + ); } diff --git a/src/video/components/actions/HeaderAction.tsx b/src/video/components/actions/HeaderAction.tsx new file mode 100644 index 00000000..390f2efd --- /dev/null +++ b/src/video/components/actions/HeaderAction.tsx @@ -0,0 +1,15 @@ +import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useMeta } from "@/video/state/logic/meta"; + +interface Props { + onClick?: () => void; + showControls?: boolean; +} + +export function HeaderAction(props: Props) { + const descriptor = useVideoPlayerDescriptor(); + const meta = useMeta(descriptor); + + return ; +} diff --git a/src/video/components/actions/PageTitleAction.tsx b/src/video/components/actions/PageTitleAction.tsx new file mode 100644 index 00000000..ab0daf0a --- /dev/null +++ b/src/video/components/actions/PageTitleAction.tsx @@ -0,0 +1,19 @@ +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { Helmet } from "react-helmet"; +import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; + +export function PageTitleAction() { + const descriptor = useVideoPlayerDescriptor(); + const { isSeries, humanizedEpisodeId, meta } = + useCurrentSeriesEpisodeInfo(descriptor); + + if (!meta) return null; + + const title = isSeries ? `${meta.title} - ${humanizedEpisodeId}` : meta.title; + + return ( + + {title} + + ); +} diff --git a/src/video/components/actions/QualityDisplayAction.tsx b/src/video/components/actions/QualityDisplayAction.tsx new file mode 100644 index 00000000..c2a58c50 --- /dev/null +++ b/src/video/components/actions/QualityDisplayAction.tsx @@ -0,0 +1,17 @@ +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useSource } from "@/video/state/logic/source"; + +export function QualityDisplayAction() { + const descriptor = useVideoPlayerDescriptor(); + const source = useSource(descriptor); + + if (!source.source) return null; + + return ( +
+

+ {source.source.quality} +

+
+ ); +} diff --git a/src/video/components/actions/ShowTitleAction.tsx b/src/video/components/actions/ShowTitleAction.tsx new file mode 100644 index 00000000..a40c3faa --- /dev/null +++ b/src/video/components/actions/ShowTitleAction.tsx @@ -0,0 +1,17 @@ +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useCurrentSeriesEpisodeInfo } from "../hooks/useCurrentSeriesEpisodeInfo"; + +export function ShowTitleAction() { + const descriptor = useVideoPlayerDescriptor(); + const { isSeries, currentEpisodeInfo, humanizedEpisodeId } = + useCurrentSeriesEpisodeInfo(descriptor); + + if (!isSeries) return null; + + return ( +

+ {humanizedEpisodeId} + {currentEpisodeInfo?.title} +

+ ); +} diff --git a/src/video/components/controllers/MetaController.tsx b/src/video/components/controllers/MetaController.tsx new file mode 100644 index 00000000..be35a702 --- /dev/null +++ b/src/video/components/controllers/MetaController.tsx @@ -0,0 +1,19 @@ +import { MWMediaMeta } from "@/backend/metadata/types"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useControls } from "@/video/state/logic/controls"; +import { useEffect } from "react"; + +interface MetaControllerProps { + meta?: MWMediaMeta; +} + +export function MetaController(props: MetaControllerProps) { + const descriptor = useVideoPlayerDescriptor(); + const controls = useControls(descriptor); + + useEffect(() => { + controls.setMeta(props.meta); + }, [props, controls]); + + return null; +} diff --git a/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts b/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts new file mode 100644 index 00000000..77afa249 --- /dev/null +++ b/src/video/components/hooks/useCurrentSeriesEpisodeInfo.ts @@ -0,0 +1,35 @@ +import { MWMediaType } from "@/backend/metadata/types"; +import { useMeta } from "@/video/state/logic/meta"; +import { useMemo } from "react"; + +export function useCurrentSeriesEpisodeInfo(descriptor: string) { + const meta = useMeta(descriptor); + + const currentSeasonInfo = useMemo(() => { + return meta?.seasons?.find( + (season) => season.id === meta?.episode?.seasonId + ); + }, [meta]); + + const currentEpisodeInfo = useMemo(() => { + return currentSeasonInfo?.episodes?.find( + (episode) => episode.id === meta?.episode?.episodeId + ); + }, [currentSeasonInfo, meta]); + + const isSeries = Boolean( + meta?.meta?.type === MWMediaType.SERIES && meta?.episode + ); + + if (!isSeries) return { isSeries: false }; + + const humanizedEpisodeId = `S${currentSeasonInfo?.number} E${currentEpisodeInfo?.number}`; + + return { + isSeries: true, + humanizedEpisodeId, + currentSeasonInfo, + currentEpisodeInfo, + meta: meta?.meta, + }; +} diff --git a/src/video/components/parts/VideoPlayerError.tsx b/src/video/components/parts/VideoPlayerError.tsx new file mode 100644 index 00000000..b9d40e5e --- /dev/null +++ b/src/video/components/parts/VideoPlayerError.tsx @@ -0,0 +1,37 @@ +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icons } from "@/components/Icon"; +import { Title } from "@/components/text/Title"; +import { useVideoPlayerDescriptor } from "@/video/state/hooks"; +import { useMeta } from "@/video/state/logic/meta"; +import { ReactNode } from "react"; +import { VideoPlayerHeader } from "./VideoPlayerHeader"; + +interface VideoPlayerErrorProps { + onGoBack?: () => void; + children?: ReactNode; +} + +export function VideoPlayerError(props: VideoPlayerErrorProps) { + const descriptor = useVideoPlayerDescriptor(); + const meta = useMeta(descriptor); + // TODO add error state + + const err = null as any; + + if (!err) return props.children as any; + + return ( +
+
+ + Failed to load media +

+ {err?.name}: {err?.description} +

+
+
+ +
+
+ ); +} diff --git a/src/video/components/parts/VideoPlayerHeader.tsx b/src/video/components/parts/VideoPlayerHeader.tsx new file mode 100644 index 00000000..c1cf603d --- /dev/null +++ b/src/video/components/parts/VideoPlayerHeader.tsx @@ -0,0 +1,65 @@ +import { MWMediaMeta } from "@/backend/metadata/types"; +import { IconPatch } from "@/components/buttons/IconPatch"; +import { Icon, Icons } from "@/components/Icon"; +import { BrandPill } from "@/components/layout/BrandPill"; +import { + getIfBookmarkedFromPortable, + useBookmarkContext, +} from "@/state/bookmark"; + +interface VideoPlayerHeaderProps { + media?: MWMediaMeta; + onClick?: () => void; + showControls?: boolean; +} + +export function VideoPlayerHeader(props: VideoPlayerHeaderProps) { + const { bookmarkStore, setItemBookmark } = useBookmarkContext(); + const isBookmarked = props.media + ? getIfBookmarkedFromPortable(bookmarkStore.bookmarks, props.media) + : false; + const showDivider = props.media && props.onClick; + return ( +
+
+

+ {props.onClick ? ( + + + Back to home + + ) : null} + {showDivider ? ( + + ) : null} + {props.media ? ( + + {props.media.title} + + ) : null} +

+ {props.media && ( + + props.media && setItemBookmark(props.media, !isBookmarked) + } + /> + )} +
+ {props.showControls ? null : ( + // <> + // + // + // + + )} +
+ ); +} diff --git a/src/video/state/events.ts b/src/video/state/events.ts index b47b7d15..0d9b632b 100644 --- a/src/video/state/events.ts +++ b/src/video/state/events.ts @@ -2,7 +2,8 @@ export type VideoPlayerEvent = | "mediaplaying" | "source" | "progress" - | "interface"; + | "interface" + | "meta"; function createEventString(id: string, event: VideoPlayerEvent): string { return `_vid:::${id}:::${event}`; diff --git a/src/video/state/init.ts b/src/video/state/init.ts index ffe66a70..67319362 100644 --- a/src/video/state/init.ts +++ b/src/video/state/init.ts @@ -4,29 +4,38 @@ import { VideoPlayerState } from "./types"; function initPlayer(): VideoPlayerState { return { - isPlaying: false, - isPaused: true, - isFullscreen: false, - isFocused: false, - isLoading: false, - isSeeking: false, - isFirstLoading: true, - time: 0, - duration: 0, + interface: { + popout: null, + isFullscreen: false, + isFocused: false, + leftControlHovering: false, + }, + + mediaPlaying: { + isPlaying: false, + isPaused: true, + isLoading: false, + isSeeking: false, + isFirstLoading: true, + hasPlayedOnce: false, + }, + + progress: { + time: 0, + duration: 0, + buffered: 0, + }, + + meta: null, + source: null, + error: null, + volume: 0, - buffered: 0, pausedWhenSeeking: false, hasInitialized: false, - leftControlHovering: false, - hasPlayedOnce: false, - error: null, - popout: null, - seasonData: { - isSeries: false, - }, canAirplay: false, + stateProvider: null, - source: null, wrapperElement: null, }; } diff --git a/src/video/state/logic/controls.ts b/src/video/state/logic/controls.ts index 1044d85d..510c4f78 100644 --- a/src/video/state/logic/controls.ts +++ b/src/video/state/logic/controls.ts @@ -1,4 +1,6 @@ +import { MWMediaMeta } from "@/backend/metadata/types"; import { updateInterface } from "@/video/state/logic/interface"; +import { updateMeta } from "@/video/state/logic/meta"; import { getPlayerState } from "../cache"; import { VideoPlayerStateController } from "../providers/providerTypes"; @@ -7,6 +9,7 @@ type ControlMethods = { closePopout(): void; setLeftControlsHover(hovering: boolean): void; setFocused(focused: boolean): void; + setMeta(meta?: MWMediaMeta): void; }; export function useControls( @@ -40,20 +43,30 @@ export function useControls( // other controls setLeftControlsHover(hovering) { - state.leftControlHovering = hovering; + state.interface.leftControlHovering = hovering; updateInterface(descriptor, state); }, openPopout(id: string) { - state.popout = id; + state.interface.popout = id; updateInterface(descriptor, state); }, closePopout() { - state.popout = null; + state.interface.popout = null; updateInterface(descriptor, state); }, setFocused(focused) { - state.isFocused = focused; + state.interface.isFocused = focused; updateInterface(descriptor, state); }, + setMeta(meta) { + if (!meta) { + state.meta = null; + } else { + state.meta = { + meta, + }; + } + updateMeta(descriptor, state); + }, }; } diff --git a/src/video/state/logic/interface.ts b/src/video/state/logic/interface.ts index bd912b18..13c99d02 100644 --- a/src/video/state/logic/interface.ts +++ b/src/video/state/logic/interface.ts @@ -12,10 +12,10 @@ export type VideoInterfaceEvent = { function getInterfaceFromState(state: VideoPlayerState): VideoInterfaceEvent { return { - popout: state.popout, - leftControlHovering: state.leftControlHovering, - isFocused: state.isFocused, - isFullscreen: state.isFullscreen, + popout: state.interface.popout, + leftControlHovering: state.interface.leftControlHovering, + isFocused: state.interface.isFocused, + isFullscreen: state.interface.isFullscreen, }; } diff --git a/src/video/state/logic/mediaplaying.ts b/src/video/state/logic/mediaplaying.ts index 7980f2ed..b25d42e7 100644 --- a/src/video/state/logic/mediaplaying.ts +++ b/src/video/state/logic/mediaplaying.ts @@ -16,12 +16,12 @@ function getMediaPlayingFromState( state: VideoPlayerState ): VideoMediaPlayingEvent { return { - hasPlayedOnce: state.hasPlayedOnce, - isLoading: state.isLoading, - isPaused: state.isPaused, - isPlaying: state.isPlaying, - isSeeking: state.isSeeking, - isFirstLoading: state.isFirstLoading, + hasPlayedOnce: state.mediaPlaying.hasPlayedOnce, + isLoading: state.mediaPlaying.isLoading, + isPaused: state.mediaPlaying.isPaused, + isPlaying: state.mediaPlaying.isPlaying, + isSeeking: state.mediaPlaying.isSeeking, + isFirstLoading: state.mediaPlaying.isFirstLoading, }; } diff --git a/src/video/state/logic/meta.ts b/src/video/state/logic/meta.ts new file mode 100644 index 00000000..35e6ad79 --- /dev/null +++ b/src/video/state/logic/meta.ts @@ -0,0 +1,35 @@ +import { useEffect, useState } from "react"; +import { getPlayerState } from "../cache"; +import { listenEvent, sendEvent, unlistenEvent } from "../events"; +import { VideoPlayerMeta, VideoPlayerState } from "../types"; + +export type VideoMetaEvent = VideoPlayerMeta | null; + +function getMetaFromState(state: VideoPlayerState): VideoMetaEvent { + return state.meta + ? { + ...state.meta, + } + : null; +} + +export function updateMeta(descriptor: string, state: VideoPlayerState) { + sendEvent(descriptor, "meta", getMetaFromState(state)); +} + +export function useMeta(descriptor: string): VideoMetaEvent { + const state = getPlayerState(descriptor); + const [data, setData] = useState(getMetaFromState(state)); + + useEffect(() => { + function update(payload: CustomEvent) { + setData(payload.detail); + } + listenEvent(descriptor, "meta", update); + return () => { + unlistenEvent(descriptor, "meta", update); + }; + }, [descriptor]); + + return data; +} diff --git a/src/video/state/logic/progress.ts b/src/video/state/logic/progress.ts index c65b09ab..3cc560de 100644 --- a/src/video/state/logic/progress.ts +++ b/src/video/state/logic/progress.ts @@ -11,9 +11,9 @@ export type VideoProgressEvent = { function getProgressFromState(state: VideoPlayerState): VideoProgressEvent { return { - time: state.time, - duration: state.duration, - buffered: state.buffered, + time: state.progress.time, + duration: state.progress.duration, + buffered: state.progress.buffered, }; } diff --git a/src/video/state/providers/videoStateProvider.ts b/src/video/state/providers/videoStateProvider.ts index ddc9b437..0746ab62 100644 --- a/src/video/state/providers/videoStateProvider.ts +++ b/src/video/state/providers/videoStateProvider.ts @@ -7,6 +7,7 @@ import { } from "@/utils/detectFeatures"; import { MWStreamType } from "@/backend/helpers/streams"; import { updateInterface } from "@/video/state/logic/interface"; +import { updateSource } from "@/video/state/logic/source"; import { getPlayerState } from "../cache"; import { updateMediaPlaying } from "../logic/mediaplaying"; import { VideoPlayerStateProvider } from "./providerTypes"; @@ -51,7 +52,7 @@ export function createVideoStateProvider( // update state player.currentTime = time; - state.time = time; + state.progress.time = time; updateProgress(descriptor, state); }, setSeeking(active) { @@ -63,12 +64,14 @@ export function createVideoStateProvider( // when seeking we pause the video // this variables isnt reactive, just used so the state can be remembered next unseek - state.pausedWhenSeeking = state.isPaused; + state.pausedWhenSeeking = state.mediaPlaying.isPaused; this.pause(); }, setSource(source) { if (!source) { player.src = ""; + state.source = null; + updateSource(descriptor, state); return; } @@ -105,52 +108,63 @@ export function createVideoStateProvider( } else if (source.type === MWStreamType.MP4) { player.src = source.source; } + + // update state + state.source = { + quality: source.quality, + type: source.type, + url: source.source, + }; + updateSource(descriptor, state); }, providerStart() { // TODO stored volume const pause = () => { - state.isPaused = true; - state.isPlaying = false; + state.mediaPlaying.isPaused = true; + state.mediaPlaying.isPlaying = false; updateMediaPlaying(descriptor, state); }; const playing = () => { - state.isPaused = false; - state.isPlaying = true; - state.isLoading = false; - state.hasPlayedOnce = true; + state.mediaPlaying.isPaused = false; + state.mediaPlaying.isPlaying = true; + state.mediaPlaying.isLoading = false; + state.mediaPlaying.hasPlayedOnce = true; updateMediaPlaying(descriptor, state); }; const waiting = () => { - state.isLoading = true; + state.mediaPlaying.isLoading = true; updateMediaPlaying(descriptor, state); }; const seeking = () => { - state.isSeeking = true; + state.mediaPlaying.isSeeking = true; updateMediaPlaying(descriptor, state); }; const seeked = () => { - state.isSeeking = false; + state.mediaPlaying.isSeeking = false; updateMediaPlaying(descriptor, state); }; const loadedmetadata = () => { - state.duration = player.duration; + state.progress.duration = player.duration; updateProgress(descriptor, state); }; const timeupdate = () => { - state.duration = player.duration; - state.time = player.currentTime; + state.progress.duration = player.duration; + state.progress.time = player.currentTime; updateProgress(descriptor, state); }; const progress = () => { - state.buffered = handleBuffered(player.currentTime, player.buffered); + state.progress.buffered = handleBuffered( + player.currentTime, + player.buffered + ); updateProgress(descriptor, state); }; const canplay = () => { - state.isFirstLoading = false; + state.mediaPlaying.isFirstLoading = false; updateMediaPlaying(descriptor, state); }; const fullscreenchange = () => { - state.isFullscreen = !!document.fullscreenElement; + state.interface.isFullscreen = !!document.fullscreenElement; updateInterface(descriptor, state); }; diff --git a/src/video/state/types.ts b/src/video/state/types.ts index e2ecb3a0..37e0969b 100644 --- a/src/video/state/types.ts +++ b/src/video/state/types.ts @@ -1,47 +1,66 @@ import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; +import { MWMediaMeta } from "@/backend/metadata/types"; import { VideoPlayerStateProvider } from "./providers/providerTypes"; +export type VideoPlayerMeta = { + meta: MWMediaMeta; + episode?: { + episodeId: string; + seasonId: string; + }; + seasons?: { + id: string; + number: number; + title: string; + episodes?: { id: string; number: number; title: string }[]; + }[]; +}; + export type VideoPlayerState = { - isPlaying: boolean; - isPaused: boolean; - isSeeking: boolean; - isLoading: boolean; - isFirstLoading: boolean; - isFullscreen: boolean; - time: number; - duration: number; - volume: number; - buffered: number; - pausedWhenSeeking: boolean; - hasInitialized: boolean; - leftControlHovering: boolean; - hasPlayedOnce: boolean; - popout: string | null; - isFocused: boolean; - seasonData: { - isSeries: boolean; - current?: { - episodeId: string; - seasonId: string; - }; - seasons?: { - id: string; - number: number; - title: string; - episodes?: { id: string; number: number; title: string }[]; - }[]; + // state related to the user interface + interface: { + isFullscreen: boolean; + popout: string | null; // id of current popout (eg source select, episode select) + isFocused: boolean; // is the video player the users focus? (shortcuts only works when its focused) + leftControlHovering: boolean; // is the cursor hovered over the left side of player controls }; - error: null | { - name: string; - description: string; + // state related to the playing state of the media + mediaPlaying: { + isPlaying: boolean; + isPaused: boolean; + isSeeking: boolean; // seeking with progress bar + isLoading: boolean; // buffering or not + isFirstLoading: boolean; // first buffering of the video, used to show + hasPlayedOnce: boolean; // has the video played at all? }; - canAirplay: boolean; - stateProvider: VideoPlayerStateProvider | null; + + // state related to video progress + progress: { + time: number; + duration: number; + buffered: number; + }; + + // meta data of video + meta: null | VideoPlayerMeta; source: null | { quality: MWStreamQuality; url: string; type: MWStreamType; }; + error: null | { + name: string; + description: string; + }; + + // misc + volume: number; + pausedWhenSeeking: boolean; + hasInitialized: boolean; + canAirplay: boolean; + + // backing fields + stateProvider: VideoPlayerStateProvider | null; wrapperElement: HTMLDivElement | null; }; diff --git a/src/views/TestView.tsx b/src/views/TestView.tsx index eddbd3bc..cc3d00da 100644 --- a/src/views/TestView.tsx +++ b/src/views/TestView.tsx @@ -5,15 +5,10 @@ // import { useEffect, useRef } from "react"; import { MWStreamQuality, MWStreamType } from "@/backend/helpers/streams"; -import { LoadingAction } from "@/video/components/actions/LoadingAction"; -import { MiddlePauseAction } from "@/video/components/actions/MiddlePauseAction"; -import { PauseAction } from "@/video/components/actions/PauseAction"; -import { ProgressAction } from "@/video/components/actions/ProgressAction"; -import { SkipTimeAction } from "@/video/components/actions/SkipTimeAction"; -import { TimeAction } from "@/video/components/actions/TimeAction"; +import { MWMediaType } from "@/backend/metadata/types"; +import { MetaController } from "@/video/components/controllers/MetaController"; import { SourceController } from "@/video/components/controllers/SourceController"; import { VideoPlayer } from "@/video/components/VideoPlayer"; -import { VideoPlayerBase } from "@/video/components/VideoPlayerBase"; // function ChromeCastButton() { // const ref = useRef(null); @@ -31,12 +26,21 @@ import { VideoPlayerBase } from "@/video/components/VideoPlayerBase"; export function TestView() { return ( - + alert("hello world")}> + ); } diff --git a/src/views/media/MediaView.tsx b/src/views/media/MediaView.tsx index 435056f9..2d6e77ec 100644 --- a/src/views/media/MediaView.tsx +++ b/src/views/media/MediaView.tsx @@ -1,22 +1,21 @@ import { useHistory, useParams } from "react-router-dom"; import { Helmet } from "react-helmet"; import { useEffect, useRef, useState } from "react"; -import { DecoratedVideoPlayer } from "@/../__old/DecoratedVideoPlayer"; import { MWStream } from "@/backend/helpers/streams"; import { SelectedMediaData, useScrape } from "@/hooks/useScrape"; -import { VideoPlayerHeader } from "@/../__old/parts/VideoPlayerHeader"; import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta"; import { decodeJWId } from "@/backend/metadata/justwatch"; -import { SourceControl } from "@/../__old/controls/SourceControl"; import { Loading } from "@/components/layout/Loading"; import { useLoading } from "@/hooks/useLoading"; import { MWMediaType } from "@/backend/metadata/types"; import { useGoBack } from "@/hooks/useGoBack"; import { IconPatch } from "@/components/buttons/IconPatch"; +import { VideoPlayer } from "@/video/components/VideoPlayer"; +import { MetaController } from "@/video/components/controllers/MetaController"; +import { SourceController } from "@/video/components/controllers/SourceController"; import { Icons } from "@/components/Icon"; +import { VideoPlayerHeader } from "@/video/components/parts/VideoPlayerHeader"; import { useWatchedItem } from "@/state/watched"; -import { ProgressListenerControl } from "@/../__old/controls/ProgressListenerControl"; -import { ShowControl } from "@/../__old/controls/ShowControl"; import { MediaFetchErrorView } from "./MediaErrorView"; import { MediaScrapeLog } from "./MediaScrapeLog"; import { NotFoundMedia, NotFoundWrapper } from "../notfound/NotFoundView"; @@ -113,17 +112,18 @@ export function MediaViewPlayer(props: MediaViewPlayerProps) { - - + + - - {props.selected.type === MWMediaType.SERIES && + /> */} + {/* {props.selected.type === MWMediaType.SERIES && props.meta.meta.type === MWMediaType.SERIES ? ( - ) : null} - + ) : null} */} +
); }