#!/usr/bin/env node /** * HLS Implementation Diagnostic Script * Checks the HLS streaming implementation and identifies potential issues */ const fs = require('fs'); const path = require('path'); console.log('๐Ÿ” HLS Implementation Diagnostic Tool'); console.log('====================================='); // Check if HLS routes exist const hlsRoutes = [ 'src/app/api/stream/hls/[id]/playlist/route.ts', 'src/app/api/stream/hls/[id]/playlist.m3u8/route.ts', 'src/app/api/stream/hls/[id]/segment/[segment]/route.ts' ]; console.log('\n๐Ÿ“ Checking HLS API Routes:'); hlsRoutes.forEach(route => { const fullPath = path.join(process.cwd(), route); const exists = fs.existsSync(fullPath); console.log(`${exists ? 'โœ…' : 'โŒ'} ${route} ${exists ? '- EXISTS' : '- MISSING'}`); }); // Check format detector console.log('\n๐Ÿ”ง Checking Format Detector:'); const formatDetectorPath = path.join(process.cwd(), 'src/lib/video-format-detector.ts'); if (fs.existsSync(formatDetectorPath)) { const content = fs.readFileSync(formatDetectorPath, 'utf8'); // Check for HLS format support const hasHLSFormat = content.includes('createHLSFormat'); const hasTSsupport = content.includes("'ts'"); const hasM3U8url = content.includes('playlist.m3u8'); console.log(`${hasHLSFormat ? 'โœ…' : 'โŒ'} HLS format detection: ${hasHLSFormat ? 'IMPLEMENTED' : 'MISSING'}`); console.log(`${hasTSsupport ? 'โœ…' : 'โŒ'} .ts file support: ${hasTSsupport ? 'INCLUDED' : 'MISSING'}`); console.log(`${hasM3U8url ? 'โœ…' : 'โŒ'} M3U8 URL generation: ${hasM3U8url ? 'CONFIGURED' : 'MISSING'}`); // Extract HLS-compatible formats const hlsFormatsMatch = content.match(/const HLS_COMPATIBLE_FORMATS = \[([\s\S]*?)\];/); if (hlsFormatsMatch) { const formats = hlsFormatsMatch[1].split(',').map(f => f.trim().replace(/['"]/g, '')); console.log(`๐Ÿ“‹ HLS-compatible formats: ${formats.join(', ')}`); } } else { console.log('โŒ Format detector file not found'); } // Check ArtPlayer integration console.log('\n๐ŸŽฌ Checking ArtPlayer Integration:'); const artPlayerPath = path.join(process.cwd(), 'src/components/artplayer-wrapper.tsx'); if (fs.existsSync(artPlayerPath)) { const content = fs.readFileSync(artPlayerPath, 'utf8'); const hasHlsImport = content.includes("import Hls from 'hls.js'"); const hasHlsPlugin = content.includes('hlsInstance'); const hasErrorHandler = content.includes('HLSErrorHandler'); console.log(`${hasHlsImport ? 'โœ…' : 'โŒ'} hls.js import: ${hasHlsImport ? 'PRESENT' : 'MISSING'}`); console.log(`${hasHlsPlugin ? 'โœ…' : 'โŒ'} HLS plugin implementation: ${hasHlsPlugin ? 'IMPLEMENTED' : 'MISSING'}`); console.log(`${hasErrorHandler ? 'โœ…' : 'โŒ'} Error handler integration: ${hasErrorHandler ? 'CONFIGURED' : 'MISSING'}`); } else { console.log('โŒ ArtPlayer wrapper file not found'); } // Check unified video player (ArtPlayer only) console.log('\n๐Ÿ”„ Checking Unified Video Player (ArtPlayer Only):'); const unifiedPlayerPath = path.join(process.cwd(), 'src/components/unified-video-player.tsx'); if (fs.existsSync(unifiedPlayerPath)) { const content = fs.readFileSync(unifiedPlayerPath, 'utf8'); const hasArtPlayerOnly = content.includes('Always use ArtPlayer now'); const noFallbacks = !content.includes('VideoViewer') && !content.includes('InlineVideoPlayer'); const hasFormatDetection = content.includes('detectVideoFormat'); console.log(`${hasArtPlayerOnly ? 'โœ…' : 'โŒ'} ArtPlayer-only architecture: ${hasArtPlayerOnly ? 'IMPLEMENTED' : 'MISSING'}`); console.log(`${noFallbacks ? 'โœ…' : 'โŒ'} Legacy player removal: ${noFallbacks ? 'COMPLETE' : 'INCOMPLETE'}`); console.log(`${hasFormatDetection ? 'โœ…' : 'โŒ'} Format detection: ${hasFormatDetection ? 'INTEGRATED' : 'MISSING'}`); } else { console.log('โŒ Unified video player file not found'); } // Check player config endpoint console.log('\nโš™๏ธ Checking Player Config Endpoint:'); const playerConfigPath = path.join(process.cwd(), 'src/app/api/video/[id]/player-config/route.ts'); if (fs.existsSync(playerConfigPath)) { const content = fs.readFileSync(playerConfigPath, 'utf8'); const hasFormatDetection = content.includes('detectVideoFormat'); const hasOptimalPlayer = content.includes('getOptimalPlayerType'); const hasStreamingUrls = content.includes('streaming'); console.log(`${hasFormatDetection ? 'โœ…' : 'โŒ'} Format detection: ${hasFormatDetection ? 'INCLUDED' : 'MISSING'}`); console.log(`${hasOptimalPlayer ? 'โœ…' : 'โŒ'} Optimal player selection: ${hasOptimalPlayer ? 'IMPLEMENTED' : 'MISSING'}`); console.log(`${hasStreamingUrls ? 'โœ…' : 'โŒ'} Streaming URLs: ${hasStreamingUrls ? 'CONFIGURED' : 'MISSING'}`); } else { console.log('โŒ Player config endpoint not found'); } // Check build output console.log('\n๐Ÿ—๏ธ Checking Build Configuration:'); const packageJsonPath = path.join(process.cwd(), 'package.json'); if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); const hasHlsJs = packageJson.dependencies && packageJson.dependencies['hls.js']; const hasArtPlayer = packageJson.dependencies && packageJson.dependencies['artplayer']; console.log(`${hasHlsJs ? 'โœ…' : 'โŒ'} hls.js dependency: ${hasHlsJs ? 'INSTALLED' : 'MISSING'}`); console.log(`${hasArtPlayer ? 'โœ…' : 'โŒ'} artplayer dependency: ${hasArtPlayer ? 'INSTALLED' : 'MISSING'}`); if (hasHlsJs) console.log(`๐Ÿ“ฆ hls.js version: ${packageJson.dependencies['hls.js']}`); if (hasArtPlayer) console.log(`๐Ÿ“ฆ artplayer version: ${packageJson.dependencies['artplayer']}`); } else { console.log('โŒ package.json not found'); } // Provide troubleshooting recommendations console.log('\n๐Ÿ”ง Troubleshooting Recommendations:'); console.log('====================================='); const issues = []; // Check for missing routes if (!fs.existsSync(path.join(process.cwd(), 'src/app/api/stream/hls/[id]/playlist.m3u8/route.ts'))) { issues.push('Missing .m3u8 route handler - HLS clients expect .m3u8 extension'); } if (!fs.existsSync(path.join(process.cwd(), 'src/app/api/stream/hls/[id]/segment/[segment]/route.ts'))) { issues.push('Missing segment serving route'); } // Check format detector issues if (fs.existsSync(formatDetectorPath)) { const content = fs.readFileSync(formatDetectorPath, 'utf8'); if (!content.includes("'ts'")) { issues.push('Format detector missing .ts file support'); } if (!content.includes('playlist.m3u8')) { issues.push('Format detector not generating proper M3U8 URLs'); } } // Check ArtPlayer integration if (fs.existsSync(artPlayerPath)) { const content = fs.readFileSync(artPlayerPath, 'utf8'); if (!content.includes('hlsInstance')) { issues.push('ArtPlayer missing HLS instance configuration'); } if (!content.includes('Hls.isSupported()')) { issues.push('ArtPlayer missing HLS support detection'); } } if (issues.length === 0) { console.log('โœ… All components appear to be properly configured!'); console.log('\n๐Ÿงช Next Steps:'); console.log('1. Run `pnpm build` to verify compilation'); console.log('2. Start the development server'); console.log('3. Test with the HLS test interface at /test-hls.html'); console.log('4. Monitor browser console for HLS.js debug output'); console.log('5. Check network tab for any loading issues'); } else { console.log('โŒ Issues found that may prevent HLS streaming:'); issues.forEach(issue => console.log(` โ€ข ${issue}`)); console.log('\n๐Ÿ”ง Suggested fixes:'); console.log('1. Ensure all HLS API routes are created'); console.log('2. Verify format detector includes .ts support'); console.log('3. Check ArtPlayer HLS integration'); console.log('4. Test with sample .ts video files'); console.log('5. Monitor browser console for detailed errors'); } console.log('\n๐Ÿ“š Common HLS Issues:'); console.log('โ€ข 404 errors: Usually indicate missing routes or incorrect URL patterns'); console.log('โ€ข CORS errors: Check Access-Control-Allow-Origin headers'); console.log('โ€ข Playlist parsing: Verify M3U8 format and segment paths'); console.log('โ€ข Segment loading: Check file paths and permissions'); console.log('โ€ข Browser compatibility: Ensure hls.js support or native HLS'); console.log('\n๐ŸŽฏ Success Indicators:'); console.log('โ€ข HLS playlist loads with 200 status'); console.log('โ€ข M3U8 content shows valid playlist format'); console.log('โ€ข Segments load successfully (binary data)'); console.log('โ€ข Video plays without buffering issues'); console.log('โ€ข Quality switching works smoothly'); console.log('\n๐Ÿš€ Ready for testing!'); // Export a simple test function for programmatic use module.exports = { diagnoseHLS: () => { return { routes: hlsRoutes.map(route => ({ path: route, exists: fs.existsSync(path.join(process.cwd(), route)) })), issues, recommendations: issues.length > 0 ? issues : ['All systems ready for testing'] }; } }; } };