bep40 commited on
Commit
0051c4f
·
verified ·
1 Parent(s): 7703d0a

Fix VTV channel loading spinner hanging

Browse files

Fix spinner 'Đang tải danh sách kênh...' that never disappears when API is slow. Add 5s max timeout, always populate static fallback, hide loader reliably.

Files changed (1) hide show
  1. static/app_v2.js +22 -17
static/app_v2.js CHANGED
@@ -80,9 +80,17 @@ function buildVTVBlockHTML(){
80
  }
81
 
82
  async function loadVTVStreams(){
 
 
 
 
 
83
  let apiOk = false;
84
  try {
85
- const r = await fetch('/api/vtv/streams', {signal: AbortSignal.timeout(8000)});
 
 
 
86
  if(r.ok){
87
  const data = await r.json();
88
  VTV_CHANNELS.forEach(ch => {
@@ -95,28 +103,25 @@ async function loadVTVStreams(){
95
  });
96
  }
97
  } catch(e) {
98
- console.warn('VTV API error:', e);
99
- }
100
- if(!apiOk){
101
- VTV_CHANNELS.forEach(ch => {
102
- if(!_vtvStreams[ch.id] || _vtvStreams[ch.id].length === 0){
103
- const fallback = VTV_STATIC_SOURCES[ch.id] || [];
104
- _vtvStreams[ch.id] = fallback.map(u => '/api/proxy/m3u8/vtv?url=' + encodeURIComponent(u));
105
- }
106
- });
107
  }
 
 
108
  VTV_CHANNELS.forEach(ch => {
 
 
 
 
 
109
  const tab = document.getElementById('vtvt-'+ch.id);
110
  if(tab){
111
- if(_vtvStreams[ch.id] && _vtvStreams[ch.id].length > 0){
112
- tab.classList.remove('off');
113
- tab.textContent = ch.name;
114
- } else {
115
- tab.style.opacity = '0.35';
116
- tab.textContent = ch.name + ' ✕';
117
- }
118
  }
119
  });
 
 
120
  }
121
 
122
  function _vtvRetry(){
 
80
  }
81
 
82
  async function loadVTVStreams(){
83
+ // Safety: always hide loader after 5s max
84
+ const loadEl = document.getElementById('vtv-load');
85
+ const hideLoader = () => { const el = document.getElementById('vtv-load'); if(el) el.style.display = 'none'; };
86
+ setTimeout(hideLoader, 5000);
87
+
88
  let apiOk = false;
89
  try {
90
+ const ctrl = new AbortController();
91
+ const tid = setTimeout(() => ctrl.abort(), 4000);
92
+ const r = await fetch('/api/vtv/streams', {signal: ctrl.signal});
93
+ clearTimeout(tid);
94
  if(r.ok){
95
  const data = await r.json();
96
  VTV_CHANNELS.forEach(ch => {
 
103
  });
104
  }
105
  } catch(e) {
106
+ console.warn('VTV API timeout/error:', e);
 
 
 
 
 
 
 
 
107
  }
108
+
109
+ // Always populate from static sources (fallback ensures tabs are always clickable)
110
  VTV_CHANNELS.forEach(ch => {
111
+ if(!_vtvStreams[ch.id] || _vtvStreams[ch.id].length === 0){
112
+ const fallback = VTV_STATIC_SOURCES[ch.id] || [];
113
+ _vtvStreams[ch.id] = fallback.map(u => '/api/proxy/m3u8/vtv?url=' + encodeURIComponent(u));
114
+ }
115
+ // Update tab: always show as available (opacity 1) since we have static fallback
116
  const tab = document.getElementById('vtvt-'+ch.id);
117
  if(tab){
118
+ tab.classList.remove('off');
119
+ tab.textContent = ch.name;
120
+ tab.style.opacity = '1';
 
 
 
 
121
  }
122
  });
123
+
124
+ hideLoader();
125
  }
126
 
127
  function _vtvRetry(){