bep40 commited on
Commit
233453a
·
verified ·
1 Parent(s): f4969ab

Fix VTV player: add VTV6, VTV10, fetch streams from backend API

Browse files
Files changed (1) hide show
  1. static/yt_live.js +86 -19
static/yt_live.js CHANGED
@@ -1,25 +1,29 @@
1
- // === VNEWS — VTV1-VTV9 + VTV Cần Thơ LIVE CHANNELS ===
2
- // Uses fptplay CDN streams via backend proxy (to add Referer header)
3
- // VTV6 slot = VTV Cần Thơ (vtvcantho)
4
- // Sources: xemtv.net, iptv-org, fptplay CDN
5
 
6
  (function(){
7
- // Channel definitions: name -> fptplay stream path
8
- // These are the actual stream URLs extracted from xemtv.net pages
9
  const CHANNELS = [
10
- {id:'vtv1', name:'VTV1', stream:'https://live.fptplay53.net/fnxch2/vtv1hd_abr.smil/chunklist.m3u8', icon:'🔴'},
11
- {id:'vtv2', name:'VTV2', stream:'https://live.fptplay53.net/fnxch2/vtv2hd_abr.smil/chunklist.m3u8', icon:'🟠'},
12
- {id:'vtv3', name:'VTV3', stream:'https://live.fptplay53.net/fnxch2/vtv3hd_abr.smil/chunklist.m3u8', icon:'🟡'},
13
- {id:'vtv4', name:'VTV4', stream:'https://live.fptplay53.net/fnxch2/vtv4hd_abr.smil/chunklist.m3u8', icon:'🟢'},
14
- {id:'vtv5', name:'VTV5', stream:'https://live-a.fptplay53.net/live/media/VTV5HD/live_hls_avc/index.m3u8', icon:'🔵'},
15
- {id:'vtvct', name:'VTV Cần Thơ', stream:'https://live.fptplay53.net/fnxch2/vtvcantho_abr.smil/chunklist.m3u8', icon:'🟣'},
16
- {id:'vtv7', name:'VTV7', stream:'https://live.fptplay53.net/fnxhd1/vtv7hd_vhls.smil/chunklist_b5000000.m3u8',icon:'⚪'},
17
- {id:'vtv8', name:'VTV8', stream:'https://live.fptplay53.net/epzhd1/vtv8hd_vhls.smil/chunklist.m3u8', icon:'🟤'},
18
- {id:'vtv9', name:'VTV9', stream:'https://live.fptplay53.net/fnxhd1/vtv9hd_vhls.smil/chunklist.m3u8', icon:'🔴'},
 
19
  ];
20
 
 
 
 
21
  let _currentCh = null;
22
  let _hls = null;
 
23
 
24
  if(document.getElementById('vtv-css')) return;
25
  const s=document.createElement('style'); s.id='vtv-css';
@@ -34,6 +38,7 @@
34
  .vtv-tab{padding:4px 8px;background:#1a2a3a;border:1px solid #2a3a4a;border-radius:10px;color:#8ab4d8;font-size:9px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:all .2s}
35
  .vtv-tab:hover{background:#0b4a7a;color:#fff}
36
  .vtv-tab.on{background:#0066cc;border-color:#00ccff;color:#fff;font-weight:700}
 
37
  .vtv-frame{position:relative;width:100%;aspect-ratio:16/9;background:#000;min-height:180px}
38
  .vtv-frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
39
  .vtv-err{display:flex;align-items:center;justify-content:center;height:180px;color:#888;font-size:12px;text-align:center;padding:20px;flex-direction:column;gap:8px}
@@ -48,13 +53,13 @@
48
  const w=document.createElement('div'); w.className='vtv-wrap'; w.id='vtv-block';
49
  let tabs='';
50
  CHANNELS.forEach(ch=>{
51
- tabs+=`<button class="vtv-tab" id="vtvt-${ch.id}" onclick="window._vtvPlay('${ch.id}')">${ch.icon} ${ch.name}</button>`;
52
  });
53
  w.innerHTML=
54
  '<div class="vtv-head"><span class="vtv-title">📺 VTV Trực Tuyến</span><span class="vtv-badge">● LIVE</span></div>'+
55
  '<div class="vtv-tabs">'+tabs+'</div>'+
56
  '<div class="vtv-frame">'+
57
- '<div class="vtv-load" id="vtv-load"><div class="vtv-spinner"></div>Đang tải kênh...</div>'+
58
  '<video id="vtv-player" playsinline muted controls preload="auto" style="display:none"></video>'+
59
  '<div class="vtv-err" id="vtv-err" style="display:none"><span id="vtv-err-msg">Không thể tải kênh</span><button onclick="window._vtvRetry()">Thử lại</button></div>'+
60
  '</div>';
@@ -65,7 +70,50 @@
65
  const h=document.getElementById('view-home');
66
  if(!h||document.getElementById('vtv-block')) return;
67
  h.insertBefore(buildBlock(), h.firstChild);
68
- setTimeout(()=>window._vtvPlay('vtv3'), 800);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  }
70
 
71
  window._vtvRetry = function(){
@@ -90,8 +138,27 @@
90
 
91
  if(_hls){_hls.destroy(); _hls=null;}
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  // Use our proxy endpoint to fetch stream with proper Referer
94
- const proxyUrl = '/api/proxy/hls?url='+encodeURIComponent(ch.stream);
95
  _playStream(video, proxyUrl, ch.name, loadEl, errEl, errMsg);
96
  };
97
 
 
1
+ // === VNEWS — VTV1-VTV10 + VTV Cần Thơ LIVE CHANNELS ===
2
+ // Fetches stream URLs from backend API (which scrapes xemtv.net PHP endpoints)
3
+ // Backend proxy adds proper Referer/Origin headers for fptplay CDN
4
+ // VTV6 = su-kien-03 (event channel), VTV10 = VTV Cần Thơ
5
 
6
  (function(){
7
+ // Channel definitions stream URLs fetched from backend
 
8
  const CHANNELS = [
9
+ {id:'vtv1', name:'VTV1', icon:'🔴'},
10
+ {id:'vtv2', name:'VTV2', icon:'🟠'},
11
+ {id:'vtv3', name:'VTV3', icon:'🟡'},
12
+ {id:'vtv4', name:'VTV4', icon:'🟢'},
13
+ {id:'vtv5', name:'VTV5', icon:'🔵'},
14
+ {id:'vtv6', name:'VTV6', icon:'🟣'},
15
+ {id:'vtv7', name:'VTV7', icon:'⚪'},
16
+ {id:'vtv8', name:'VTV8', icon:'🟤'},
17
+ {id:'vtv9', name:'VTV9', icon:'🔴'},
18
+ {id:'vtv10', name:'VTV Cần Thơ', icon:'🟡'},
19
  ];
20
 
21
+ // Fetched stream URLs (populated by _fetchStreams)
22
+ const STREAMS = {};
23
+
24
  let _currentCh = null;
25
  let _hls = null;
26
+ let _fetching = false;
27
 
28
  if(document.getElementById('vtv-css')) return;
29
  const s=document.createElement('style'); s.id='vtv-css';
 
38
  .vtv-tab{padding:4px 8px;background:#1a2a3a;border:1px solid #2a3a4a;border-radius:10px;color:#8ab4d8;font-size:9px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:all .2s}
39
  .vtv-tab:hover{background:#0b4a7a;color:#fff}
40
  .vtv-tab.on{background:#0066cc;border-color:#00ccff;color:#fff;font-weight:700}
41
+ .vtv-tab.off{opacity:.4;pointer-events:none}
42
  .vtv-frame{position:relative;width:100%;aspect-ratio:16/9;background:#000;min-height:180px}
43
  .vtv-frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
44
  .vtv-err{display:flex;align-items:center;justify-content:center;height:180px;color:#888;font-size:12px;text-align:center;padding:20px;flex-direction:column;gap:8px}
 
53
  const w=document.createElement('div'); w.className='vtv-wrap'; w.id='vtv-block';
54
  let tabs='';
55
  CHANNELS.forEach(ch=>{
56
+ tabs+=`<button class="vtv-tab off" id="vtvt-${ch.id}" onclick="window._vtvPlay('${ch.id}')">${ch.icon} ${ch.name}</button>`;
57
  });
58
  w.innerHTML=
59
  '<div class="vtv-head"><span class="vtv-title">📺 VTV Trực Tuyến</span><span class="vtv-badge">● LIVE</span></div>'+
60
  '<div class="vtv-tabs">'+tabs+'</div>'+
61
  '<div class="vtv-frame">'+
62
+ '<div class="vtv-load" id="vtv-load"><div class="vtv-spinner"></div>Đang tải danh sách kênh...</div>'+
63
  '<video id="vtv-player" playsinline muted controls preload="auto" style="display:none"></video>'+
64
  '<div class="vtv-err" id="vtv-err" style="display:none"><span id="vtv-err-msg">Không thể tải kênh</span><button onclick="window._vtvRetry()">Thử lại</button></div>'+
65
  '</div>';
 
70
  const h=document.getElementById('view-home');
71
  if(!h||document.getElementById('vtv-block')) return;
72
  h.insertBefore(buildBlock(), h.firstChild);
73
+ _fetchStreams();
74
+ }
75
+
76
+ // Fetch stream URLs from backend
77
+ window._fetchVtvStreams = async function(){
78
+ if(_fetching) return;
79
+ _fetching = true;
80
+ try{
81
+ const r = await fetch('/api/vtv/streams');
82
+ if(r.ok){
83
+ const data = await r.json();
84
+ if(data.channels){
85
+ data.channels.forEach(ch=>{
86
+ if(ch.stream_url) STREAMS[ch.id] = ch.stream_url;
87
+ });
88
+ // Enable tabs for channels that have streams
89
+ CHANNELS.forEach(ch=>{
90
+ const tab = document.getElementById('vtvt-'+ch.id);
91
+ if(tab){
92
+ if(STREAMS[ch.id]){
93
+ tab.classList.remove('off');
94
+ } else {
95
+ tab.textContent = ch.icon + ' ' + ch.name + ' ✕';
96
+ tab.style.opacity = '0.4';
97
+ }
98
+ }
99
+ });
100
+ }
101
+ }
102
+ }catch(e){
103
+ console.warn('VTV streams fetch failed:', e);
104
+ }
105
+ _fetching = false;
106
+ };
107
+
108
+ function _fetchStreams(){
109
+ window._fetchVtvStreams().then(()=>{
110
+ // Auto-play VTV3 if available
111
+ if(STREAMS['vtv3']){
112
+ setTimeout(()=>window._vtvPlay('vtv3'), 500);
113
+ } else if(STREAMS['vtv1']){
114
+ setTimeout(()=>window._vtvPlay('vtv1'), 500);
115
+ }
116
+ });
117
  }
118
 
119
  window._vtvRetry = function(){
 
138
 
139
  if(_hls){_hls.destroy(); _hls=null;}
140
 
141
+ // Get stream URL — fetch fresh if not cached
142
+ let streamUrl = STREAMS[chId];
143
+ if(!streamUrl){
144
+ try{
145
+ const r = await fetch('/api/vtv/stream/'+encodeURIComponent(ch.name));
146
+ if(r.ok){
147
+ const d = await r.json();
148
+ streamUrl = d.stream_url;
149
+ if(streamUrl) STREAMS[chId] = streamUrl;
150
+ }
151
+ }catch(e){}
152
+ }
153
+
154
+ if(!streamUrl){
155
+ loadEl.style.display='none'; errEl.style.display='flex';
156
+ errMsg.textContent = ch.name + ': Không tìm thấy luồng. Thử lại sau.';
157
+ return;
158
+ }
159
+
160
  // Use our proxy endpoint to fetch stream with proper Referer
161
+ const proxyUrl = '/api/proxy/hls?url='+encodeURIComponent(streamUrl);
162
  _playStream(video, proxyUrl, ch.name, loadEl, errEl, errMsg);
163
  };
164