bep40 commited on
Commit
1ec593c
·
verified ·
1 Parent(s): 43c5903

revert: restore index.html to ed6aeb52

Browse files
Files changed (1) hide show
  1. static/index.html +3 -14
static/index.html CHANGED
@@ -33,23 +33,12 @@ function addCmt(id,n,t){let c=getCmts(id);c.push({n,t,d:new Date().toLocaleStrin
33
  function incS(id){let v=(LS.get('s_'+id)||0)+1;LS.set('s_'+id,v);return v;}
34
  function getS(id){return LS.get('s_'+id)||0}
35
  function doShare(title,articleUrl,img){const shareUrl=SPACE+'/s?url='+encodeURIComponent(articleUrl)+'&title='+encodeURIComponent(title)+'&img='+encodeURIComponent(img||'');const aid=hid(articleUrl||title);incS(aid);if(navigator.share)navigator.share({title,url:shareUrl}).catch(()=>{});else navigator.clipboard.writeText(shareUrl).then(()=>alert('Đã sao chép!')).catch(()=>{});}
36
- document.addEventListener('click',function(e){if(!e.target.closest('.cmt-panel')&&!e.target.closest('.tiktok-right-btn')){document.querySelectorAll('.cmt-panel.open').forEach(p=>p.classList.remove('open'));}});
37
- async function init(){
38
- _cats=await fetch('/api/categories').then(r=>r.json());
39
- let bar='<div class="cat active" data-cat="home">🏠</div><div class="cat" data-cat="video">🎬 Video</div>';
40
- _cats.forEach(c=>{bar+=`<div class="cat" data-cat="${c.id}">${c.name}</div>`;});
41
- document.getElementById('cat-bar').innerHTML=bar;
42
- document.querySelectorAll('.cat').forEach(t=>{t.onclick=()=>switchCat(t.dataset.cat);});
43
- await loadHome();
44
- const params=new URLSearchParams(location.search);
45
- const openUrl=params.get('open');
46
- if(openUrl){history.replaceState(null,'',location.pathname);readArticle(openUrl,'vne');}
47
- }
48
  function switchCat(id){document.querySelectorAll('.cat').forEach(x=>x.classList.remove('active'));document.querySelector(`[data-cat="${id}"]`)?.classList.add('active');document.querySelectorAll('.view').forEach(x=>x.classList.remove('active'));document.querySelectorAll('video').forEach(v=>v.pause());if(id==='home')document.getElementById('view-home').classList.add('active');else if(id==='video'){document.getElementById('view-video').classList.add('active');loadVideos();}else{document.getElementById('view-cat').classList.add('active');loadCat(id);}}
49
  function showView(id){document.querySelectorAll('.view').forEach(x=>x.classList.remove('active'));document.getElementById(id).classList.add('active');}
50
  async function loadHome(){const[news,hl,sh]=await Promise.all([fetch('/api/homepage').then(r=>r.json()),fetch('/api/highlights').then(r=>r.json()),fetch('/api/shorts').then(r=>r.json())]);let h='';if(sh&&sh.length){h+='<div class="slider-wrap"><div class="slider-header"><span class="slider-label">📱 Shorts 24h</span></div><div class="slider-track">';sh.forEach((a,i)=>{h+=`<div class="slider-item shorts-item" onclick="openTikTok('shorts','${a.link}')"><div class="slider-thumb shorts-thumb">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="slider-title">${a.title}</div></div>`;});h+='</div></div>';}if(hl&&hl.length){h+='<div class="slider-wrap"><div class="slider-header"><span class="slider-label">🎬 Highlight</span></div><div class="slider-track">';hl.forEach((a,i)=>{h+=`<div class="slider-item" onclick="openTikTok('highlights','${a.link}')"><div class="slider-thumb">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="slider-title">${a.title}</div></div>`;});h+='</div></div>';}const groups={};news.forEach(a=>{if(!groups[a.group])groups[a.group]=[];groups[a.group].push(a);});for(const[g,arts] of Object.entries(groups)){h+=`<div class="section-title">${g}</div><div class="grid">`;arts.slice(0,6).forEach(a=>{const bg=a.source==='bbc'?'badge-bbc':a.source==='bdp'?'badge-bdp':'badge-vne';const lb=a.source==='bbc'?'BBC':a.source==='bdp'?'BDP':'VnE';const aid=hid(a.link);h+=`<div class="card" onclick="readArticle('${a.link.replace(/'/g,"\\'")}','${a.source}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}</div><div class="card-body"><span class="badge ${bg}">${lb}</span><div class="card-title">${a.title}</div><div class="card-meta"><span>👁${getV(aid)}</span><span>💬${getCmts(aid).length}</span></div></div></div>`;});h+='</div>';}document.getElementById('view-home').innerHTML=h;}
51
  async function loadCat(id){const el=document.getElementById('view-cat');el.innerHTML='<div class="loading">Đang tải...</div>';const arts=await fetch('/api/category/'+id).then(r=>r.json());if(!arts.length){el.innerHTML='<div class="loading">Không có tin</div>';return;}let h='<div class="grid">';arts.forEach(a=>{const bg=a.source==='bbc'?'badge-bbc':a.source==='bdp'?'badge-bdp':'badge-vne';h+=`<div class="card" onclick="readArticle('${a.link.replace(/'/g,"\\'")}','${a.source}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}</div><div class="card-body"><span class="badge ${bg}">${a.source}</span><div class="card-title">${a.title}</div></div></div>`;});h+='</div>';el.innerHTML=h;}
52
- async function readArticle(url,source){showView('view-article');const el=document.getElementById('view-article');el.innerHTML='<div class="loading">Đang tải...</div>';const aid=hid(url);incV(aid);const data=await fetch('/api/article?url='+encodeURIComponent(url)).then(r=>r.json());if(!data||data.error){el.innerHTML=`<button class="back-btn" onclick="switchCat('home')">← Quay lại</button><div class="article-view" style="text-align:center;padding:60px 20px"><p style="color:#aaa;margin-bottom:12px">Không tải được nội dung</p><a href="${url}" target="_blank" style="color:#5cb87a;font-size:14px">📰 Mở bài viết gốc</a></div>`;return;}const ogImg=data.og_image||'';let h=`<button class="back-btn" onclick="switchCat('home')">← Quay lại</button><div class="article-view"><h1 class="article-title">${data.title}</h1>`;if(data.summary)h+=`<div class="article-summary">${data.summary}</div>`;data.body.forEach(b=>{if(b.type==='p')h+=`<p class="article-p">${b.text}</p>`;else if(b.type==='img')h+=`<img class="article-img" src="${b.src}">`;else if(b.type==='heading')h+=`<h2 class="article-h2">${b.text}</h2>`;});h+=`<div class="article-actions"><button onclick="doShare('${data.title.replace(/'/g,"\\'")}','${url.replace(/'/g,"\\'")}','${ogImg.replace(/'/g,"\\'")}')">📤 Chia sẻ (${getS(aid)})</button><button>👁 ${getV(aid)}</button><button>💬 ${getCmts(aid).length}</button></div>`;h+=renderCmtSection(aid);h+='</div>';el.innerHTML=h;window.scrollTo(0,0);}
53
  function renderCmtSection(aid){const cmts=getCmts(aid);let h=`<div class="cmt-section"><h3>💬 Bình luận (${cmts.length})</h3><div id="cl-${aid}">`;cmts.slice().reverse().forEach(c=>{h+=`<div class="cmt-item"><b>${c.n}</b> <small>${c.d}</small><p>${c.t}</p></div>`;});if(!cmts.length)h+='<p style="color:#666;font-size:11px">Chưa có bình luận</p>';h+=`</div><div class="cmt-form"><input id="cn-${aid}" placeholder="Tên"><input id="ct-${aid}" placeholder="Bình luận..."><button onclick="submitCmt('${aid}')">Gửi</button></div></div>`;return h;}
54
  function submitCmt(aid){const n=document.getElementById('cn-'+aid),t=document.getElementById('ct-'+aid);if(!n.value.trim()||!t.value.trim())return;addCmt(aid,n.value.trim(),t.value.trim());t.value='';const cmts=getCmts(aid);let h='';cmts.slice().reverse().forEach(c=>{h+=`<div class="cmt-item"><b>${c.n}</b> <small>${c.d}</small><p>${c.t}</p></div>`;});document.getElementById('cl-'+aid).innerHTML=h;}
55
  async function loadVideos(){const el=document.getElementById('view-video');if(el.dataset.loaded)return;el.innerHTML='<div class="loading">Đang tải...</div>';const[hl,bdp]=await Promise.all([fetch('/api/highlights').then(r=>r.json()),fetch('/api/bdp_videos').then(r=>r.json())]);let h='<div class="section-title">🎬 Highlight</div><div class="grid">';hl.forEach((a,i)=>{h+=`<div class="card" onclick="openTikTok('highlights','${a.link}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="card-body"><span class="badge badge-24h">24h</span><div class="card-title">${a.title}</div></div></div>`;});h+='</div>';if(bdp.length){h+='<div class="section-title">⚽ BDP</div><div class="grid">';bdp.forEach((a,i)=>{h+=`<div class="card" onclick="openTikTok('bdp','${a.link}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="card-body"><span class="badge badge-bdp">BDP</span><div class="card-title">${a.title}</div></div></div>`;});h+='</div>';}el.innerHTML=h;el.dataset.loaded='1';}
@@ -69,7 +58,7 @@ function initFeed(){const feed=document.getElementById('tiktok-feed');if(!feed)r
69
  let cur=-1;function act(idx){if(idx===cur)return;closeAllCmtPanels();slides.forEach((sl,i)=>{const v=sl.querySelector('video');if(i===idx){v.currentTime=0;v.play().catch(()=>setTimeout(()=>v.play().catch(()=>{}),500));const aid=sl.dataset.aid;if(aid){incV(aid);const vc=document.getElementById('vc-'+i);if(vc)vc.textContent=getV(aid);}}else v.pause();});cur=idx;}
70
  let sT;feed.addEventListener('scroll',()=>{clearTimeout(sT);sT=setTimeout(()=>{const rect=feed.getBoundingClientRect();const ctr=rect.top+rect.height/2;let best=-1,bestD=1e9;slides.forEach((sl,i)=>{const d=Math.abs(sl.getBoundingClientRect().top+sl.getBoundingClientRect().height/2-ctr);if(d<bestD){bestD=d;best=i;}});if(best>=0)act(best);},150);});
71
  setTimeout(()=>act(0),500);
72
- slides.forEach(sl=>{const v=sl.querySelector('video');v.addEventListener('click',e=>{e.preventDefault();closeAllCmtPanels();v.paused?v.play().catch(()=>{}):v.pause();});});}
73
  function toggleMute(){const f=document.getElementById('tiktok-feed');if(!f)return;const vs=f.querySelectorAll('video');const m=!vs[0]?.muted;vs.forEach(v=>v.muted=m);f.querySelectorAll('.tiktok-unmute').forEach(b=>b.textContent=m?'🔇':'🔊');}
74
  function toggleContain(btn){const sl=btn.closest('.tiktok-slide');sl.classList.toggle('contain-mode');btn.textContent=sl.classList.contains('contain-mode')?'⤢':'⬇';}
75
  function seekV(i,s){const sl=document.getElementById('tslide-'+i);if(sl){const v=sl.querySelector('video');if(v)v.currentTime=Math.max(0,Math.min(v.duration||9999,v.currentTime+s));}}
 
33
  function incS(id){let v=(LS.get('s_'+id)||0)+1;LS.set('s_'+id,v);return v;}
34
  function getS(id){return LS.get('s_'+id)||0}
35
  function doShare(title,articleUrl,img){const shareUrl=SPACE+'/s?url='+encodeURIComponent(articleUrl)+'&title='+encodeURIComponent(title)+'&img='+encodeURIComponent(img||'');const aid=hid(articleUrl||title);incS(aid);if(navigator.share)navigator.share({title,url:shareUrl}).catch(()=>{});else navigator.clipboard.writeText(shareUrl).then(()=>alert('Đã sao chép!')).catch(()=>{});}
36
+ async function init(){_cats=await fetch('/api/categories').then(r=>r.json());let bar='<div class="cat active" data-cat="home">🏠</div><div class="cat" data-cat="video">🎬 Video</div>';_cats.forEach(c=>{bar+=`<div class="cat" data-cat="${c.id}">${c.name}</div>`;});document.getElementById('cat-bar').innerHTML=bar;document.querySelectorAll('.cat').forEach(t=>{t.onclick=()=>switchCat(t.dataset.cat);});await loadHome();const pending=localStorage.getItem('pending_article');if(pending){localStorage.removeItem('pending_article');let src='vne';if(pending.includes('bbc.com'))src='bbc';readArticle(pending,src);}}
 
 
 
 
 
 
 
 
 
 
 
37
  function switchCat(id){document.querySelectorAll('.cat').forEach(x=>x.classList.remove('active'));document.querySelector(`[data-cat="${id}"]`)?.classList.add('active');document.querySelectorAll('.view').forEach(x=>x.classList.remove('active'));document.querySelectorAll('video').forEach(v=>v.pause());if(id==='home')document.getElementById('view-home').classList.add('active');else if(id==='video'){document.getElementById('view-video').classList.add('active');loadVideos();}else{document.getElementById('view-cat').classList.add('active');loadCat(id);}}
38
  function showView(id){document.querySelectorAll('.view').forEach(x=>x.classList.remove('active'));document.getElementById(id).classList.add('active');}
39
  async function loadHome(){const[news,hl,sh]=await Promise.all([fetch('/api/homepage').then(r=>r.json()),fetch('/api/highlights').then(r=>r.json()),fetch('/api/shorts').then(r=>r.json())]);let h='';if(sh&&sh.length){h+='<div class="slider-wrap"><div class="slider-header"><span class="slider-label">📱 Shorts 24h</span></div><div class="slider-track">';sh.forEach((a,i)=>{h+=`<div class="slider-item shorts-item" onclick="openTikTok('shorts','${a.link}')"><div class="slider-thumb shorts-thumb">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="slider-title">${a.title}</div></div>`;});h+='</div></div>';}if(hl&&hl.length){h+='<div class="slider-wrap"><div class="slider-header"><span class="slider-label">🎬 Highlight</span></div><div class="slider-track">';hl.forEach((a,i)=>{h+=`<div class="slider-item" onclick="openTikTok('highlights','${a.link}')"><div class="slider-thumb">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="slider-title">${a.title}</div></div>`;});h+='</div></div>';}const groups={};news.forEach(a=>{if(!groups[a.group])groups[a.group]=[];groups[a.group].push(a);});for(const[g,arts] of Object.entries(groups)){h+=`<div class="section-title">${g}</div><div class="grid">`;arts.slice(0,6).forEach(a=>{const bg=a.source==='bbc'?'badge-bbc':a.source==='bdp'?'badge-bdp':'badge-vne';const lb=a.source==='bbc'?'BBC':a.source==='bdp'?'BDP':'VnE';const aid=hid(a.link);h+=`<div class="card" onclick="readArticle('${a.link.replace(/'/g,"\\'")}','${a.source}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}</div><div class="card-body"><span class="badge ${bg}">${lb}</span><div class="card-title">${a.title}</div><div class="card-meta"><span>👁${getV(aid)}</span><span>💬${getCmts(aid).length}</span></div></div></div>`;});h+='</div>';}document.getElementById('view-home').innerHTML=h;}
40
  async function loadCat(id){const el=document.getElementById('view-cat');el.innerHTML='<div class="loading">Đang tải...</div>';const arts=await fetch('/api/category/'+id).then(r=>r.json());if(!arts.length){el.innerHTML='<div class="loading">Không có tin</div>';return;}let h='<div class="grid">';arts.forEach(a=>{const bg=a.source==='bbc'?'badge-bbc':a.source==='bdp'?'badge-bdp':'badge-vne';h+=`<div class="card" onclick="readArticle('${a.link.replace(/'/g,"\\'")}','${a.source}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}</div><div class="card-body"><span class="badge ${bg}">${a.source}</span><div class="card-title">${a.title}</div></div></div>`;});h+='</div>';el.innerHTML=h;}
41
+ async function readArticle(url,source){if(source!=='vne'&&source!=='bbc'){window.open(url,'_blank');return;}showView('view-article');const el=document.getElementById('view-article');el.innerHTML='<div class="loading">Đang tải...</div>';const aid=hid(url);incV(aid);const data=await fetch('/api/article?url='+encodeURIComponent(url)).then(r=>r.json());if(!data||data.error){el.innerHTML=`<button class="back-btn" onclick="switchCat('home')">← Quay lại</button><div class="loading"><a href="${url}" target="_blank" style="color:#5cb87a">Mở link gốc</a></div>`;return;}const ogImg=data.og_image||'';let h=`<button class="back-btn" onclick="switchCat('home')">← Quay lại</button><div class="article-view"><h1 class="article-title">${data.title}</h1>`;if(data.summary)h+=`<div class="article-summary">${data.summary}</div>`;data.body.forEach(b=>{if(b.type==='p')h+=`<p class="article-p">${b.text}</p>`;else if(b.type==='img')h+=`<img class="article-img" src="${b.src}">`;else if(b.type==='heading')h+=`<h2 class="article-h2">${b.text}</h2>`;});h+=`<div class="article-actions"><button onclick="doShare('${data.title.replace(/'/g,"\\'")}','${url.replace(/'/g,"\\'")}','${ogImg.replace(/'/g,"\\'")}')">📤 Chia sẻ (${getS(aid)})</button><button>👁 ${getV(aid)}</button><button>💬 ${getCmts(aid).length}</button></div>`;h+=renderCmtSection(aid);h+='</div>';el.innerHTML=h;window.scrollTo(0,0);}
42
  function renderCmtSection(aid){const cmts=getCmts(aid);let h=`<div class="cmt-section"><h3>💬 Bình luận (${cmts.length})</h3><div id="cl-${aid}">`;cmts.slice().reverse().forEach(c=>{h+=`<div class="cmt-item"><b>${c.n}</b> <small>${c.d}</small><p>${c.t}</p></div>`;});if(!cmts.length)h+='<p style="color:#666;font-size:11px">Chưa có bình luận</p>';h+=`</div><div class="cmt-form"><input id="cn-${aid}" placeholder="Tên"><input id="ct-${aid}" placeholder="Bình luận..."><button onclick="submitCmt('${aid}')">Gửi</button></div></div>`;return h;}
43
  function submitCmt(aid){const n=document.getElementById('cn-'+aid),t=document.getElementById('ct-'+aid);if(!n.value.trim()||!t.value.trim())return;addCmt(aid,n.value.trim(),t.value.trim());t.value='';const cmts=getCmts(aid);let h='';cmts.slice().reverse().forEach(c=>{h+=`<div class="cmt-item"><b>${c.n}</b> <small>${c.d}</small><p>${c.t}</p></div>`;});document.getElementById('cl-'+aid).innerHTML=h;}
44
  async function loadVideos(){const el=document.getElementById('view-video');if(el.dataset.loaded)return;el.innerHTML='<div class="loading">Đang tải...</div>';const[hl,bdp]=await Promise.all([fetch('/api/highlights').then(r=>r.json()),fetch('/api/bdp_videos').then(r=>r.json())]);let h='<div class="section-title">🎬 Highlight</div><div class="grid">';hl.forEach((a,i)=>{h+=`<div class="card" onclick="openTikTok('highlights','${a.link}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="card-body"><span class="badge badge-24h">24h</span><div class="card-title">${a.title}</div></div></div>`;});h+='</div>';if(bdp.length){h+='<div class="section-title">⚽ BDP</div><div class="grid">';bdp.forEach((a,i)=>{h+=`<div class="card" onclick="openTikTok('bdp','${a.link}')"><div class="card-img">${a.img?`<img src="${a.img}">`:''}<div class="card-play">▶</div></div><div class="card-body"><span class="badge badge-bdp">BDP</span><div class="card-title">${a.title}</div></div></div>`;});h+='</div>';}el.innerHTML=h;el.dataset.loaded='1';}
 
58
  let cur=-1;function act(idx){if(idx===cur)return;closeAllCmtPanels();slides.forEach((sl,i)=>{const v=sl.querySelector('video');if(i===idx){v.currentTime=0;v.play().catch(()=>setTimeout(()=>v.play().catch(()=>{}),500));const aid=sl.dataset.aid;if(aid){incV(aid);const vc=document.getElementById('vc-'+i);if(vc)vc.textContent=getV(aid);}}else v.pause();});cur=idx;}
59
  let sT;feed.addEventListener('scroll',()=>{clearTimeout(sT);sT=setTimeout(()=>{const rect=feed.getBoundingClientRect();const ctr=rect.top+rect.height/2;let best=-1,bestD=1e9;slides.forEach((sl,i)=>{const d=Math.abs(sl.getBoundingClientRect().top+sl.getBoundingClientRect().height/2-ctr);if(d<bestD){bestD=d;best=i;}});if(best>=0)act(best);},150);});
60
  setTimeout(()=>act(0),500);
61
+ slides.forEach(sl=>{const v=sl.querySelector('video');v.addEventListener('click',e=>{e.preventDefault();v.paused?v.play().catch(()=>{}):v.pause();});});}
62
  function toggleMute(){const f=document.getElementById('tiktok-feed');if(!f)return;const vs=f.querySelectorAll('video');const m=!vs[0]?.muted;vs.forEach(v=>v.muted=m);f.querySelectorAll('.tiktok-unmute').forEach(b=>b.textContent=m?'🔇':'🔊');}
63
  function toggleContain(btn){const sl=btn.closest('.tiktok-slide');sl.classList.toggle('contain-mode');btn.textContent=sl.classList.contains('contain-mode')?'⤢':'⬇';}
64
  function seekV(i,s){const sl=document.getElementById('tslide-'+i);if(sl){const v=sl.querySelector('video');if(v)v.currentTime=Math.max(0,Math.min(v.duration||9999,v.currentTime+s));}}