47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
import Hls from 'hls.js'
|
|
import { useEffect, useRef } from 'react'
|
|
import { getAccessToken } from '@/shared/api/client'
|
|
import { cn } from '@/shared/lib/cn'
|
|
|
|
/**
|
|
* Мини-плеер HLS для админки: плейлист и сегменты лежат под admin-роутами (JWT), поэтому запросы
|
|
* идут через hls.js с Bearer-заголовком. Нативный путь (Safari) — только там, где hls.js не нужен.
|
|
*/
|
|
export function HlsVideo({ src, className }: { src: string; className?: string }) {
|
|
const videoRef = useRef<HTMLVideoElement>(null)
|
|
|
|
useEffect(() => {
|
|
const video = videoRef.current
|
|
if (!video) return
|
|
let hls: Hls | null = null
|
|
if (Hls.isSupported()) {
|
|
hls = new Hls({
|
|
xhrSetup: (xhr) => {
|
|
const token = getAccessToken()
|
|
if (token) xhr.setRequestHeader('Authorization', `Bearer ${token}`)
|
|
},
|
|
})
|
|
hls.loadSource(src)
|
|
hls.attachMedia(video)
|
|
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
|
video.src = src
|
|
}
|
|
return () => {
|
|
hls?.destroy()
|
|
}
|
|
}, [src])
|
|
|
|
return (
|
|
<video
|
|
ref={videoRef}
|
|
controls
|
|
playsInline
|
|
className={cn('aspect-video w-full rounded-md border border-border bg-black', className)}
|
|
>
|
|
{/* Субтитров пайплайн не производит: ffmpeg режет видео и звук, дорожек с текстом нет.
|
|
Пустой track объявляет это явно, вместо молчаливого отсутствия. */}
|
|
<track kind="captions" />
|
|
</video>
|
|
)
|
|
}
|