nextav/tests/streaming/test-ts-streaming.mjs

181 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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();