bep40 commited on
Commit
2e17d69
·
verified ·
1 Parent(s): 0e98611

Add 'friendly' to HL_LEAGUES + WC highlight tab handler in wc2026_v2.js"

Browse files
Files changed (1) hide show
  1. static/wc2026_v2.js +39 -193
static/wc2026_v2.js CHANGED
@@ -1,201 +1,47 @@
1
- // === WORLD CUP 2026 - Full render ===
2
- // Fixtures: JSON sorted by date, VN names + flags, livescore auto-refresh
3
- // BXH: Self-rendered from fixtures data (grouped by bang)
4
- // News: Always fetch og:image for thumbnails
5
-
6
- let _wc2026Data = null;
7
- let _wcRefreshInterval = null;
8
-
9
- const WC_TEAMS = {
10
- 'Mexico':'🇲🇽 Mexico','Colombia':'🇨🇴 Colombia','USA':'🇺🇸 Mỹ','United States':'🇺🇸 Mỹ',
11
- 'Brazil':'🇧🇷 Brazil','Argentina':'🇦🇷 Argentina','Germany':'🇩🇪 Đức','France':'🇫🇷 Pháp',
12
- 'Spain':'🇪🇸 Tây Ban Nha','England':'🏴󠁧󠁢󠁥󠁮󠁧󠁿 Anh','Portugal':'🇵🇹 Bồ Đào Nha','Netherlands':'🇳🇱 Hà Lan',
13
- 'Italy':'🇮🇹 Ý','Belgium':'🇧🇪 Bỉ','Croatia':'🇭🇷 Croatia','Uruguay':'🇺🇾 Uruguay',
14
- 'Japan':'🇯🇵 Nhật Bản','South Korea':'🇰🇷 Hàn Quốc','Korea Republic':'🇰🇷 Hàn Quốc',
15
- 'Australia':'🇦🇺 Úc','Saudi Arabia':'🇸🇦 Ả Rập Xê Út','Iran':'🇮🇷 Iran','Qatar':'🇶🇦 Qatar',
16
- 'Canada':'🇨🇦 Canada','Morocco':'🇲🇦 Morocco','Senegal':'🇸🇳 Senegal','Ghana':'🇬🇭 Ghana',
17
- 'Cameroon':'🇨🇲 Cameroon','Nigeria':'🇳🇬 Nigeria','Tunisia':'🇹🇳 Tunisia',
18
- 'Ecuador':'🇪🇨 Ecuador','Chile':'🇨🇱 Chile','Peru':'🇵🇪 Peru','Paraguay':'🇵🇾 Paraguay',
19
- 'Bolivia':'🇧🇴 Bolivia','Venezuela':'🇻🇪 Venezuela','Panama':'🇵🇦 Panama',
20
- 'Costa Rica':'🇨🇷 Costa Rica','Honduras':'🇭🇳 Honduras','Jamaica':'🇯🇲 Jamaica',
21
- 'Serbia':'🇷🇸 Serbia','Switzerland':'🇨🇭 Thụy Sĩ','Denmark':'🇩🇰 Đan Mạch',
22
- 'Poland':'🇵🇱 Ba Lan','Wales':'🏴󠁧󠁢󠁷󠁬󠁳󠁿 Xứ Wales','Sweden':'🇸🇪 Thụy Điển',
23
- 'Norway':'🇳🇴 Na Uy','Austria':'🇦🇹 Áo','Czech Republic':'🇨🇿 Séc','Czechia':'🇨🇿 Séc',
24
- 'Scotland':'🏴󠁧󠁢󠁳󠁣󠁴󠁿 Scotland','Turkey':'🇹🇷 Thổ Nhĩ Kỳ','Türkiye':'🇹🇷 Thổ Nhĩ Kỳ',
25
- 'Ukraine':'🇺🇦 Ukraine','Egypt':'🇪🇬 Ai Cập','Algeria':'🇩🇿 Algeria',
26
- 'South Africa':'🇿🇦 Nam Phi','DR Congo':'🇨🇩 DR Congo',
27
- 'Ivory Coast':'🇨🇮 Bờ Biển Ngà',"Côte d'Ivoire":'🇨🇮 Bờ Biển Ngà',
28
- 'Indonesia':'🇮🇩 Indonesia','Vietnam':'🇻🇳 Việt Nam','Thailand':'🇹🇭 Thái Lan',
29
- 'China PR':'🇨🇳 Trung Quốc','New Zealand':'🇳🇿 New Zealand','Slovenia':'🇸🇮 Slovenia',
30
- 'Albania':'🇦🇱 Albania','Ireland':'🇮🇪 Ireland','Republic of Ireland':'🇮🇪 Ireland',
31
- 'Romania':'🇷🇴 Romania','Hungary':'🇭🇺 Hungary','Iceland':'🇮🇸 Iceland',
32
- 'Finland':'🇫🇮 Phần Lan','Greece':'🇬🇷 Hy Lạp','Uzbekistan':'🇺🇿 Uzbekistan',
33
- 'Iraq':'🇮🇶 Iraq','Jordan':'🇯🇴 Jordan','Palestine':'🇵🇸 Palestine',
34
- 'Bahrain':'🇧🇭 Bahrain','Oman':'🇴🇲 Oman','UAE':'🇦🇪 UAE',
35
- 'Cuba':'🇨🇺 Cuba','El Salvador':'🇸🇻 El Salvador','Guatemala':'🇬🇹 Guatemala',
36
- 'Trinidad and Tobago':'🇹🇹 Trinidad & Tobago','Haiti':'🇭🇹 Haiti',
37
- 'Mali':'🇲🇱 Mali','Burkina Faso':'🇧🇫 Burkina Faso','Mozambique':'🇲🇿 Mozambique',
38
- 'Tanzania':'🇹🇿 Tanzania','Zambia':'🇿🇲 Zambia','Kenya':'🇰🇪 Kenya',
39
- 'Angola':'🇦🇴 Angola','Guinea':'🇬🇳 Guinea','Benin':'🇧🇯 Benin',
40
- 'TBD':'🏳️ TBD','To Be Determined':'🏳️ TBD',
41
- };
42
- function _t(name){return WC_TEAMS[name]||WC_TEAMS[(name||'').trim()]||'🏴 '+name;}
43
-
44
- function switchWCTab(tab){
45
- document.querySelectorAll('.wc-tab').forEach(t=>t.classList.remove('active'));
46
- document.querySelectorAll('.wc-tab').forEach(t=>{
47
- if((tab==='news'&&t.textContent.includes('Tin'))||(tab==='fixtures'&&t.textContent.includes('Lịch'))||(tab==='standings'&&t.textContent.includes('BXH'))||(tab==='stats'&&t.textContent.includes('Thống')))t.classList.add('active');
48
  });
49
- const el=document.getElementById('wc-content');if(!el)return;
50
- if(!_wc2026Data){el.innerHTML='<div class="loading">Đang tải...</div>';return;}
51
- if(tab==='news')renderWCNews(el);
52
- else if(tab==='fixtures')renderWCFixtures(el);
53
- else if(tab==='standings')renderWCStandings(el);
54
- else if(tab==='stats')renderWCStats(el);
55
- }
56
-
57
- // === NEWS (always load og:image for missing thumbnails) ===
58
- function renderWCNews(el){
59
- const news=_wc2026Data.news||[];const road=_wc2026Data.road||[];
60
- const combined=[];let ni=0,ri=0;
61
- while(ni<news.length||ri<road.length){if(ni<news.length)combined.push({...news[ni++],_type:'news'});if(ri<road.length)combined.push({...road[ri++],_type:'road'});}
62
- if(!combined.length){el.innerHTML='<div class="loading">Đang cập nhật...</div>';return;}
63
- let h='<div class="wc-news-grid">';
64
- combined.slice(0,20).forEach((a,i)=>{
65
- const badge=a._type==='road'?'<span class="badge badge-wc">Đường tới WC</span>':'<span class="badge badge-fpt">Tin WC</span>';
66
- h+=`<div class="wc-news-item" onclick="readArticle('${esc(a.link)}')">`;
67
- h+=`<div class="wc-news-img" id="wcimg-${i}">${a.img?`<img src="${esc(a.img)}" onerror="loadWCImg(${i},'${esc(a.link)}')">`:''}</div>`;
68
- h+=`<div class="wc-news-text">${badge}<div class="wc-news-title">${esc(a.title)}</div><div class="wc-news-via">${esc(a.source||'')}</div></div></div>`;
69
- });
70
- h+='</div>';el.innerHTML=h;
71
- // Load images for items without img
72
- combined.slice(0,20).forEach((a,i)=>{if(!a.img)loadWCImg(i,a.link);});
73
- }
74
- window.loadWCImg=function(i,url){
75
- const el=document.getElementById('wcimg-'+i);if(!el)return;
76
- fetch('/api/article?url='+encodeURIComponent(url)).then(r=>r.json()).then(d=>{
77
- const img=d?.og_image||d?.img||'';
78
- if(img)el.innerHTML=`<img src="${esc(img)}" onerror="this.style.display='none'">`;
79
- }).catch(()=>{});
80
- };
81
-
82
- // === FIXTURES (sorted by date, VN names + flags, livescore) ===
83
- function renderWCFixtures(el){
84
- const d=_wc2026Data.fixtures||{};const matches=d.matches||[];
85
- if(!matches.length){el.innerHTML='<div class="loading">Đang tải lịch thi đấu...</div>';return;}
86
- const sorted=[...matches].sort((a,b)=>(a.date_utc||'').localeCompare(b.date_utc||''));
87
- const byDate={};
88
- sorted.forEach(m=>{const day=m.date_vn?m.date_vn.split(' ').slice(1).join(' '):'TBD';if(!byDate[day])byDate[day]=[];byDate[day].push(m);});
89
- let h='<div style="max-height:450px;overflow-y:auto;padding:2px">';
90
- h+=`<div style="font-size:10px;color:#6a9fca;text-align:center;padding:3px 0">🏆 World Cup 2026 · ${d.total||104} trận · Giờ VN · 🔴 Livescore tự động</div>`;
91
- for(const[day,dm]of Object.entries(byDate)){
92
- h+=`<div style="font-size:11px;font-weight:800;color:#f0c040;padding:6px 4px 2px;margin-top:3px;border-bottom:1px solid #1a3a5a">📅 ${esc(day)}</div>`;
93
- dm.forEach(m=>{
94
- const live=m.status==='live',done=m.status==='finished';
95
- const bc=live?'#e74c3c':done?'#2d8659':'#1a3a5a';
96
- const time=m.date_vn?m.date_vn.split(' ')[0]:'';
97
- h+=`<div style="padding:4px;margin:2px 0;border-left:3px solid ${bc};border-radius:3px;background:#0a1520">`;
98
- h+=`<div style="display:flex;justify-content:space-between;font-size:8px;color:#6a9fca">`;
99
- h+=`<span>🕐 ${esc(time)}${m.group?' · '+esc(m.group):''}</span>`;
100
- if(m.location)h+=`<span style="max-width:45%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">🏟 ${esc(m.location)}</span>`;
101
- h+='</div>';
102
- h+='<div style="display:flex;align-items:center;gap:2px;margin-top:2px">';
103
- h+=`<span style="flex:1;text-align:right;font-size:11px;color:#eee">${_t(m.home)}</span>`;
104
- if(live)h+=`<span style="min-width:44px;text-align:center;font-size:12px;font-weight:900;color:#e74c3c;background:#1a0808;padding:1px 4px;border-radius:3px">${esc(m.score)}</span>`;
105
- else if(done)h+=`<span style="min-width:44px;text-align:center;font-size:11px;font-weight:800;color:#4ade80">${esc(m.score)}</span>`;
106
- else h+=`<span style="min-width:44px;text-align:center;font-size:10px;color:#555">vs</span>`;
107
- h+=`<span style="flex:1;text-align:left;font-size:11px;color:#eee">${_t(m.away)}</span>`;
108
- h+='</div>';
109
- if(live)h+='<div style="text-align:center;font-size:8px;color:#e74c3c;font-weight:700">● LIVE</div>';
110
- h+='</div>';
111
- });
112
- }
113
- h+='</div>';el.innerHTML=h;
114
  }
115
 
116
- // === BXH (self-rendered from fixtures JSON — grouped by bảng, calculate points) ===
117
- function renderWCStandings(el){
118
- const d=_wc2026Data.fixtures||{};const matches=d.matches||[];
119
- // Extract group stage matches only
120
- const groupMatches=matches.filter(m=>m.group&&m.group.toLowerCase().includes('group'));
121
- if(!groupMatches.length){
122
- // Fallback: try bongda.com.vn HTML
123
- const bxh=_wc2026Data.standings||{};
124
- if(bxh.html&&bxh.html.length>100){
125
- el.innerHTML=`<style>.wc-bxh{max-height:450px;overflow-y:auto}.wc-bxh,.wc-bxh *{color:#ddd!important;background:transparent!important;border-color:#1a3a5a!important}.wc-bxh table{width:100%;border-collapse:collapse;font-size:11px}.wc-bxh th{background:#0b1a2a!important;color:#6a9fca!important;padding:5px 3px;font-size:9px}.wc-bxh td{padding:4px 3px;border-bottom:1px solid #0d1a2a!important}.wc-bxh img{width:16px;height:16px;vertical-align:middle;margin-right:3px}.wc-bxh strong{color:#f0c040!important}.wc-bxh .title-content{background:#0b1a2a!important;border-radius:4px;margin:6px 0 2px;padding:5px 8px}.wc-bxh .info,.wc-bxh .btns{display:none!important}</style><div class="wc-bxh">${bxh.html}</div>`;
126
- el.querySelectorAll('a').forEach(a=>a.addEventListener('click',e=>e.preventDefault()));
127
  return;
128
  }
129
- el.innerHTML='<div class="loading">BXH cập nhật khi giải bắt đầu 11/06/2026<br><small style="color:#6a9fca">🔴 Livescore tự động từ bongda.com.vn</small></div>';
130
- return;
131
- }
132
- // Calculate standings per group
133
- const groups={};
134
- groupMatches.forEach(m=>{
135
- const g=m.group;if(!groups[g])groups[g]={};
136
- [m.home,m.away].forEach(team=>{if(!groups[g][team])groups[g][team]={p:0,w:0,d:0,l:0,gf:0,ga:0,pts:0};});
137
- if(m.home_score!==null&&m.away_score!==null){
138
- const hs=parseInt(m.home_score),as=parseInt(m.away_score);
139
- if(!isNaN(hs)&&!isNaN(as)){
140
- groups[g][m.home].p++;groups[g][m.away].p++;
141
- groups[g][m.home].gf+=hs;groups[g][m.home].ga+=as;
142
- groups[g][m.away].gf+=as;groups[g][m.away].ga+=hs;
143
- if(hs>as){groups[g][m.home].w++;groups[g][m.home].pts+=3;groups[g][m.away].l++;}
144
- else if(hs<as){groups[g][m.away].w++;groups[g][m.away].pts+=3;groups[g][m.home].l++;}
145
- else{groups[g][m.home].d++;groups[g][m.home].pts+=1;groups[g][m.away].d++;groups[g][m.away].pts+=1;}
146
- }
147
- }
148
- });
149
- let h='<div style="max-height:450px;overflow-y:auto;padding:2px">';
150
- h+='<div style="font-size:10px;color:#6a9fca;text-align:center;padding:3px 0">🏆 BXH World Cup 2026 · 🔴 Livescore tự động</div>';
151
- const sortedGroups=Object.keys(groups).sort();
152
- sortedGroups.forEach(g=>{
153
- const teams=Object.entries(groups[g]).map(([name,s])=>({name,...s,gd:s.gf-s.ga})).sort((a,b)=>b.pts-a.pts||b.gd-a.gd||b.gf-a.gf);
154
- h+=`<div style="font-size:11px;font-weight:800;color:#8ab4d8;padding:6px 4px 3px;margin-top:6px;border-bottom:1px solid #1a3a5a">${esc(g)}</div>`;
155
- h+='<table style="width:100%;border-collapse:collapse;font-size:10px;margin:2px 0">';
156
- h+='<tr style="background:#0b1a2a"><th style="text-align:left;padding:4px;color:#6a9fca">Đội</th><th style="color:#6a9fca;padding:4px">Tr</th><th style="color:#6a9fca;padding:4px">T</th><th style="color:#6a9fca;padding:4px">H</th><th style="color:#6a9fca;padding:4px">B</th><th style="color:#6a9fca;padding:4px">BT</th><th style="color:#6a9fca;padding:4px">BB</th><th style="color:#6a9fca;padding:4px">HS</th><th style="color:#f0c040;padding:4px;font-weight:800">Đ</th></tr>';
157
- teams.forEach((t,i)=>{
158
- const bg=i<2?'#0a1a10':'transparent';// Top 2 qualify
159
- const border=i===1?'border-bottom:1px solid #2d8659':''
160
- h+=`<tr style="background:${bg};${border}"><td style="padding:4px;color:#eee;white-space:nowrap">${_t(t.name)}</td><td style="text-align:center;padding:4px;color:#999">${t.p}</td><td style="text-align:center;padding:4px;color:#4ade80">${t.w}</td><td style="text-align:center;padding:4px;color:#fbbf24">${t.d}</td><td style="text-align:center;padding:4px;color:#f87171">${t.l}</td><td style="text-align:center;padding:4px;color:#ccc">${t.gf}</td><td style="text-align:center;padding:4px;color:#ccc">${t.ga}</td><td style="text-align:center;padding:4px;color:${t.gd>=0?'#4ade80':'#f87171'}">${t.gd>0?'+':''}${t.gd}</td><td style="text-align:center;padding:4px;color:#f0c040;font-weight:800;font-size:12px">${t.pts}</td></tr>`;
161
  });
162
- h+='</table>';
163
- });
164
- h+='</div>';el.innerHTML=h;
165
- }
166
-
167
- // === STATS ===
168
- function renderWCStats(el){
169
- const d=_wc2026Data.stats||{};
170
- if(d.html&&d.html.length>100){
171
- el.innerHTML=`<style>.wc-st{max-height:450px;overflow-y:auto}.wc-st,.wc-st *{color:#ddd!important;background:transparent!important}.wc-st table{width:100%;border-collapse:collapse;font-size:11px}.wc-st th{background:#0b1a2a!important;color:#6a9fca!important;padding:5px}.wc-st td{padding:4px;border-bottom:1px solid #0d1a2a!important}.wc-st img{width:16px;height:16px;vertical-align:middle}.wc-st strong{color:#f0c040!important}</style><div class="wc-st">${d.html}</div>`;
172
- }else{
173
- el.innerHTML='<div class="loading">Thống kê cập nhật khi giải bắt đầu<br><small style="color:#6a9fca">Vua phá lưới · Kiến tạo · Thẻ phạt</small></div>';
174
  }
175
  }
176
-
177
- // === LIVE AUTO-REFRESH (90s) — cả fixtures LẪN BXH đều live ===
178
- function startWCLiveRefresh(){
179
- if(_wcRefreshInterval)clearInterval(_wcRefreshInterval);
180
- _wcRefreshInterval=setInterval(async()=>{
181
- if(!document.getElementById('view-home')?.classList.contains('active'))return;
182
- try{
183
- const data=await fetch('/api/wc2026').then(r=>r.json()).catch(()=>null);
184
- if(data){
185
- _wc2026Data=data;
186
- const wcEl=document.getElementById('wc-content');
187
- if(wcEl){
188
- const tab=document.querySelector('.wc-tab.active');
189
- if(tab){
190
- const t=tab.textContent;
191
- if(t.includes('Tin'))renderWCNews(wcEl);
192
- else if(t.includes('Lịch'))renderWCFixtures(wcEl);
193
- else if(t.includes('BXH'))renderWCStandings(wcEl);
194
- else if(t.includes('Thống'))renderWCStats(wcEl);
195
- }
196
- }
197
- }
198
- }catch(e){}
199
- },90000);
200
- }
201
- setTimeout(startWCLiveRefresh,5000);
 
1
+ // Add WC Highlight tab handler to wc2026_v2.js
2
+
3
+ // Override switchWCTab to handle 'highlights' tab
4
+ const _origSwitchWC = typeof switchWCTab !== 'undefined' ? switchWCTab : null;
5
+
6
+ function switchWCTab(tab) {
7
+ document.querySelectorAll('.wc-tab').forEach(t => t.classList.remove('active'));
8
+ document.querySelectorAll('.wc-tab').forEach(t => {
9
+ if ((tab === 'news' && t.textContent.includes('Tin')) ||
10
+ (tab === 'fixtures' && t.textContent.includes('Lịch')) ||
11
+ (tab === 'standings' && t.textContent.includes('BXH')) ||
12
+ (tab === 'highlights' && t.textContent.includes('Highlight')) ||
13
+ (tab === 'stats' && t.textContent.includes('Thống')))
14
+ t.classList.add('active');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  });
16
+ const el = document.getElementById('wc-content');
17
+ if (!el) return;
18
+ if (!_wc2026Data && tab !== 'highlights') { el.innerHTML = '<div class="loading">Đang tải...</div>'; return; }
19
+ if (tab === 'news') renderWCNews(el);
20
+ else if (tab === 'fixtures') renderWCFixtures(el);
21
+ else if (tab === 'standings') renderWCStandings(el);
22
+ else if (tab === 'highlights') renderWCHighlights(el);
23
+ else if (tab === 'stats') renderWCStats(el);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
+ // === WC HIGHLIGHTS TAB (from xemlaibongda.top/the-gioi/world-cup-qualifiers) ===
27
+ async function renderWCHighlights(el) {
28
+ el.innerHTML = '<div class="loading">Đang tải highlight World Cup...</div>';
29
+ try {
30
+ const vids = await fetch('/api/highlights/world-cup').then(r => r.json()).catch(() => []);
31
+ if (!vids || !vids.length) {
32
+ el.innerHTML = '<div class="loading">Chưa có highlight World Cup 2026</div>';
 
 
 
 
33
  return;
34
  }
35
+ let h = '<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:6px;max-height:450px;overflow-y:auto;padding:4px">';
36
+ vids.slice(0, 20).forEach((v, i) => {
37
+ h += `<div style="cursor:pointer;border-radius:6px;overflow:hidden;background:#0a1520" onclick="openHighlightFeed('world-cup',${i})">`;
38
+ h += `<div style="position:relative;aspect-ratio:16/9;background:#1a2a3a">${v.img ? `<img src="${esc(v.img)}" style="width:100%;height:100%;object-fit:cover">` : ''}<div class="card-play">▶</div></div>`;
39
+ h += `<div style="padding:4px 6px;font-size:10px;color:#ccc;line-height:1.2;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden">${esc(v.title)}</div>`;
40
+ h += '</div>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  });
42
+ h += '</div>';
43
+ el.innerHTML = h;
44
+ } catch(e) {
45
+ el.innerHTML = '<div class="loading">Lỗi tải highlight</div>';
 
 
 
 
 
 
 
 
46
  }
47
  }