import { RunOutput } from "@movie-web/providers"; import { useCallback, useEffect, useState } from "react"; import { Navigate, useLocation, useNavigate, useParams, } from "react-router-dom"; import { useAsync } from "react-use"; import { usePlayer } from "@/components/player/hooks/usePlayer"; import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta"; import { convertProviderCaption } from "@/components/player/utils/captions"; import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource"; import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape"; import { useQueryParam } from "@/hooks/useQueryParams"; import { MetaPart } from "@/pages/parts/player/MetaPart"; import { PlaybackErrorPart } from "@/pages/parts/player/PlaybackErrorPart"; import { PlayerPart } from "@/pages/parts/player/PlayerPart"; import { ScrapeErrorPart } from "@/pages/parts/player/ScrapeErrorPart"; import { ScrapingPart } from "@/pages/parts/player/ScrapingPart"; import { useLastNonPlayerLink } from "@/stores/history"; import { PlayerMeta, playerStatus } from "@/stores/player/slices/source"; import { needsOnboarding } from "@/utils/onboarding"; import { parseTimestamp } from "@/utils/timestamp"; export function RealPlayerView() { const navigate = useNavigate(); const params = useParams<{ media: string; episode?: string; season?: string; }>(); const [errorData, setErrorData] = useState<{ sources: Record; sourceOrder: ScrapingItems[]; } | null>(null); const [startAtParam] = useQueryParam("t"); const { status, playMedia, reset, setScrapeNotFound, shouldStartFromBeginning, setShouldStartFromBeginning, } = usePlayer(); const { setPlayerMeta, scrapeMedia } = usePlayerMeta(); const backUrl = useLastNonPlayerLink(); const paramsData = JSON.stringify({ media: params.media, season: params.season, episode: params.episode, }); useEffect(() => { reset(); }, [paramsData, reset]); const metaChange = useCallback( (meta: PlayerMeta) => { if (meta?.type === "show") navigate( `/media/${params.media}/${meta.season?.tmdbId}/${meta.episode?.tmdbId}`, ); else navigate(`/media/${params.media}`); }, [navigate, params], ); const playAfterScrape = useCallback( (out: RunOutput | null) => { if (!out) return; let startAt: number | undefined; if (startAtParam) startAt = parseTimestamp(startAtParam) ?? undefined; playMedia( convertRunoutputToSource(out), convertProviderCaption(out.stream.captions), out.sourceId, shouldStartFromBeginning ? 0 : startAt, ); setShouldStartFromBeginning(false); }, [ playMedia, startAtParam, shouldStartFromBeginning, setShouldStartFromBeginning, ], ); return ( {status === playerStatus.IDLE ? ( ) : null} {status === playerStatus.SCRAPING && scrapeMedia ? ( { setErrorData({ sourceOrder, sources, }); setScrapeNotFound(); }} onGetStream={playAfterScrape} /> ) : null} {status === playerStatus.SCRAPE_NOT_FOUND && errorData ? ( ) : null} {status === playerStatus.PLAYBACK_ERROR ? : null} ); } export function PlayerView() { const loc = useLocation(); const { loading, error, value } = useAsync(() => { return needsOnboarding(); }); if (error) throw new Error("Failed to detect onboarding"); if (loading) return null; if (value) return ( ); return ; } export default PlayerView;