Implement Tuner v1 — Go backend, React frontend, Docker setup
- Go backend: REST API, M3U parser, FFmpeg/MediaMTX process manager - React/Vite frontend: HLS player, admin panel, channel browser (dark theme) - MediaMTX config for RTMP ingest + HLS output - Multi-stage Dockerfile (Go + Bun + Alpine runtime) - docker-compose.yml for single-container deployment - Sample M3U playlist with test streams Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
55
frontend/src/components/Player.tsx
Normal file
55
frontend/src/components/Player.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import Hls from "hls.js";
|
||||
|
||||
export default function Player() {
|
||||
const videoRef = useRef<HTMLVideoElement>(null);
|
||||
const hlsRef = useRef<Hls | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const video = videoRef.current;
|
||||
if (!video) return;
|
||||
|
||||
const src = `http://${window.location.hostname}:8888/live/stream/`;
|
||||
|
||||
if (Hls.isSupported()) {
|
||||
const hls = new Hls({
|
||||
enableWorker: true,
|
||||
lowLatencyMode: true,
|
||||
});
|
||||
hlsRef.current = hls;
|
||||
hls.loadSource(src);
|
||||
hls.attachMedia(video);
|
||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||
video.play().catch(() => {});
|
||||
});
|
||||
hls.on(Hls.Events.ERROR, (_event, data) => {
|
||||
if (data.fatal) {
|
||||
if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
|
||||
setTimeout(() => hls.loadSource(src), 5000);
|
||||
} else {
|
||||
hls.destroy();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (video.canPlayType("application/vnd.apple.mpegurl")) {
|
||||
video.src = src;
|
||||
video.addEventListener("loadedmetadata", () => {
|
||||
video.play().catch(() => {});
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (hlsRef.current) {
|
||||
hlsRef.current.destroy();
|
||||
hlsRef.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="player-container">
|
||||
<video ref={videoRef} className="player-video" controls playsInline />
|
||||
<div className="player-offline">Stream Offline</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user