181 lines
7.8 KiB
JavaScript
181 lines
7.8 KiB
JavaScript
#!/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(); |