Spaces:
Running
Running
RESTORE 2ced164: Revert to multi-file JS (pre-merge)
Browse files- static/yt_live.js +1 -114
static/yt_live.js
CHANGED
|
@@ -296,11 +296,6 @@
|
|
| 296 |
} catch(e){ alert('Không hỗ trợ PiP'); }
|
| 297 |
};
|
| 298 |
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
// MyTV section loaded separately
|
| 302 |
-
|
| 303 |
-
|
| 304 |
function pinBlock(){
|
| 305 |
const h = document.getElementById('view-home');
|
| 306 |
if(!h||document.getElementById('vtv-block')) return;
|
|
@@ -408,123 +403,15 @@
|
|
| 408 |
};
|
| 409 |
}
|
| 410 |
|
| 411 |
-
|
| 412 |
-
// ===== MyTV Highlights Section =====
|
| 413 |
-
let _mytvInserted = false;
|
| 414 |
-
|
| 415 |
-
function buildMyTVBlock(){
|
| 416 |
-
const w = document.createElement('div');
|
| 417 |
-
w.className = 'vtv-wrap';
|
| 418 |
-
w.id = 'mytv-block';
|
| 419 |
-
w.style.borderColor = '#e85d04';
|
| 420 |
-
w.innerHTML =
|
| 421 |
-
'<div class="vtv-head" style="background:linear-gradient(90deg,#4a1a00,#1a1a1a)">' +
|
| 422 |
-
'<span class="vtv-title" style="color:#f0c040">🎬 MyTV Highlights & Full Trận</span>' +
|
| 423 |
-
'<span class="vtv-badge" style="color:#f0c040">● NEW</span>' +
|
| 424 |
-
'</div>' +
|
| 425 |
-
'<div id="mytv-grid" style="display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:8px;">' +
|
| 426 |
-
'<div class="vtv-err" style="grid-column:1/-1;flex-direction:row;gap:8px;padding:12px">' +
|
| 427 |
-
'<div class="vtv-spinner" style="width:16px;height:16px;border-width:2px"></div> Đang tải video MyTV...' +
|
| 428 |
-
'</div>' +
|
| 429 |
-
'</div>';
|
| 430 |
-
return w;
|
| 431 |
-
}
|
| 432 |
-
|
| 433 |
-
async function loadMyTVVideos(){
|
| 434 |
-
const grid = document.getElementById('mytv-grid');
|
| 435 |
-
if(!grid) return;
|
| 436 |
-
try{
|
| 437 |
-
const r = await fetch('/api/mytv/videos?limit=10', {signal: AbortSignal.timeout(15000)});
|
| 438 |
-
const videos = await r.json();
|
| 439 |
-
if(!videos || !videos.length){
|
| 440 |
-
grid.innerHTML = '<div class="vtv-err" style="grid-column:1/-1">Chưa có video MyTV</div>';
|
| 441 |
-
return;
|
| 442 |
-
}
|
| 443 |
-
let h = '';
|
| 444 |
-
videos.forEach((v, i)=>{
|
| 445 |
-
const title = esc(v.title || 'Video');
|
| 446 |
-
const url = v.url || '';
|
| 447 |
-
const type = v.type === 'full_match' ? 'FULL' : 'HL';
|
| 448 |
-
const typeColor = v.type === 'full_match' ? '#5cb87a' : '#f0c040';
|
| 449 |
-
h += '<div class="mytv-item" onclick="window._playMyTVVideo(\''+esc(url)+'\',\''+esc(title)+'\')" style="background:#1a1a1a;border:1px solid #333;border-radius:8px;overflow:hidden;cursor:pointer;transition:all .2s;" onmouseover="this.style.borderColor=\'#e85d04\'" onmouseout="this.style.borderColor=\'#333\'">' +
|
| 450 |
-
'<div style="position:relative;aspect-ratio:16/9;background:linear-gradient(135deg,#1a2a1f,#0d1117);display:flex;align-items:center;justify-content:center;">' +
|
| 451 |
-
'<span style="font-size:28px;">⚽</span>' +
|
| 452 |
-
'<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.3);opacity:0;transition:opacity .2s;" class="mytv-play-overlay">' +
|
| 453 |
-
'<span style="font-size:32px;">▶</span>' +
|
| 454 |
-
'</div>' +
|
| 455 |
-
'<span style="position:absolute;top:4px;right:4px;font-size:8px;font-weight:700;color:'+typeColor+';background:rgba(0,0,0,.7);padding:2px 6px;border-radius:3px;">'+type+'</span>' +
|
| 456 |
-
'</div>' +
|
| 457 |
-
'<div style="padding:6px 8px;">' +
|
| 458 |
-
'<div style="font-size:11px;font-weight:700;color:#ddd;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">'+title+'</div>' +
|
| 459 |
-
'<div style="font-size:9px;color:#888;margin-top:2px;">MyTV.com.vn</div>' +
|
| 460 |
-
'</div>' +
|
| 461 |
-
'</div>';
|
| 462 |
-
});
|
| 463 |
-
grid.innerHTML = h;
|
| 464 |
-
}catch(e){
|
| 465 |
-
grid.innerHTML = '<div class="vtv-err" style="grid-column:1/-1">Không tải được video MyTV</div>';
|
| 466 |
-
}
|
| 467 |
-
}
|
| 468 |
-
|
| 469 |
-
function injectMyTVBlock(){
|
| 470 |
-
if(_mytvInserted) return;
|
| 471 |
-
const vtvBlock = document.getElementById('vtv-block');
|
| 472 |
-
if(!vtvBlock) return;
|
| 473 |
-
if(document.getElementById('mytv-block')){ _mytvInserted = true; return; }
|
| 474 |
-
const mytv = buildMyTVBlock();
|
| 475 |
-
vtvBlock.insertAdjacentElement('afterend', mytv);
|
| 476 |
-
_mytvInserted = true;
|
| 477 |
-
loadMyTVVideos().catch(()=>{});
|
| 478 |
-
}
|
| 479 |
-
|
| 480 |
-
window._playMyTVVideo = function(url, title){
|
| 481 |
-
const overlay = document.getElementById('match-overlay');
|
| 482 |
-
const body = document.getElementById('mo-body');
|
| 483 |
-
const moTitle = document.getElementById('mo-title');
|
| 484 |
-
if(!overlay || !body) return;
|
| 485 |
-
moTitle.textContent = title || 'Video MyTV';
|
| 486 |
-
overlay.classList.add('active');
|
| 487 |
-
document.body.style.overflow = 'hidden';
|
| 488 |
-
body.innerHTML = '<div class="vtv-err" style="display:flex"><div class="vtv-spinner"></div><span style="margin-left:8px">Đang tải video MyTV...</span></div>';
|
| 489 |
-
|
| 490 |
-
fetch('/api/video_url?url='+encodeURIComponent(url))
|
| 491 |
-
.then(r => r.json())
|
| 492 |
-
.then(v => {
|
| 493 |
-
if(v && v.src){
|
| 494 |
-
const isHLS = v.type === 'hls' || v.src.includes('.m3u8');
|
| 495 |
-
body.innerHTML = '<div style="position:relative;width:100%;aspect-ratio:16/9;background:#000;border-radius:8px;overflow:hidden;">' +
|
| 496 |
-
'<video id="mytv-video-player" playsinline controls autoplay style="width:100%;height:100%;object-fit:contain;" src="'+v.src+'"></video>' +
|
| 497 |
-
'</div>' +
|
| 498 |
-
'<div style="margin-top:8px;font-size:12px;color:#888;">Nguồn: MyTV.com.vn</div>';
|
| 499 |
-
if(typeof Hls !== 'undefined' && Hls.isSupported()){
|
| 500 |
-
const video = document.getElementById('mytv-video-player');
|
| 501 |
-
if(video){ const hls = new Hls(); hls.loadSource(v.src); hls.attachMedia(video); }
|
| 502 |
-
}
|
| 503 |
-
} else {
|
| 504 |
-
body.innerHTML = '<div class="vtv-err" style="display:flex"><span>Không tìm thấy video. </span><a href="'+esc(url)+'" target="_blank" style="color:#5cb87a;margin-left:4px;">Mở trực tiếp trên MyTV →</a></div>';
|
| 505 |
-
}
|
| 506 |
-
})
|
| 507 |
-
.catch(e => {
|
| 508 |
-
body.innerHTML = '<div class="vtv-err" style="display:flex"><span>Lỗi tải video. </span><a href="'+esc(url)+'" target="_blank" style="color:#5cb87a;margin-left:4px;">Mở trực tiếp trên MyTV →</a></div>';
|
| 509 |
-
});
|
| 510 |
-
};
|
| 511 |
-
|
| 512 |
// Override loadHome to inject VTV block
|
| 513 |
const _origLoadHome = window.loadHome;
|
| 514 |
if(_origLoadHome && !_origLoadHome.__vtvWrapped){
|
| 515 |
window.loadHome = async function(){
|
| 516 |
-
// Skip if already loaded (guard against double-wrap)
|
| 517 |
-
if(window._homeLoaded) return;
|
| 518 |
const old = document.getElementById('vtv-block');
|
| 519 |
if(old) old.remove();
|
| 520 |
_blockInserted = false;
|
| 521 |
const r = await _origLoadHome.apply(this, arguments);
|
| 522 |
-
try{
|
| 523 |
-
pinBlock();
|
| 524 |
-
// Inject MyTV section after VTV block
|
| 525 |
-
setTimeout(()=>{ try{ injectMyTVBlock(); }catch(e){ console.warn('MyTV inject error:', e); } }, 500);
|
| 526 |
-
setTimeout(()=>{ try{ injectMyTVBlock(); }catch(e){} }, 2000);
|
| 527 |
-
}catch(e){ console.warn('VTV pinBlock error:', e); }
|
| 528 |
return r;
|
| 529 |
};
|
| 530 |
window.loadHome.__vtvWrapped = true;
|
|
|
|
| 296 |
} catch(e){ alert('Không hỗ trợ PiP'); }
|
| 297 |
};
|
| 298 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
function pinBlock(){
|
| 300 |
const h = document.getElementById('view-home');
|
| 301 |
if(!h||document.getElementById('vtv-block')) return;
|
|
|
|
| 403 |
};
|
| 404 |
}
|
| 405 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
// Override loadHome to inject VTV block
|
| 407 |
const _origLoadHome = window.loadHome;
|
| 408 |
if(_origLoadHome && !_origLoadHome.__vtvWrapped){
|
| 409 |
window.loadHome = async function(){
|
|
|
|
|
|
|
| 410 |
const old = document.getElementById('vtv-block');
|
| 411 |
if(old) old.remove();
|
| 412 |
_blockInserted = false;
|
| 413 |
const r = await _origLoadHome.apply(this, arguments);
|
| 414 |
+
try{ pinBlock(); }catch(e){}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
return r;
|
| 416 |
};
|
| 417 |
window.loadHome.__vtvWrapped = true;
|