59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
'use client';
|
|
import React, { useEffect, useRef } from 'react';
|
|
import { Radio } from 'lucide-react';
|
|
|
|
interface Props {
|
|
hlsUrl?: string;
|
|
thumbnailUrl?: string;
|
|
}
|
|
|
|
export default function VideoPlayer({ hlsUrl, thumbnailUrl }: Props) {
|
|
const videoRef = useRef<HTMLVideoElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (!hlsUrl || !videoRef.current) return;
|
|
const video = videoRef.current;
|
|
|
|
if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
|
video.src = hlsUrl;
|
|
return;
|
|
}
|
|
|
|
import('hls.js').then(({ default: Hls }) => {
|
|
if (Hls.isSupported()) {
|
|
const hls = new Hls();
|
|
hls.loadSource(hlsUrl);
|
|
hls.attachMedia(video);
|
|
return () => hls.destroy();
|
|
}
|
|
});
|
|
}, [hlsUrl]);
|
|
|
|
if (!hlsUrl) {
|
|
return (
|
|
<div className="relative aspect-video bg-black/40 rounded-2xl border border-white/5 flex flex-col items-center justify-center gap-4 text-stone-500">
|
|
<Radio size={48} className="text-stone-600" />
|
|
<p className="text-sm font-medium">Stream offline — no source available</p>
|
|
{thumbnailUrl && (
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
<img src={thumbnailUrl} alt="Stream thumbnail" className="absolute inset-0 w-full h-full object-cover rounded-2xl opacity-20" />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="relative aspect-video rounded-2xl overflow-hidden bg-black shadow-2xl shadow-black/60">
|
|
<video
|
|
ref={videoRef}
|
|
controls
|
|
autoPlay
|
|
muted
|
|
playsInline
|
|
className="w-full h-full"
|
|
poster={thumbnailUrl}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|