meta data in video player

This commit is contained in:
Jelle van Snik 2023-02-04 16:29:21 +01:00
parent 27ef9be6b1
commit bb14d63a9c
20 changed files with 492 additions and 168 deletions

View File

@ -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 (
<div className="absolute inset-0 flex items-center justify-center">
@ -48,12 +57,12 @@ function LeftSideControls() {
{/* <VolumeControl className="mr-2" /> */}
<TimeAction />
</div>
{/* <ShowTitleControl /> */}
<ShowTitleAction />
</>
);
}
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 (
<VideoPlayerBase>
{/* <PageTitleControl media={props.media?.meta} /> */}
{/* <VideoPlayerError media={props.media?.meta} onGoBack={props.onGoBack}> */}
<BackdropAction onBackdropChange={onBackdropChange}>
<CenterPosition>
<LoadingAction />
</CenterPosition>
<CenterPosition>
<MiddlePauseAction />
</CenterPosition>
{isMobile ? (
<PageTitleAction />
<VideoPlayerError onGoBack={props.onGoBack}>
<BackdropAction onBackdropChange={onBackdropChange}>
<CenterPosition>
<LoadingAction />
</CenterPosition>
<CenterPosition>
<MiddlePauseAction />
</CenterPosition>
{isMobile ? (
<Transition
animation="fade"
show={show}
className="absolute inset-0 flex items-center justify-center"
>
<MobileCenterAction />
</Transition>
) : (
""
)}
<Transition
animation="fade"
animation="slide-down"
show={show}
className="absolute inset-0 flex items-center justify-center"
className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2"
>
<MobileCenterAction />
<HeaderAction showControls={isMobile} onClick={props.onGoBack} />
</Transition>
) : (
""
)}
<Transition
animation="slide-down"
show={show}
className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2"
>
{/* <VideoPlayerHeader
media={props.media?.meta}
onClick={props.onGoBack}
isMobile={isMobile}
/> */}
</Transition>
<Transition
animation="slide-up"
show={show}
className="pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2 [margin-bottom:env(safe-area-inset-bottom)]"
>
<div className="flex w-full items-center space-x-3">
{isMobile && <TimeAction noDuration />}
<ProgressAction />
</div>
<div className="flex items-center">
{isMobile ? (
<div className="grid w-full grid-cols-[56px,1fr,56px] items-center">
<div />
<div className="flex items-center justify-center">
{/* <SeriesSelectionControl /> */}
{/* <SourceSelectionControl media={props.media} /> */}
<Transition
animation="slide-up"
show={show}
className="pointer-events-auto absolute inset-x-0 bottom-0 flex flex-col px-4 pb-2 [margin-bottom:env(safe-area-inset-bottom)]"
>
<div className="flex w-full items-center space-x-3">
{isMobile && <TimeAction noDuration />}
<ProgressAction />
</div>
<div className="flex items-center">
{isMobile ? (
<div className="grid w-full grid-cols-[56px,1fr,56px] items-center">
<div />
<div className="flex items-center justify-center">
{/* <SeriesSelectionControl /> */}
{/* <SourceSelectionControl media={props.media} /> */}
</div>
<FullscreenAction />
</div>
<FullscreenAction />
</div>
) : (
<>
<LeftSideControls />
<div className="flex-1" />
{/* <QualityDisplayControl />
<SeriesSelectionControl />
) : (
<>
<LeftSideControls />
<div className="flex-1" />
<QualityDisplayAction />
{/* <SeriesSelectionControl />
<SourceSelectionControl media={props.media} />
<AirplayControl />
<ChromeCastControl /> */}
<FullscreenAction />
</>
)}
</div>
</Transition>
</BackdropAction>
{props.children}
{/* </VideoPlayerError> */}
<FullscreenAction />
</>
)}
</div>
</Transition>
</BackdropAction>
{props.children}
</VideoPlayerError>
</VideoPlayerBase>
);
}

View File

@ -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 <VideoPlayerHeader media={meta?.meta} {...props} />;
}

View File

@ -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 (
<Helmet>
<title>{title}</title>
</Helmet>
);
}

View File

@ -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 (
<div className="rounded-md bg-denim-300 py-1 px-2 transition-colors">
<p className="text-center text-xs font-bold text-slate-300 transition-colors">
{source.source.quality}
</p>
</div>
);
}

View File

@ -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 (
<p className="ml-8 select-none space-x-2 text-white">
<span>{humanizedEpisodeId}</span>
<span className="opacity-50">{currentEpisodeInfo?.title}</span>
</p>
);
}

View File

@ -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;
}

View File

@ -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,
};
}

View File

@ -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 (
<div>
<div className="absolute inset-0 flex flex-col items-center justify-center bg-denim-100">
<IconPatch icon={Icons.WARNING} className="mb-6 text-red-400" />
<Title>Failed to load media</Title>
<p className="my-6 max-w-lg">
{err?.name}: {err?.description}
</p>
</div>
<div className="pointer-events-auto absolute inset-x-0 top-0 flex flex-col py-6 px-8 pb-2">
<VideoPlayerHeader media={meta?.meta} onClick={props.onGoBack} />
</div>
</div>
);
}

View File

@ -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 (
<div className="flex items-center">
<div className="flex flex-1 items-center">
<p className="flex items-center">
{props.onClick ? (
<span
onClick={props.onClick}
className="flex cursor-pointer items-center py-1 text-white opacity-50 transition-opacity hover:opacity-100"
>
<Icon className="mr-2" icon={Icons.ARROW_LEFT} />
<span>Back to home</span>
</span>
) : null}
{showDivider ? (
<span className="mx-4 h-6 w-[1.5px] rotate-[30deg] bg-white opacity-50" />
) : null}
{props.media ? (
<span className="flex items-center text-white">
<span>{props.media.title}</span>
</span>
) : null}
</p>
{props.media && (
<IconPatch
clickable
transparent
icon={isBookmarked ? Icons.BOOKMARK : Icons.BOOKMARK_OUTLINE}
className="ml-2 text-white"
onClick={() =>
props.media && setItemBookmark(props.media, !isBookmarked)
}
/>
)}
</div>
{props.showControls ? null : (
// <>
// <AirplayControl />
// <ChromeCastControl />
// </>
<BrandPill />
)}
</div>
);
}

View File

@ -2,7 +2,8 @@ export type VideoPlayerEvent =
| "mediaplaying"
| "source"
| "progress"
| "interface";
| "interface"
| "meta";
function createEventString(id: string, event: VideoPlayerEvent): string {
return `_vid:::${id}:::${event}`;

View File

@ -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,
};
}

View File

@ -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);
},
};
}

View File

@ -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,
};
}

View File

@ -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,
};
}

View File

@ -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<VideoMetaEvent>(descriptor, "meta", getMetaFromState(state));
}
export function useMeta(descriptor: string): VideoMetaEvent {
const state = getPlayerState(descriptor);
const [data, setData] = useState<VideoMetaEvent>(getMetaFromState(state));
useEffect(() => {
function update(payload: CustomEvent<VideoMetaEvent>) {
setData(payload.detail);
}
listenEvent(descriptor, "meta", update);
return () => {
unlistenEvent(descriptor, "meta", update);
};
}, [descriptor]);
return data;
}

View File

@ -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,
};
}

View File

@ -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);
};

View File

@ -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;
};

View File

@ -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<HTMLDivElement>(null);
@ -31,12 +26,21 @@ import { VideoPlayerBase } from "@/video/components/VideoPlayerBase";
export function TestView() {
return (
<VideoPlayer>
<VideoPlayer onGoBack={() => alert("hello world")}>
<SourceController
quality={MWStreamQuality.QUNKNOWN}
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"
type={MWStreamType.MP4}
/>
<MetaController
meta={{
id: "test",
title: "Hello world",
type: MWMediaType.MOVIE,
year: "1234",
seasons: undefined,
}}
/>
</VideoPlayer>
);
}

View File

@ -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) {
<Helmet>
<html data-full="true" />
</Helmet>
<DecoratedVideoPlayer media={props.meta} onGoBack={goBack} autoPlay>
<SourceControl
<VideoPlayer onGoBack={goBack}>
<MetaController meta={props.meta.meta} />
<SourceController
source={props.stream.streamUrl}
type={props.stream.type}
quality={props.stream.quality}
/>
<ProgressListenerControl
{/* <ProgressListenerControl
startAt={firstStartTime.current}
onProgress={updateProgress}
/>
{props.selected.type === MWMediaType.SERIES &&
/> */}
{/* {props.selected.type === MWMediaType.SERIES &&
props.meta.meta.type === MWMediaType.SERIES ? (
<ShowControl
series={{
@ -138,8 +138,8 @@ export function MediaViewPlayer(props: MediaViewPlayerProps) {
seasonData={props.meta.meta.seasonData}
seasons={props.meta.meta.seasons}
/>
) : null}
</DecoratedVideoPlayer>
) : null} */}
</VideoPlayer>
</div>
);
}