feat: apply phase1 DX cleanup for private registry
This commit is contained in:
+25
-106
@@ -8,6 +8,7 @@ import { setupRtmpInstance } from '../utils/rtmpSetup'
|
||||
import { setupMpegtsInstance } from '../utils/mpegtsSetup'
|
||||
import { detectVideoProtocol } from '../utils/videoProtocol'
|
||||
import { createSubtitleBlobURL } from '../utils/subtitles'
|
||||
import { logger } from '../utils/logger'
|
||||
import './VideoElement.css'
|
||||
|
||||
interface VideoElementProps {
|
||||
@@ -112,7 +113,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
// Check if this is a live broadcast (duration is Infinity for live streams)
|
||||
const isLiveBroadcast = !isFinite(video.duration) || video.duration === 0
|
||||
console.log('[VideoElement] Is live broadcast?', isLiveBroadcast, 'duration:', video.duration)
|
||||
logger.log('[VideoElement] Is live broadcast?', isLiveBroadcast, 'duration:', video.duration)
|
||||
|
||||
setVideoState((prev) => ({
|
||||
...prev,
|
||||
@@ -127,7 +128,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
if (tracks && processedSubtitles.length > 0) {
|
||||
const defaultSubtitle = processedSubtitles.find((sub) => sub.default)
|
||||
if (defaultSubtitle) {
|
||||
console.log(`🎯 Found default subtitle in metadata: ${defaultSubtitle.label}`)
|
||||
logger.log(`🎯 Found default subtitle in metadata: ${defaultSubtitle.label}`)
|
||||
// Set subtitle in context (this will trigger the useEffect that enables it)
|
||||
setSubtitle(defaultSubtitle)
|
||||
}
|
||||
@@ -142,7 +143,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
// Re-check if this is a live broadcast when duration changes
|
||||
const isLiveBroadcast = !isFinite(video.duration) || video.duration === 0
|
||||
console.log('[VideoElement] Duration changed. Is live broadcast?', isLiveBroadcast, 'duration:', video.duration)
|
||||
logger.log('[VideoElement] Duration changed. Is live broadcast?', isLiveBroadcast, 'duration:', video.duration)
|
||||
|
||||
setVideoState((prev) => ({
|
||||
...prev,
|
||||
@@ -339,25 +340,16 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
throw new Error(`Failed to fetch subtitle: ${response.status} ${response.statusText}`)
|
||||
}
|
||||
const srtContent = await response.text()
|
||||
console.log(`SRT content length: ${srtContent.length} chars`)
|
||||
|
||||
const blobUrl = createSubtitleBlobURL(srtContent, 'srt')
|
||||
subtitleBlobUrlsRef.current.push(blobUrl)
|
||||
|
||||
// Debug: fetch the blob URL to verify VTT content
|
||||
const vttResponse = await fetch(blobUrl)
|
||||
const vttContent = await vttResponse.text()
|
||||
console.log(`VTT content preview (first 500 chars):`, vttContent.substring(0, 500))
|
||||
console.log(`Total VTT length: ${vttContent.length} chars`)
|
||||
|
||||
console.log(`Processed SRT subtitle "${subtitle.label}": ${subtitle.src} -> ${blobUrl}`)
|
||||
return { ...subtitle, src: blobUrl }
|
||||
}
|
||||
// VTT files can be used directly
|
||||
console.log(`Using VTT subtitle "${subtitle.label}": ${subtitle.src}`)
|
||||
return subtitle
|
||||
} catch (error) {
|
||||
console.error(`Failed to process subtitle ${subtitle.label}:`, error)
|
||||
logger.error(`Failed to process subtitle ${subtitle.label}:`, error)
|
||||
return subtitle
|
||||
}
|
||||
})
|
||||
@@ -459,10 +451,10 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[VideoElement] Source:', src)
|
||||
console.log('[VideoElement] Detected protocol:', detection.protocol)
|
||||
console.log('[VideoElement] Is live stream?', detection.isLive)
|
||||
console.log('[VideoElement] Needs special player?', detection.needsSpecialPlayer)
|
||||
logger.log('[VideoElement] Source:', src)
|
||||
logger.log('[VideoElement] Detected protocol:', detection.protocol)
|
||||
logger.log('[VideoElement] Is live stream?', detection.isLive)
|
||||
logger.log('[VideoElement] Needs special player?', detection.needsSpecialPlayer)
|
||||
|
||||
const setupPlayer = async () => {
|
||||
try {
|
||||
@@ -473,12 +465,12 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
||||
const shouldUseHlsJs = canPlayHLS === '' || !isSafari
|
||||
|
||||
console.log('[VideoElement] Native HLS support?', canPlayHLS)
|
||||
console.log('[VideoElement] Is Safari?', isSafari)
|
||||
console.log('[VideoElement] Will use HLS.js?', shouldUseHlsJs)
|
||||
logger.log('[VideoElement] Native HLS support?', canPlayHLS)
|
||||
logger.log('[VideoElement] Is Safari?', isSafari)
|
||||
logger.log('[VideoElement] Will use HLS.js?', shouldUseHlsJs)
|
||||
|
||||
if (shouldUseHlsJs) {
|
||||
console.log('[VideoElement] Setting up HLS.js...')
|
||||
logger.log('[VideoElement] Setting up HLS.js...')
|
||||
cleanupFn = await setupHlsInstance({
|
||||
video,
|
||||
src,
|
||||
@@ -507,7 +499,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
}
|
||||
} else {
|
||||
if (isCancelled) return
|
||||
console.log('[VideoElement] Using native HLS playback')
|
||||
logger.log('[VideoElement] Using native HLS playback')
|
||||
video.src = src
|
||||
if (autoplay) {
|
||||
void video.play().catch(() => undefined)
|
||||
@@ -518,7 +510,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
case 'rtmp': {
|
||||
// RTMP/FLV streaming setup
|
||||
console.log('[VideoElement] Setting up RTMP/FLV player...')
|
||||
logger.log('[VideoElement] Setting up RTMP/FLV player...')
|
||||
cleanupFn = await setupRtmpInstance({
|
||||
video,
|
||||
src,
|
||||
@@ -536,7 +528,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
case 'mpegts': {
|
||||
// MPEG-TS/IPTV streaming setup
|
||||
console.log('[VideoElement] Setting up MPEG-TS player...')
|
||||
logger.log('[VideoElement] Setting up MPEG-TS player...')
|
||||
cleanupFn = await setupMpegtsInstance({
|
||||
video,
|
||||
src,
|
||||
@@ -556,7 +548,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
// DASH streaming - not yet implemented
|
||||
if (isCancelled) return
|
||||
const error = new Error('DASH streaming is not yet supported')
|
||||
console.error('[VideoElement]', error.message)
|
||||
logger.error('[VideoElement]', error.message)
|
||||
setVideoState((prev) => ({ ...prev, error, loading: false }))
|
||||
onError?.(error)
|
||||
break
|
||||
@@ -566,7 +558,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
default: {
|
||||
// Native HTML5 video (MP4, WebM, etc.)
|
||||
if (isCancelled) return
|
||||
console.log('[VideoElement] Using native video.src')
|
||||
logger.log('[VideoElement] Using native video.src')
|
||||
video.src = src
|
||||
if (autoplay) {
|
||||
void video.play().catch(() => undefined)
|
||||
@@ -585,7 +577,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
if (isCancelled) return
|
||||
|
||||
console.error('[VideoElement] Setup error:', error)
|
||||
logger.error('[VideoElement] Setup error:', error)
|
||||
setVideoState((prev) => ({
|
||||
...prev,
|
||||
error,
|
||||
@@ -728,11 +720,11 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
// Wait for track to have cues before showing
|
||||
if (track.cues && track.cues.length > 0) {
|
||||
track.mode = 'showing'
|
||||
console.log(`🔊 Enabled subtitle track: ${track.label} (${track.language})`)
|
||||
console.log(` - cues available: ${track.cues.length}`)
|
||||
console.log(` - track.mode: ${track.mode}`)
|
||||
logger.log(`🔊 Enabled subtitle track: ${track.label} (${track.language})`)
|
||||
logger.log(` - cues available: ${track.cues.length}`)
|
||||
logger.log(` - track.mode: ${track.mode}`)
|
||||
} else {
|
||||
console.warn(`⚠️ Track ${track.label} has no cues yet, waiting...`)
|
||||
logger.warn(`⚠️ Track ${track.label} has no cues yet, waiting...`)
|
||||
// Track not ready yet, will be handled by load event
|
||||
track.mode = 'showing'
|
||||
}
|
||||
@@ -747,7 +739,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
|
||||
// Also listen for track load events to retry
|
||||
const handleTrackChange = () => {
|
||||
console.log(`🔄 Track changed, re-enabling subtitle`)
|
||||
logger.log(`🔄 Track changed, re-enabling subtitle`)
|
||||
enableSubtitle()
|
||||
}
|
||||
|
||||
@@ -762,80 +754,6 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
}
|
||||
}, [settings.subtitle, videoRef])
|
||||
|
||||
// Debug: Monitor text track loading
|
||||
useEffect(() => {
|
||||
const video = videoRef.current
|
||||
if (!video) return
|
||||
|
||||
const handleTrackLoad = (e: Event) => {
|
||||
const track = e.target as HTMLTrackElement
|
||||
const textTrack = track.track
|
||||
console.log(`✅ Track loaded: ${track.label} (${track.srclang})`)
|
||||
console.log(` - readyState: ${track.readyState}`)
|
||||
console.log(` - track.mode: ${textTrack.mode}`)
|
||||
console.log(` - track.cues: ${textTrack.cues?.length || 0}`)
|
||||
console.log(` - src: ${track.src}`)
|
||||
|
||||
// Log first few cues if available
|
||||
if (textTrack.cues && textTrack.cues.length > 0) {
|
||||
console.log(` - First cue: ${(textTrack.cues[0] as VTTCue).startTime}s - ${(textTrack.cues[0] as VTTCue).endTime}s: "${(textTrack.cues[0] as VTTCue).text}"`)
|
||||
} else {
|
||||
console.warn(` ⚠️ No cues found in track!`)
|
||||
}
|
||||
}
|
||||
|
||||
const handleTrackError = (e: Event) => {
|
||||
const track = e.target as HTMLTrackElement
|
||||
console.error(`❌ Track error: ${track.label} (${track.srclang})`)
|
||||
console.error(` - src: ${track.src}`)
|
||||
console.error(` - readyState: ${track.readyState}`)
|
||||
}
|
||||
|
||||
const trackElements = video.querySelectorAll('track')
|
||||
trackElements.forEach((track) => {
|
||||
track.addEventListener('load', handleTrackLoad)
|
||||
track.addEventListener('error', handleTrackError)
|
||||
})
|
||||
|
||||
// Also monitor text tracks
|
||||
const textTracks = video.textTracks
|
||||
const handleCueChange = () => {
|
||||
for (let i = 0; i < textTracks.length; i++) {
|
||||
const track = textTracks[i]
|
||||
if (track.mode === 'showing') {
|
||||
console.log(`🎬 Cuechange: ${track.label}, cues: ${track.cues?.length || 0}, active cues: ${track.activeCues?.length || 0}`)
|
||||
if (track.activeCues && track.activeCues.length > 0) {
|
||||
const cue = track.activeCues[0] as VTTCue
|
||||
console.log(` - Active cue text: "${cue.text}"`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < textTracks.length; i++) {
|
||||
textTracks[i].addEventListener('cuechange', handleCueChange)
|
||||
}
|
||||
|
||||
// Log all text tracks after a delay to see their state
|
||||
setTimeout(() => {
|
||||
console.log(`📊 Text tracks summary (${textTracks.length} total):`)
|
||||
for (let i = 0; i < textTracks.length; i++) {
|
||||
const track = textTracks[i]
|
||||
console.log(` [${i}] ${track.label} (${track.language}): mode=${track.mode}, cues=${track.cues?.length || 0}`)
|
||||
}
|
||||
}, 1000)
|
||||
|
||||
return () => {
|
||||
trackElements.forEach((track) => {
|
||||
track.removeEventListener('load', handleTrackLoad)
|
||||
track.removeEventListener('error', handleTrackError)
|
||||
})
|
||||
for (let i = 0; i < textTracks.length; i++) {
|
||||
textTracks[i].removeEventListener('cuechange', handleCueChange)
|
||||
}
|
||||
}
|
||||
}, [videoRef, processedSubtitles])
|
||||
|
||||
return (
|
||||
<div className="video-container">
|
||||
<video
|
||||
@@ -876,3 +794,4 @@ export const VideoElement: React.FC<VideoElementProps> = ({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user