refactor: strip debug noise to reduce bundle

This commit is contained in:
Mert Uyanık
2025-10-29 09:06:29 +03:00
parent a00cfe2249
commit 60adb36721
7 changed files with 51 additions and 95 deletions
+9 -35
View File
@@ -131,12 +131,12 @@ export const VideoElement: React.FC<VideoElementProps> = ({
// Check if it's a CORS-related error // Check if it's a CORS-related error
const videoError = video.error const videoError = video.error
if (videoError.code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED || if (
videoError.code === MediaError.MEDIA_ERR_NETWORK) { videoError.code === MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED ||
videoError.code === MediaError.MEDIA_ERR_NETWORK
) {
// Could be a CORS issue // Could be a CORS issue
const corsMessage = getCORSErrorMessage(video.src || src) errorMessage = getCORSErrorMessage(video.src || src)
console.error(corsMessage)
errorMessage = `Failed to load video. This might be a CORS issue. Check console for details.`
} }
const error = new Error(errorMessage) const error = new Error(errorMessage)
@@ -153,13 +153,11 @@ export const VideoElement: React.FC<VideoElementProps> = ({
if (timeSinceLastClick < 300) { if (timeSinceLastClick < 300) {
// Double click - toggle fullscreen // Double click - toggle fullscreen
e.preventDefault() e.preventDefault()
console.log('🖱️ [Video Click] Double-click detected, toggling fullscreen')
toggleFullscreen() toggleFullscreen()
lastClickTimeRef.current = 0 lastClickTimeRef.current = 0
} else { } else {
// Single click - record time // Single click - record time
lastClickTimeRef.current = now lastClickTimeRef.current = now
console.log('🖱️ [Video Click] Single click detected')
} }
}, },
[toggleFullscreen] [toggleFullscreen]
@@ -208,11 +206,6 @@ export const VideoElement: React.FC<VideoElementProps> = ({
return return
} }
// Log warning if external URL
if (validation.warning) {
console.warn(`⚠️ [Video] ${validation.warning}`)
}
const isHLS = src.includes('.m3u8') const isHLS = src.includes('.m3u8')
let cleanupFn: (() => void) | null = null let cleanupFn: (() => void) | null = null
@@ -237,54 +230,41 @@ export const VideoElement: React.FC<VideoElementProps> = ({
hls.attachMedia(video) hls.attachMedia(video)
hls.on(Hls.Events.MANIFEST_PARSED, () => { hls.on(Hls.Events.MANIFEST_PARSED, () => {
console.log('✅ [HLS] Manifest parsed successfully')
// Extract audio tracks after manifest is parsed // Extract audio tracks after manifest is parsed
// Sometimes audio tracks are not immediately available, so we try with a small delay // Sometimes audio tracks are not immediately available, so we try with a small delay
setTimeout(() => { setTimeout(() => {
const tracks = getHlsAudioTracks(hls) const tracks = getHlsAudioTracks(hls)
if (tracks.length > 0) { if (tracks.length > 0) {
console.log(`✅ [HLS] Found ${tracks.length} audio tracks:`, tracks)
setAvailableAudioTracks(tracks) setAvailableAudioTracks(tracks)
onAudioTracksLoaded?.(tracks) onAudioTracksLoaded?.(tracks)
} else {
console.log('️ [HLS] No audio tracks found in manifest')
} }
}, 100) }, 100)
if (autoplay) { if (autoplay) {
video.play().catch((err) => { void video.play().catch(() => undefined)
console.warn('⚠️ [HLS] Autoplay prevented:', err)
})
} }
}) })
// Also listen to audio track updates // Also listen to audio track updates
hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, (_event: any, data: any) => { hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, () => {
console.log('🔄 [HLS] Audio tracks updated:', data)
const tracks = getHlsAudioTracks(hls) const tracks = getHlsAudioTracks(hls)
if (tracks.length > 0) { if (tracks.length > 0) {
console.log(`✅ [HLS] Found ${tracks.length} audio tracks after update:`, tracks)
setAvailableAudioTracks(tracks) setAvailableAudioTracks(tracks)
onAudioTracksLoaded?.(tracks) onAudioTracksLoaded?.(tracks)
} }
}) })
hls.on(Hls.Events.ERROR, (_event: any, data: any) => { hls.on(Hls.Events.ERROR, (_event: any, data: any) => {
console.error('❌ [HLS] Error:', data)
if (data.fatal) { if (data.fatal) {
switch (data.type) { switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR: case Hls.ErrorTypes.NETWORK_ERROR:
console.error('❌ [HLS] Fatal network error, trying to recover...')
hls.startLoad() hls.startLoad()
break break
case Hls.ErrorTypes.MEDIA_ERROR: case Hls.ErrorTypes.MEDIA_ERROR:
console.error('❌ [HLS] Fatal media error, trying to recover...')
hls.recoverMediaError() hls.recoverMediaError()
break break
default: default:
console.error('❌ [HLS] Fatal error, cannot recover')
handleError() handleError()
break break
} }
@@ -296,19 +276,16 @@ export const VideoElement: React.FC<VideoElementProps> = ({
// Setup cleanup function // Setup cleanup function
cleanupFn = () => { cleanupFn = () => {
console.log('🧹 [HLS] Cleaning up HLS instance...')
if (hls) { if (hls) {
hls.destroy() hls.destroy()
} }
delete (video as any).__hlsInstance delete (video as any).__hlsInstance
} }
} catch (err) { } catch (err) {
console.error('❌ [HLS] Failed to load or initialize hls.js:', err)
let error: Error let error: Error
if (err instanceof Error && isCORSError(err)) { if (err instanceof Error && isCORSError(err)) {
const corsMessage = getCORSErrorMessage(src) const corsMessage = getCORSErrorMessage(src)
console.error(corsMessage) error = new Error(corsMessage)
error = new Error('Failed to load HLS stream. This might be a CORS issue. Check console for details.')
} else { } else {
error = err instanceof Error ? err : new Error('Failed to load HLS') error = err instanceof Error ? err : new Error('Failed to load HLS')
} }
@@ -323,9 +300,7 @@ export const VideoElement: React.FC<VideoElementProps> = ({
// Native support or regular video // Native support or regular video
video.src = src video.src = src
if (autoplay) { if (autoplay) {
video.play().catch((err) => { void video.play().catch(() => undefined)
console.warn('⚠️ [Video] Autoplay prevented:', err)
})
} }
} }
} }
@@ -363,7 +338,6 @@ export const VideoElement: React.FC<VideoElementProps> = ({
if (trackIndex !== -1) { if (trackIndex !== -1) {
setHlsAudioTrack(hlsInstance, trackIndex) setHlsAudioTrack(hlsInstance, trackIndex)
console.log(`✅ [Video] Audio track changed to: ${settings.audioTrack.name}`)
} }
}, [settings.audioTrack, availableAudioTracks, videoRef]) }, [settings.audioTrack, availableAudioTracks, videoRef])
+3 -1
View File
@@ -126,7 +126,9 @@ export const PlayerProvider: React.FC<PlayerProviderProps> = ({
try { try {
await videoRef.current?.requestPictureInPicture() await videoRef.current?.requestPictureInPicture()
} catch (error) { } catch (error) {
console.error('PIP error:', error) if (error instanceof Error) {
setVideoState((prev) => ({ ...prev, error }))
}
} }
} else { } else {
await document.exitPictureInPicture() await document.exitPictureInPicture()
+7 -8
View File
@@ -6,6 +6,7 @@ export interface CORSCheckResult {
supported: boolean supported: boolean
error?: string error?: string
needsProxy: boolean needsProxy: boolean
supportsRange?: boolean
} }
/** /**
@@ -21,6 +22,7 @@ export const checkVideoCORS = async (url: string): Promise<CORSCheckResult> => {
const corsHeader = response.headers.get('Access-Control-Allow-Origin') const corsHeader = response.headers.get('Access-Control-Allow-Origin')
const rangeHeader = response.headers.get('Accept-Ranges') const rangeHeader = response.headers.get('Accept-Ranges')
const supportsRange = !!rangeHeader && rangeHeader !== 'none'
if (!corsHeader && !response.ok) { if (!corsHeader && !response.ok) {
return { return {
@@ -30,14 +32,11 @@ export const checkVideoCORS = async (url: string): Promise<CORSCheckResult> => {
} }
} }
if (!rangeHeader || rangeHeader === 'none') { return {
console.warn('⚠️ [CORS] Server does not support Range Requests. Seeking may not work properly.') supported: true,
} needsProxy: false,
supportsRange,
return { }
supported: true,
needsProxy: false,
}
} catch (error) { } catch (error) {
// CORS error or network error // CORS error or network error
if (error instanceof TypeError && error.message.includes('CORS')) { if (error instanceof TypeError && error.message.includes('CORS')) {
+8 -27
View File
@@ -24,7 +24,6 @@ const loadHlsFromCDN = (): Promise<any> => {
script.onload = () => { script.onload = () => {
if (typeof (window as any).Hls !== 'undefined') { if (typeof (window as any).Hls !== 'undefined') {
console.log('✅ [HLS Loader] Loaded hls.js from CDN')
resolve((window as any).Hls) resolve((window as any).Hls)
} else { } else {
reject(new Error('HLS.js CDN loaded but Hls global not found')) reject(new Error('HLS.js CDN loaded but Hls global not found'))
@@ -45,19 +44,14 @@ const loadHlsFromCDN = (): Promise<any> => {
export const loadHls = async (): Promise<any> => { export const loadHls = async (): Promise<any> => {
try { try {
// Try loading from npm package first // Try loading from npm package first
console.log('🔄 [HLS Loader] Attempting to load hls.js from npm package...')
const hlsModule = await import('hls.js') const hlsModule = await import('hls.js')
console.log('✅ [HLS Loader] Loaded hls.js from npm package')
return hlsModule.default return hlsModule.default
} catch (npmError) { } catch (npmError) {
console.warn('⚠️ [HLS Loader] Failed to load hls.js from npm, trying CDN fallback...', npmError)
try { try {
// Fallback to CDN // Fallback to CDN
const Hls = await loadHlsFromCDN() const Hls = await loadHlsFromCDN()
return Hls return Hls
} catch (cdnError) { } catch (cdnError) {
console.error('❌ [HLS Loader] Failed to load hls.js from both npm and CDN', cdnError)
throw new Error('Unable to load HLS.js library. HLS streaming is not available.') throw new Error('Unable to load HLS.js library. HLS streaming is not available.')
} }
} }
@@ -84,18 +78,14 @@ export const hasNativeHlsSupport = (): boolean => {
export const getHlsAudioTracks = (hls: any): AudioTrack[] => { export const getHlsAudioTracks = (hls: any): AudioTrack[] => {
try { try {
if (!hls) { if (!hls) {
console.warn('⚠️ [HLS Loader] HLS instance is null or undefined')
return [] return []
} }
// Check if audioTracks property exists // Check if audioTracks property exists
if (!hls.audioTracks || !Array.isArray(hls.audioTracks)) { if (!hls.audioTracks || !Array.isArray(hls.audioTracks)) {
console.warn('⚠️ [HLS Loader] audioTracks not available or not an array:', hls.audioTracks)
return [] return []
} }
console.log('🔍 [HLS Loader] Raw audio tracks from HLS:', hls.audioTracks)
const audioTracks: AudioTrack[] = hls.audioTracks.map((track: any, index: number) => { const audioTracks: AudioTrack[] = hls.audioTracks.map((track: any, index: number) => {
const audioTrack = { const audioTrack = {
name: track.name || track.label || `Audio ${index + 1}`, name: track.name || track.label || `Audio ${index + 1}`,
@@ -105,13 +95,11 @@ export const getHlsAudioTracks = (hls: any): AudioTrack[] => {
default: track.default || false, default: track.default || false,
autoselect: track.autoselect || false, autoselect: track.autoselect || false,
} }
console.log(`🎵 [HLS Loader] Parsed audio track ${index}:`, audioTrack)
return audioTrack return audioTrack
}) })
return audioTracks return audioTracks
} catch (error) { } catch (error) {
console.error('❌ [HLS Loader] Error extracting audio tracks:', error)
return [] return []
} }
} }
@@ -120,20 +108,13 @@ export const getHlsAudioTracks = (hls: any): AudioTrack[] => {
* Set active audio track in HLS instance * Set active audio track in HLS instance
*/ */
export const setHlsAudioTrack = (hls: any, audioTrackIndex: number): void => { export const setHlsAudioTrack = (hls: any, audioTrackIndex: number): void => {
try { if (!hls || !hls.audioTracks) {
if (!hls || !hls.audioTracks) { return
console.warn('⚠️ [HLS Loader] HLS instance or audioTracks not available')
return
}
if (audioTrackIndex < 0 || audioTrackIndex >= hls.audioTracks.length) {
console.warn('⚠️ [HLS Loader] Invalid audio track index:', audioTrackIndex)
return
}
hls.audioTrack = audioTrackIndex
console.log(`✅ [HLS Loader] Audio track set to index ${audioTrackIndex}`)
} catch (error) {
console.error('❌ [HLS Loader] Error setting audio track:', error)
} }
if (audioTrackIndex < 0 || audioTrackIndex >= hls.audioTracks.length) {
return
}
hls.audioTrack = audioTrackIndex
} }
+2 -5
View File
@@ -57,7 +57,6 @@ const parseAudioMediaTag = (line: string): AudioTrack | null => {
const autoselect = attributes['AUTOSELECT'] === 'YES' const autoselect = attributes['AUTOSELECT'] === 'YES'
if (!name || !uri) { if (!name || !uri) {
console.warn('⚠️ [M3U8 Parser] Audio track missing NAME or URI:', line)
return null return null
} }
@@ -69,8 +68,7 @@ const parseAudioMediaTag = (line: string): AudioTrack | null => {
default: defaultTrack, default: defaultTrack,
autoselect, autoselect,
} }
} catch (error) { } catch {
console.error('❌ [M3U8 Parser] Error parsing audio track:', line, error)
return null return null
} }
} }
@@ -87,8 +85,7 @@ export const fetchAndParseM3U8 = async (url: string): Promise<AudioTrack[]> => {
const manifestContent = await response.text() const manifestContent = await response.text()
return parseM3U8AudioTracks(manifestContent) return parseM3U8AudioTracks(manifestContent)
} catch (error) { } catch {
console.error('❌ [M3U8 Parser] Error fetching M3U8:', error)
return [] return []
} }
} }
+15 -7
View File
@@ -87,29 +87,37 @@ export const checkFetchSupport = (): boolean => {
* Initialize all polyfills * Initialize all polyfills
* Call this once when the app loads * Call this once when the app loads
*/ */
export const initializePolyfills = () => { export interface PolyfillDiagnostics {
warnings: string[]
errors: string[]
}
export const initializePolyfills = (): PolyfillDiagnostics => {
const warnings: string[] = []
const errors: string[] = []
try { try {
setupFullscreenPolyfill() setupFullscreenPolyfill()
setupPIPPolyfill() setupPIPPolyfill()
// Check critical API support // Check critical API support
if (!checkPromiseSupport()) { if (!checkPromiseSupport()) {
console.warn('[VideoPlayer] Promise not supported. Please add Promise polyfill.') warnings.push('Promise not supported. Please add a Promise polyfill for full compatibility.')
} }
if (!checkFetchSupport()) { if (!checkFetchSupport()) {
console.warn('[VideoPlayer] Fetch API not supported. Subtitle loading may fail.') warnings.push('Fetch API not supported. Subtitle loading may fail without a fetch polyfill.')
} }
// Check for MediaSource API (required for HLS.js) // Check for MediaSource API (required for HLS.js)
if (typeof MediaSource === 'undefined') { if (typeof MediaSource === 'undefined') {
console.warn('[VideoPlayer] MediaSource API not supported. HLS streaming will not work.') warnings.push('MediaSource API not supported. HLS streaming will not work on this browser.')
} }
console.log('✅ [VideoPlayer] Polyfills initialized successfully')
} catch (error) { } catch (error) {
console.error('[VideoPlayer] Error initializing polyfills:', error) errors.push(error instanceof Error ? error.message : String(error))
} }
return { warnings, errors }
} }
/** /**
+7 -12
View File
@@ -45,18 +45,13 @@ export const createSubtitleBlobURL = (content: string, format: 'vtt' | 'srt'): s
* Fetch and parse subtitle file * Fetch and parse subtitle file
*/ */
export const fetchSubtitle = async (url: string): Promise<string> => { export const fetchSubtitle = async (url: string): Promise<string> => {
try { const response = await fetch(url)
const response = await fetch(url) const content = await response.text()
const content = await response.text()
// Detect format // Detect format
if (url.endsWith('.srt')) { if (url.endsWith('.srt')) {
return parseSRT(content) return parseSRT(content)
}
return content
} catch (error) {
console.error('Failed to fetch subtitle:', error)
throw error
} }
return content
} }