#!/usr/bin/env node /** * HLS Endpoint Verification Script * Tests the HLS streaming endpoints to ensure they work correctly */ const http = require('http'); const fs = require('fs'); const path = require('path'); const TEST_VIDEO_ID = 109; // The .ts file from the logs const HOST = 'localhost'; const PORT = 3000; function makeRequest(path, method = 'GET') { return new Promise((resolve, reject) => { const options = { hostname: HOST, port: PORT, path: path, method: method, headers: { 'Accept': '*/*', 'User-Agent': 'HLS-Test/1.0' } }; const req = http.request(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { resolve({ status: res.statusCode, headers: res.headers, data: data }); }); }); req.on('error', (err) => { reject(err); }); req.setTimeout(5000, () => { req.destroy(); reject(new Error('Request timeout')); }); req.end(); }); } async function testHLSEndpoints() { console.log(`๐Ÿงช Testing HLS endpoints for video ID: ${TEST_VIDEO_ID}`); console.log('====================================='); try { // Test 1: Player Config Endpoint console.log('\n1๏ธโƒฃ Testing Player Config Endpoint...'); try { const playerConfig = await makeRequest(`/api/video/${TEST_VIDEO_ID}/player-config`); console.log(` Status: ${playerConfig.status} ${playerConfig.status === 200 ? 'โœ…' : 'โŒ'}`); if (playerConfig.status === 200) { const config = JSON.parse(playerConfig.data); console.log(` Player Type: ${config.player?.type || 'unknown'}`); console.log(` Format Type: ${config.format?.type || 'unknown'}`); console.log(` HLS URL: ${config.streaming?.hls_url || 'none'}`); console.log(` Direct URL: ${config.streaming?.direct_url || 'none'}`); if (config.format?.type === 'hls') { console.log(' โœ… Format correctly identified as HLS'); } else { console.log(' โš ๏ธ Format not identified as HLS - checking file extension...'); } } else { console.log(` Response: ${playerConfig.data}`); } } catch (err) { console.log(` โŒ Error: ${err.message}`); } // Test 2: HLS Playlist Endpoint (.m3u8) console.log('\n2๏ธโƒฃ Testing HLS Playlist (.m3u8)...'); try { const playlist = await makeRequest(`/api/stream/hls/${TEST_VIDEO_ID}/playlist.m3u8`); console.log(` Status: ${playlist.status} ${playlist.status === 200 ? 'โœ…' : 'โŒ'}`); console.log(` Content-Type: ${playlist.headers['content-type'] || 'none'}`); if (playlist.status === 200) { console.log(' โœ… Playlist loaded successfully'); console.log(` Content-Length: ${playlist.headers['content-length'] || 'unknown'} bytes`); // Validate M3U8 format const lines = playlist.data.split('\n'); const hasM3UHeader = lines[0].includes('#EXTM3U'); const hasTargetDuration = lines.some(line => line.includes('#EXT-X-TARGETDURATION')); const hasSegments = lines.some(line => line.endsWith('.ts')); console.log(` M3U8 Format: ${hasM3UHeader ? 'โœ… Valid' : 'โŒ Invalid'}`); console.log(` Target Duration: ${hasTargetDuration ? 'โœ… Present' : 'โŒ Missing'}`); console.log(` Segments: ${hasSegments ? 'โœ… Found' : 'โŒ None'}`); if (hasM3UHeader) { // Count segments const segments = lines.filter(line => line.endsWith('.ts')); console.log(` Number of segments: ${segments.length}`); // Show first few lines console.log(' First 5 lines:'); lines.slice(0, 5).forEach(line => console.log(` ${line}`)); } } else { console.log(` Response: ${playlist.data}`); } } catch (err) { console.log(` โŒ Error: ${err.message}`); } // Test 3: HLS Playlist Endpoint (without .m3u8) console.log('\n3๏ธโƒฃ Testing HLS Playlist (without .m3u8)...'); try { const playlist = await makeRequest(`/api/stream/hls/${TEST_VIDEO_ID}/playlist`); console.log(` Status: ${playlist.status} ${playlist.status === 200 ? 'โœ…' : 'โŒ'}`); if (playlist.status === 200) { console.log(' โœ… Alternative playlist route works'); } } catch (err) { console.log(` โŒ Error: ${err.message}`); } // Test 4: HLS Segment Endpoint console.log('\n4๏ธโƒฃ Testing HLS Segment (segment 0)...'); try { const segment = await makeRequest(`/api/stream/hls/${TEST_VIDEO_ID}/segment/0.ts`); console.log(` Status: ${segment.status} ${segment.status === 200 ? 'โœ…' : 'โŒ'}`); console.log(` Content-Type: ${segment.headers['content-type'] || 'none'}`); if (segment.status === 200) { console.log(' โœ… Segment loaded successfully'); console.log(` Content-Length: ${segment.headers['content-length'] || 'unknown'} bytes`); // Check if it's actually a TS file const isBinary = segment.data.includes('\0') || /[^\x20-\x7E\n\r\t]/.test(segment.data); console.log(` Content Type: ${isBinary ? 'โœ… Binary (likely TS)' : 'โš ๏ธ Text (unexpected)'}`); } else { console.log(` Response: ${segment.data}`); // Check if it's a fallback message if (segment.data.includes('not yet implemented')) { console.log(' โš ๏ธ Segment serving not implemented for this format'); } } } catch (err) { console.log(` โŒ Error: ${err.message}`); } // Test 5: Direct Stream Endpoint (for comparison) console.log('\n5๏ธโƒฃ Testing Direct Stream (for comparison)...'); try { const direct = await makeRequest(`/api/stream/direct/${TEST_VIDEO_ID}`); console.log(` Status: ${direct.status} ${direct.status === 200 ? 'โœ…' : 'โŒ'}`); console.log(` Content-Type: ${direct.headers['content-type'] || 'none'}`); if (direct.status === 200) { console.log(' โœ… Direct streaming works'); console.log(` Content-Length: ${direct.headers['content-length'] || 'unknown'} bytes`); // Check for range support const acceptsRanges = direct.headers['accept-ranges']; console.log(` Range Support: ${acceptsRanges ? `โœ… ${acceptsRanges}` : 'โŒ None'}`); } else { console.log(` Response: ${direct.data}`); } } catch (err) { console.log(` โŒ Error: ${err.message}`); } console.log('\nโœ… HLS endpoint testing completed!'); console.log('\n๐ŸŽฏ Summary:'); console.log('โ€ข Player config should identify .ts files as HLS-compatible'); console.log('โ€ข HLS playlist should return valid M3U8 format'); console.log('โ€ข Segments should load as binary data'); console.log('โ€ข Direct streaming should work as fallback'); } catch (error) { console.error('โŒ Test suite failed:', error.message); } } // Run the tests console.log('๐Ÿš€ Starting HLS endpoint verification...'); console.log(`Testing against: http://${HOST}:${PORT}`); console.log('Make sure your development server is running!'); console.log(''); testHLSEndpoints().catch(console.error);