bep40 commited on
Commit
6bee349
·
verified ·
1 Parent(s): a035976

Add VTV debug test page in static folder

Browse files
Files changed (1) hide show
  1. static/vtv_test2.html +116 -0
static/vtv_test2.html ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>VTV Stream Debug</title>
7
+ <style>
8
+ body{background:#111;color:#eee;font-family:monospace;padding:16px;margin:0}
9
+ h2{color:#5cb87a;font-size:16px}
10
+ video{width:100%;max-width:600px;background:#000;margin:10px 0;display:block}
11
+ #log{background:#1a1a1a;border:1px solid #333;padding:10px;max-height:300px;overflow-y:auto;white-space:pre-wrap;font-size:11px;line-height:1.5}
12
+ .ok{color:#5cb87a}.err{color:#e74c3c}.warn{color:#f0c040}.info{color:#888}
13
+ button{background:#2d8659;border:0;color:#fff;padding:8px 16px;border-radius:8px;cursor:pointer;margin:4px;font-size:12px}
14
+ select{background:#222;color:#eee;border:1px solid #444;padding:6px;border-radius:6px;font-size:12px}
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <h2>📺 VTV Stream Debug Test</h2>
19
+ <div>
20
+ <select id="ch">
21
+ <option value="vtv1">VTV1</option><option value="vtv2">VTV2</option><option value="vtv3">VTV3</option>
22
+ <option value="vtv4">VTV4</option><option value="vtv5">VTV5</option><option value="vtv6" selected>VTV6</option>
23
+ <option value="vtv7">VTV7</option><option value="vtv8">VTV8</option><option value="vtv9">VTV9</option>
24
+ </select>
25
+ <button onclick="startPlay()">▶ Play</button>
26
+ <button onclick="location.reload()">🔄 Reload</button>
27
+ </div>
28
+ <video id="v" controls autoplay muted playsinline></video>
29
+ <div id="log"></div>
30
+
31
+ <script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.13/dist/hls.min.js"></script>
32
+ <script>
33
+ const LOG=(msg,type)=>{const el=document.getElementById('log');const c=type||'info';el.innerHTML+='<span class="'+c+'">['+new Date().toISOString().substr(11,12)+'] '+msg+'\n</span>';el.scrollTop=el.scrollHeight;};
34
+ const VTVGO={"vtv1":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv1-manifest.m3u8","vtv2":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv2-manifest.m3u8","vtv3":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv3-manifest.m3u8","vtv4":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv4-manifest.m3u8","vtv5":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv5-manifest.m3u8","vtv6":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv6-manifest.m3u8","vtv7":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv7-manifest.m3u8","vtv8":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv8-manifest.m3u8","vtv9":"https://vtvgolive-failover.vtvdigital.vn/vtvgo/vtv9-manifest.m3u8"};
35
+ const BASE="https://bep40-vnews.hf.space";
36
+ const video=document.getElementById('v');
37
+ let hls=null;
38
+
39
+ LOG('Page loaded','ok');
40
+ LOG('HLS.js: '+(Hls.version||'unknown')+' | supported: '+Hls.isSupported(),'info');
41
+ LOG('Native HLS: '+video.canPlayType('application/vnd.apple.mpegurl'),'info');
42
+
43
+ function startPlay(){
44
+ const ch=document.getElementById('ch').value;
45
+ const directUrl=VTVGO[ch];
46
+ const proxyUrl=BASE+'/api/proxy/m3u8/vtv?url='+encodeURIComponent(directUrl);
47
+ LOG('\n--- Playing '+ch+' ---','info');
48
+ LOG('Proxy: '+proxyUrl,'info');
49
+ if(hls){hls.destroy();hls=null;}
50
+ video.pause();video.src='';
51
+
52
+ if(!Hls.isSupported()){
53
+ LOG('Using native HLS','warn');
54
+ video.src=proxyUrl;
55
+ video.play().then(()=>LOG('Native play OK','ok')).catch(e=>LOG('Native play: '+e,'err'));
56
+ return;
57
+ }
58
+
59
+ hls=new Hls({enableWorker:false,lowLatencyMode:true,startLevel:-1,capLevelToPlayerSize:true,maxBufferLength:6,debug:true});
60
+ hls.attachMedia(video);
61
+ LOG('attachMedia done','info');
62
+
63
+ hls.on(Hls.Events.MEDIA_ATTACHED,()=>{
64
+ LOG('MEDIA_ATTACHED','ok');
65
+ hls.loadSource(proxyUrl);
66
+ LOG('loadSource: '+proxyUrl.substring(0,60),'info');
67
+ });
68
+
69
+ hls.on(Hls.Events.MANIFEST_LOADING,()=>LOG('MANIFEST_LOADING','info'));
70
+ hls.on(Hls.Events.MANIFEST_LOADED,()=>LOG('MANIFEST_LOADED','ok'));
71
+ hls.on(Hls.Events.MANIFEST_PARSED,(ev,d)=>{
72
+ LOG('MANIFEST_PARSED: '+d.levels.length+' levels, '+(d.levels[0]?d.levels[0].width+'x'+d.levels[0].height:'?'),'ok');
73
+ const res=d.levels.map(l=>l.width+'x'+l.height).join(', ');
74
+ LOG('Available: '+res,'info');
75
+ });
76
+
77
+ hls.on(Hls.Events.FRAG_LOADED,(ev,d)=>{
78
+ const sz=d.frag&&d.frag.data&&d.frag.data.length;
79
+ LOG('FRAG_LOADED #'+d.frag.sn+' size='+sz,'ok');
80
+ });
81
+
82
+ hls.on(Hls.Events.BUFFER_APPENDED,()=>{
83
+ const buf=video.buffered;
84
+ let bufInfo='';
85
+ if(buf.length>0)bufInfo='buf[0]='+buf.start(0).toFixed(1)+'-'+buf.end(0).toFixed(1);
86
+ const dur=video.duration;
87
+ const ct=video.currentTime;
88
+ LOG('BUFFER_APPENDED '+bufInfo+' dur='+(isFinite(dur)?dur.toFixed(1):'live')+' ct='+ct.toFixed(1),'ok');
89
+ });
90
+
91
+ hls.on(Hls.Events.ERROR,(ev,data)=>{
92
+ LOG('ERROR '+data.type+' '+data.details+' fatal='+data.fatal,'err');
93
+ if(data.url)LOG(' URL: '+data.url.substring(0,80),'err');
94
+ if(data.fatal){
95
+ LOG('Fatal error - destroying HLS','err');
96
+ hls.destroy();hls=null;
97
+ }
98
+ });
99
+
100
+ video.addEventListener('playing',()=>LOG('🎬 VIDEO PLAYING!','ok'),{once:true});
101
+ video.addEventListener('loadeddata',()=>LOG('LOADED DATA','ok'),{once:true});
102
+ video.addEventListener('error',(e)=>LOG('VIDEO ERROR: '+video.error.code+' '+video.error.message,'err'),{once:true});
103
+
104
+ let checkCount=0;
105
+ const checkInterval=setInterval(()=>{
106
+ checkCount++;
107
+ if(checkCount>20){clearInterval(checkInterval);return;}
108
+ const state={ready:video.readyState,networkState:video.networkState,w:video.videoWidth,h:video.videoHeight,paused:video.paused,muted:video.muted};
109
+ LOG('State #'+checkCount+': '+JSON.stringify(state),state.w>0?'ok':'warn');
110
+ if(state.w>0){LOG('🎉 VIDEO HAS FRAMES '+state.w+'x'+state.h,'ok');clearInterval(checkInterval);}
111
+ if(video.error){LOG('Error: '+video.error.message,'err');clearInterval(checkInterval);}
112
+ },1000);
113
+ }
114
+ </script>
115
+ </body>
116
+ </html>