mirror of
https://github.com/myronblair/kino-app
synced 2026-07-28 05:23:45 -05:00
81 lines
2.5 KiB
React
81 lines
2.5 KiB
React
import { useEffect, useRef, useState } from "react";
|
|
import { useNavigate, useParams } from "react-router-dom";
|
|
import api, { getStreamUrl } from "../lib/api";
|
|
import { ArrowLeft } from "lucide-react";
|
|
|
|
export default function Player() {
|
|
const { id } = useParams();
|
|
const nav = useNavigate();
|
|
const [movie, setMovie] = useState(null);
|
|
const videoRef = useRef(null);
|
|
const lastSent = useRef(0);
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
(async () => {
|
|
const { data } = await api.get(`/movies/${id}`);
|
|
if (cancelled) return;
|
|
setMovie(data);
|
|
// Restore progress
|
|
try {
|
|
const { data: p } = await api.get(`/progress/${id}`);
|
|
if (videoRef.current && p?.position_seconds) {
|
|
videoRef.current.currentTime = p.position_seconds;
|
|
}
|
|
} catch {}
|
|
})();
|
|
return () => { cancelled = true; };
|
|
}, [id]);
|
|
|
|
const onTimeUpdate = () => {
|
|
const v = videoRef.current;
|
|
if (!v || !v.duration) return;
|
|
const now = Date.now();
|
|
if (now - lastSent.current < 5000) return;
|
|
lastSent.current = now;
|
|
api.post("/progress", {
|
|
movie_id: id,
|
|
position_seconds: v.currentTime,
|
|
duration_seconds: v.duration,
|
|
}).catch(() => {});
|
|
};
|
|
|
|
if (!movie) {
|
|
return (
|
|
<div className="min-h-screen bg-black flex items-center justify-center text-[#8A8A8A]" data-testid="player-loading">
|
|
Loading…
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="fixed inset-0 bg-black z-50 flex flex-col" data-testid="player-page">
|
|
<button
|
|
onClick={() => nav(-1)}
|
|
className="absolute top-6 left-6 z-10 flex items-center gap-2 text-white/80 hover:text-white bg-black/60 hover:bg-black px-4 py-2 transition-colors duration-300"
|
|
data-testid="player-back-button"
|
|
>
|
|
<ArrowLeft size={16} strokeWidth={1.5} />
|
|
<span className="text-xs uppercase tracking-[0.2em]">Back</span>
|
|
</button>
|
|
|
|
<div className="absolute top-6 right-6 z-10 text-right">
|
|
<h2 className="font-display text-xl text-white tracking-tight" data-testid="player-title">
|
|
{movie.title}
|
|
</h2>
|
|
<p className="text-[10px] uppercase tracking-[0.3em] text-[#8A8A8A]">{movie.year} · {movie.rating}</p>
|
|
</div>
|
|
|
|
<video
|
|
ref={videoRef}
|
|
src={getStreamUrl(movie)}
|
|
controls
|
|
autoPlay
|
|
className="w-full h-full object-contain bg-black"
|
|
onTimeUpdate={onTimeUpdate}
|
|
data-testid="player-video"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|