Initial commit — StreamStack v1
Five-service streaming platform: auth, catalogue, streaming, ingest, thumbnailer. Includes React frontend served by nginx, NATS JetStream event bus, aiobotocore async S3, PyAV video metadata + thumbnail extraction, service-to-service JWT auth, and a full unit + e2e test suite.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { getStreamToken } from '../api'
|
||||
|
||||
export default function VideoPlayer({ item, jwt, onClose }) {
|
||||
const [src, setSrc] = useState(null)
|
||||
const [error, setError] = useState(null)
|
||||
const videoRef = useRef(null)
|
||||
|
||||
useEffect(() => {
|
||||
getStreamToken(item.id, jwt)
|
||||
.then(url => setSrc(url))
|
||||
.catch(e => setError(e.message))
|
||||
}, [item.id, jwt])
|
||||
|
||||
useEffect(() => {
|
||||
if (src && videoRef.current) {
|
||||
videoRef.current.play().catch(() => {})
|
||||
videoRef.current.requestFullscreen?.().catch(() => {})
|
||||
}
|
||||
}, [src])
|
||||
|
||||
return (
|
||||
<div className="player-overlay" onClick={onClose}>
|
||||
<div className="player-box" onClick={e => e.stopPropagation()}>
|
||||
<button className="player-close" onClick={onClose}>✕</button>
|
||||
<h2>{item.title}</h2>
|
||||
{error && <p className="error">{error}</p>}
|
||||
{src ? (
|
||||
<video
|
||||
ref={videoRef}
|
||||
src={src}
|
||||
controls
|
||||
className="player-video"
|
||||
/>
|
||||
) : (
|
||||
!error && <p>Loading…</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user