import { ScrapeMedia } from "@movie-web/providers"; import { useCallback, useEffect, useRef, useState } from "react"; import { MWStreamType } from "@/backend/helpers/streams"; import { usePlayer } from "@/components/player/hooks/usePlayer"; import { providers } from "@/utils/providers"; export interface ScrapingProps { media: ScrapeMedia; // onGetStream?: () => void; } export interface ScrapingSegment { name: string; id: string; status: "failure" | "pending" | "notfound" | "success" | "waiting"; reason?: string; percentage: number; } export interface ScrapingItems { id: string; children: string[]; } function useScrape() { const [sources, setSources] = useState>({}); const [sourceOrder, setSourceOrder] = useState([]); const startScraping = useCallback( async (media: ScrapeMedia) => { if (!providers) return; const output = await providers.runAll({ media, events: { init(evt) { setSources( evt.sourceIds .map((v) => { const source = providers.getMetadata(v); if (!source) throw new Error("invalid source id"); const out: ScrapingSegment = { name: source.name, id: source.id, status: "waiting", percentage: 0, }; return out; }) .reduce>((a, v) => { a[v.id] = v; return a; }, {}) ); setSourceOrder(evt.sourceIds.map((v) => ({ id: v, children: [] }))); }, start(id) { setSources((s) => { if (s[id]) s[id].status = "pending"; return { ...s }; }); }, update(evt) { setSources((s) => { if (s[evt.id]) { s[evt.id].status = evt.status; s[evt.id].reason = evt.reason; s[evt.id].percentage = evt.percentage; } return { ...s }; }); }, discoverEmbeds(evt) { setSources((s) => { evt.embeds.forEach((v) => { const source = providers.getMetadata(v.embedScraperId); if (!source) throw new Error("invalid source id"); const out: ScrapingSegment = { name: source.name, id: v.id, status: "waiting", percentage: 0, }; s[v.id] = out; }); return { ...s }; }); setSourceOrder((s) => { const source = s.find((v) => v.id === evt.sourceId); if (!source) throw new Error("invalid source id"); source.children = evt.embeds.map((v) => v.id); return [...s]; }); }, }, }); return output; }, [setSourceOrder, setSources] ); return { startScraping, sourceOrder, sources, }; } export function ScrapingPart(props: ScrapingProps) { const { playMedia } = usePlayer(); const { startScraping, sourceOrder, sources } = useScrape(); const started = useRef(false); useEffect(() => { if (started.current) return; started.current = true; (async () => { const output = await startScraping(props.media); if (output?.stream.type !== "file") return; const firstFile = Object.values(output.stream.qualities)[0]; playMedia({ type: MWStreamType.MP4, url: firstFile.url, }); })(); }, [startScraping, props, playMedia]); return (
{sourceOrder.map((order) => { const source = sources[order.id]; if (!source) return null; return (

{source.name}

status: {source.status} ({source.percentage}%)

reason: {source.reason}

{order.children.map((embedId) => { const embed = sources[embedId]; if (!embed) return null; return (

{embed.name}

status: {embed.status} ({embed.percentage}%)

reason: {embed.reason}

); })}
); })}
); }