import { useState, useCallback, useRef } from 'react';
import Hls from 'hls.js';
const BASE = 'https://missourimonster-vyla.hf.space';
type PlayerState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'playing'; sourceLabel: string }
| { status: 'error'; message: string };
export function useStreamPlayer(tmdbId: number) {
const [state, setState] = useState<PlayerState>({ status: 'idle' });
const hlsRef = useRef<Hls | null>(null);
const load = useCallback(async (videoEl: HTMLVideoElement) => {
setState({ status: 'loading' });
const queue: { url: string; label: string }[] = [];
let started = false;
function tryNext() {
if (!queue.length) {
setState({ status: 'error', message: 'All sources failed.' });
return;
}
const { url, label } = queue.shift()!;
hlsRef.current?.destroy();
const hls = new Hls();
hlsRef.current = hls;
hls.on(Hls.Events.MANIFEST_PARSED, () => {
setState({ status: 'playing', sourceLabel: label });
videoEl.play();
});
hls.on(Hls.Events.ERROR, (_, err) => {
if (err.fatal) { hls.destroy(); tryNext(); }
});
hls.loadSource(url);
hls.attachMedia(videoEl);
}
try {
const res = await fetch(`${BASE}/movie?id=${tmdbId}`);
const reader = res.body!.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop()!;
for (const line of lines) {
if (!line.startsWith('data: ')) continue;
const event = JSON.parse(line.slice(6));
if (event.type === 'source') {
queue.push({ url: event.source.url, label: event.source.label });
if (!started) { started = true; tryNext(); }
}
if (event.type === 'done' && !started) {
setState({ status: 'error', message: 'No sources available for this title.' });
}
}
}
} catch {
setState({ status: 'error', message: 'Network error. Check your connection.' });
}
}, [tmdbId]);
return { state, load };
}