#!/usr/bin/env node /** * TS File Streaming Test Suite * Tests various approaches to .ts file playback and streaming */ const BASE_URL = 'http://localhost:3000'; async function testTSStreaming() { console.log('šŸŽ¬ TS File Streaming Test Suite'); console.log('================================\n'); // Test with a sample video ID - adjust as needed const TEST_VIDEO_ID = 109; // Change this to a .ts file in your system try { // Test 1: Check video format detection console.log('1ļøāƒ£ Testing Format Detection...'); const configResponse = await fetch(`${BASE_URL}/api/video/${TEST_VIDEO_ID}/player-config`); if (configResponse.ok) { const config = await configResponse.json(); console.log(` āœ… Format detected: ${config.format.type}`); console.log(` šŸ“Š Support level: ${config.format.supportLevel}`); console.log(` šŸ”— Primary URL: ${config.format.url}`); if (config.format.qualities) { console.log(` šŸŽÆ Available qualities: ${config.format.qualities.length}`); config.format.qualities.forEach(q => { console.log(` - ${q.html}: ${q.url}`); }); } } else { console.log(` āŒ Failed to get player config: ${configResponse.status}`); } // Test 2: HLS Playlist Generation console.log('\n2ļøāƒ£ Testing HLS Playlist...'); const playlistResponse = await fetch(`${BASE_URL}/api/stream/hls/${TEST_VIDEO_ID}/playlist.m3u8`); if (playlistResponse.ok) { const playlist = await playlistResponse.text(); console.log(` āœ… Playlist generated (${playlist.length} chars)`); // Parse playlist to check structure const lines = playlist.split('\n').filter(line => line.trim()); const hasM3UHeader = lines[0] === '#EXTM3U'; const hasTargetDuration = lines.some(line => line.startsWith('#EXT-X-TARGETDURATION')); const segments = lines.filter(line => line.endsWith('.ts')); console.log(` šŸ“ Valid M3U8: ${hasM3UHeader ? 'āœ…' : 'āŒ'}`); console.log(` ā±ļø Target Duration: ${hasTargetDuration ? 'āœ…' : 'āŒ'}`); console.log(` šŸŽžļø Segments found: ${segments.length}`); if (segments.length > 0) { console.log(` šŸ“‹ First segment: ${segments[0]}`); } } else { console.log(` āŒ Playlist generation failed: ${playlistResponse.status}`); } // Test 3: HLS Segment Access console.log('\n3ļøāƒ£ Testing HLS Segment Access...'); const segmentResponse = await fetch(`${BASE_URL}/api/stream/hls/${TEST_VIDEO_ID}/segment/0.ts`, { method: 'HEAD' }); console.log(` šŸ“¦ Segment 0 status: ${segmentResponse.status} ${segmentResponse.status === 200 ? 'āœ…' : 'āŒ'}`); if (segmentResponse.ok) { const contentLength = segmentResponse.headers.get('Content-Length'); const contentType = segmentResponse.headers.get('Content-Type'); const acceptRanges = segmentResponse.headers.get('Accept-Ranges'); console.log(` šŸ“ Content-Length: ${contentLength ? `${(parseInt(contentLength) / 1024 / 1024).toFixed(2)} MB` : 'Not set'}`); console.log(` šŸ·ļø Content-Type: ${contentType || 'Not set'}`); console.log(` šŸŽÆ Accept-Ranges: ${acceptRanges || 'Not set'}`); } // Test 4: Direct Streaming console.log('\n4ļøāƒ£ Testing Direct Streaming...'); const directResponse = await fetch(`${BASE_URL}/api/stream/direct/${TEST_VIDEO_ID}`, { method: 'HEAD' }); console.log(` šŸŽ¬ Direct stream status: ${directResponse.status} ${directResponse.status === 200 ? 'āœ…' : 'āŒ'}`); if (directResponse.ok) { const contentLength = directResponse.headers.get('Content-Length'); const contentType = directResponse.headers.get('Content-Type'); const acceptRanges = directResponse.headers.get('Accept-Ranges'); console.log(` šŸ“ Content-Length: ${contentLength ? `${(parseInt(contentLength) / 1024 / 1024).toFixed(2)} MB` : 'Not set'}`); console.log(` šŸ·ļø Content-Type: ${contentType || 'Not set'}`); console.log(` šŸŽÆ Accept-Ranges: ${acceptRanges || 'Not set'}`); } // Test 5: External Streaming console.log('\n5ļøāƒ£ Testing External Streaming...'); const externalResponse = await fetch(`${BASE_URL}/api/external-stream/${TEST_VIDEO_ID}`, { method: 'HEAD' }); console.log(` šŸ”— External stream status: ${externalResponse.status} ${externalResponse.status === 200 ? 'āœ…' : 'āŒ'}`); if (externalResponse.ok) { const duration = externalResponse.headers.get('X-Content-Duration'); const bitrate = externalResponse.headers.get('X-Content-Bitrate'); console.log(` ā±ļø Duration: ${duration ? `${duration}s` : 'Not available'}`); console.log(` šŸ“Š Bitrate: ${bitrate || 'Not available'}`); } // Test 6: TS Conversion Status console.log('\n6ļøāƒ£ Testing TS Conversion Status...'); const conversionResponse = await fetch(`${BASE_URL}/api/videos/${TEST_VIDEO_ID}/convert-ts`); if (conversionResponse.ok) { const conversionData = await conversionResponse.json(); console.log(` šŸ”„ Convertible: ${conversionData.convertible ? 'āœ…' : 'āŒ'}`); console.log(` šŸ“ Has converted file: ${conversionData.has_converted_file ? 'āœ…' : 'āŒ'}`); if (conversionData.analysis) { console.log(` šŸŽ„ Video codec: ${conversionData.analysis.video_codec || 'Unknown'}`); console.log(` šŸ”Š Audio codec: ${conversionData.analysis.audio_codec || 'Unknown'}`); console.log(` ā±ļø Duration: ${conversionData.analysis.duration ? `${conversionData.analysis.duration}s` : 'Unknown'}`); } if (conversionData.recommendations) { console.log(' šŸ’” Recommendations:'); Object.entries(conversionData.recommendations).forEach(([key, value]) => { if (value) console.log(` - ${key}: ${value}`); }); } } else { console.log(` āŒ Conversion status check failed: ${conversionResponse.status}`); } // Test 7: Media Access Information console.log('\n7ļøāƒ£ Testing Media Access Information...'); const mediaAccessResponse = await fetch(`${BASE_URL}/api/media-access/${TEST_VIDEO_ID}`); if (mediaAccessResponse.ok) { const mediaData = await mediaAccessResponse.json(); console.log(` āœ… Media access data retrieved`); console.log(` šŸ·ļø Primary recommendation: ${mediaData.primary_recommendation || 'Not specified'}`); if (mediaData.streaming_options) { console.log(' 🌐 Streaming options:'); Object.entries(mediaData.streaming_options).forEach(([key, value]) => { if (typeof value === 'string') { console.log(` - ${key}: ${value}`); } }); } } else { console.log(` āŒ Media access failed: ${mediaAccessResponse.status}`); } // Summary and Recommendations console.log('\nšŸ“‹ Test Summary & Recommendations'); console.log('=================================='); console.log('āœ… If HLS playlist and segments work: Use HLS streaming for best compatibility'); console.log('āœ… If direct streaming works: .ts file contains web-compatible codecs'); console.log('āœ… If conversion is available: Consider converting for broader browser support'); console.log('šŸ“ For downloaded .ts files from streaming sites: HLS approach is optimal'); console.log('šŸ”§ For compatibility issues: Use external player or container conversion'); } catch (error) { console.error('āŒ Test suite error:', error.message); } } // Helper function for requests async function makeRequest(url) { const response = await fetch(`${BASE_URL}${url}`); return { status: response.status, data: response.ok ? await response.text() : await response.text() }; } // Run the test suite testTSStreaming();