Spaces:
Running
Running
Upload static/yt_live.js
Browse files- static/yt_live.js +172 -0
static/yt_live.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// === VNEWS — VTV LIVE + Inline Recorder v9 ===
|
| 2 |
+
// Features: PiP, mini-player, INLINE RECORDER, VTVGO POPUP players for each channel
|
| 3 |
+
// FIX v10: Correct VTVGO popup URLs for all channels + World Cup 2026 TS stream links
|
| 4 |
+
// FIX v11: Allow clicking off tabs (always clickable), better stream status handling
|
| 5 |
+
|
| 6 |
+
(function(){
|
| 7 |
+
if(window._ytLiveLoaded) return;
|
| 8 |
+
window._ytLiveLoaded = true;
|
| 9 |
+
|
| 10 |
+
const CHANNELS = [
|
| 11 |
+
{id:'vtv1',name:'VTV1',badge:'Tin tức'},{id:'vtv2',name:'VTV2',badge:'Khoa học'},
|
| 12 |
+
{id:'vtv3',name:'VTV3',badge:'Giải trí'},{id:'vtv4',name:'VTV4',badge:'Quốc tế'},
|
| 13 |
+
{id:'vtv5',name:'VTV5',badge:'Miền Nam'},{id:'vtv6',name:'VTV6',badge:'Thanh niên'},
|
| 14 |
+
{id:'vtv7',name:'VTV7',badge:'Giáo dục'},{id:'vtv8',name:'VTV8',badge:'Miền Trung'},
|
| 15 |
+
{id:'vtv9',name:'VTV9',badge:'Miền Bắc'},{id:'vtv10',name:'VTV10',badge:'Cần Thơ'},
|
| 16 |
+
{id:'vtvprime',name:'VTVPrime',badge:'Prime'},
|
| 17 |
+
];
|
| 18 |
+
|
| 19 |
+
const VTV_POPUP_URLS = {
|
| 20 |
+
vtv1: 'https://package.vtvgo.vn/channel/vtv1-1,1.html',
|
| 21 |
+
vtv2: 'https://package.vtvgo.vn/channel/vtv2-1,2.html',
|
| 22 |
+
vtv3: 'https://package.vtvgo.vn/channel/vtv3-1,3.html',
|
| 23 |
+
vtv4: 'https://package.vtvgo.vn/channel/vtv4-1,4.html',
|
| 24 |
+
vtv5: 'https://package.vtvgo.vn/channel/vtv5-1,5.html',
|
| 25 |
+
vtv6: 'https://package.vtvgo.vn/channel/vtv6-1,13.html',
|
| 26 |
+
vtv7: 'https://package.vtvgo.vn/channel/vtv7-1,27.html',
|
| 27 |
+
vtv8: 'https://package.vtvgo.vn/channel/vtv8-1,36.html',
|
| 28 |
+
vtv9: 'https://package.vtvgo.vn/channel/vtv9-1,39.html',
|
| 29 |
+
vtv10: 'https://package.vtvgo.vn/channel/vtv10-1,6.html',
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
const DEFAULT_CHANNEL = 'vtv3';
|
| 33 |
+
const NEEDS_PROXY = /fptplay\.net|vtvgo\.vn/;
|
| 34 |
+
const STREAMS = {};
|
| 35 |
+
let _currentCh = null, _hls = null, _loading = false, _blockInserted = false;
|
| 36 |
+
let _streamsLoaded = false, _pipActive = false, _miniActive = false, _vtvPinned = false, _vtvPopupActive = false;
|
| 37 |
+
|
| 38 |
+
const _rec = {
|
| 39 |
+
active: false, startTime: null, endTime: null,
|
| 40 |
+
isRecording: false, recorder: null, chunks: [], blob: null,
|
| 41 |
+
ratio: 'original', _dragMarker: null, _recTimer: null,
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
const style = document.createElement('style');
|
| 45 |
+
style.textContent = `
|
| 46 |
+
.vtv-wrap{position:relative;margin:6px 4px;background:#111;border:1px solid #0066cc;border-radius:10px;overflow:hidden}
|
| 47 |
+
.vtv-head{display:flex;align-items:center;gap:8px;padding:8px 10px;background:linear-gradient(90deg,#003366,#1a1a1a)}
|
| 48 |
+
.vtv-title{font-size:13px;font-weight:800;color:#00ccff}
|
| 49 |
+
.vtv-badge{font-size:10px;font-weight:800;color:#00ccff;animation:vtvp 1.3s infinite}
|
| 50 |
+
@keyframes vtvp{0%,100%{opacity:1}50%{opacity:.3}}
|
| 51 |
+
.vtv-tabs{display:flex;flex-wrap:wrap;gap:3px;padding:6px 8px;overflow-x:auto;scrollbar-width:none;background:#0d1a2a}
|
| 52 |
+
.vtv-tabs::-webkit-scrollbar{display:none}
|
| 53 |
+
.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}
|
| 54 |
+
.vtv-tab:hover{background:#0b4a7a;color:#fff}
|
| 55 |
+
.vtv-tab.on{background:#0066cc;border-color:#00ccff;color:#fff;font-weight:700}
|
| 56 |
+
.vtv-tab.off{opacity:.35}
|
| 57 |
+
.vtv-frame{position:relative;width:100%;aspect-ratio:16/9;background:#000;min-height:180px}
|
| 58 |
+
.vtv-frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
|
| 59 |
+
.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}
|
| 60 |
+
.vtv-err button{background:#0066cc;border:none;color:#fff;padding:6px 14px;border-radius:8px;font-size:11px;cursor:pointer}
|
| 61 |
+
.vtv-load{display:flex;align-items:center;justify-content:center;height:180px;color:#00ccff;font-size:12px;flex-direction:column;gap:8px}
|
| 62 |
+
.vtv-spinner{width:24px;height:24px;border:2px solid #333;border-top-color:#00ccff;border-radius:50%;animation:vtvspin .8s linear infinite}
|
| 63 |
+
@keyframes vtvspin{to{transform:rotate(360deg)}}
|
| 64 |
+
.vtv-controls{display:flex;align-items:center;gap:4px;padding:4px 8px;background:#0d1a2a;border-top:1px solid #1a2a3a}
|
| 65 |
+
.vtv-pip-btn{background:#1a2a3a;border:1px solid #2a3a4a;color:#8ab4d8;font-size:9px;padding:3px 8px;border-radius:6px;cursor:pointer;transition:all .2s;display:flex;align-items:center;gap:4px}
|
| 66 |
+
.vtv-pip-btn:hover{background:#0b4a7a;color:#fff}
|
| 67 |
+
.vtv-pip-btn.on{background:#0066cc;border-color:#00ccff;color:#fff}
|
| 68 |
+
.vtv-pip-btn svg{width:12px;height:12px;fill:currentColor}
|
| 69 |
+
.vtv-epg{margin:0;padding:6px 10px;background:#0a1628;border-top:1px solid #1a2a3a}
|
| 70 |
+
.vtv-epg-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:4px}
|
| 71 |
+
.vtv-epg-title{font-size:10px;font-weight:700;color:#00ccff}
|
| 72 |
+
.vtv-epg-toggle{background:none;border:1px solid #2a3a4a;color:#8ab4d8;font-size:9px;padding:2px 8px;border-radius:6px;cursor:pointer}
|
| 73 |
+
.vtv-epg-list{display:flex;gap:4px;overflow-x:auto;scrollbar-width:none;padding-bottom:4px}
|
| 74 |
+
.vtv-epg-list::-webkit-scrollbar{display:none}
|
| 75 |
+
.vtv-epg-item{flex:0 0 auto;padding:3px 6px;background:#1a2a3a;border-radius:4px;font-size:8px;color:#8ab4d8;white-space:nowrap;cursor:pointer}
|
| 76 |
+
.vtv-epg-item:hover{background:#2a4a6a}
|
| 77 |
+
.vtv-epg-item.now{background:#0066cc;color:#fff;font-weight:700}
|
| 78 |
+
.vtv-epg-item .t{font-size:7px;color:#6a8aaa}
|
| 79 |
+
.vtv-epg-item.now .t{color:#aaccee}
|
| 80 |
+
.vtv-epg-item .n{color:#ccc;font-size:8px}
|
| 81 |
+
.vtv-epg-item.now .n{color:#fff}
|
| 82 |
+
.vtv-epg-empty{color:#666;font-size:9px;padding:4px}
|
| 83 |
+
.vtv-epg-loading{color:#00ccff;font-size:9px;padding:4px;display:flex;align-items:center;gap:6px}
|
| 84 |
+
.vtv-epg-sp{width:10px;height:10px;border:1px solid #333;border-top-color:#00ccff;border-radius:50%;animation:vtvspin .8s linear infinite}
|
| 85 |
+
.vtv-pin-btn{position:absolute;top:6px;right:8px;z-index:5;background:rgba(0,0,0,.5);border:1px solid #2a3a4a;color:#8ab4d8;font-size:9px;padding:2px 6px;border-radius:4px;cursor:pointer;font-weight:700;display:flex;align-items:center;gap:3px}
|
| 86 |
+
.vtv-pin-btn:hover{background:#0b4a7a;color:#fff}
|
| 87 |
+
.vtv-pin-btn.pinned{background:#0066cc;border-color:#00ccff;color:#fff}
|
| 88 |
+
.vtv-wrap.vtv-sticky{position:sticky;top:0;z-index:48;transition:all .25s ease;box-shadow:0 4px 24px rgba(0,102,204,.35)}
|
| 89 |
+
.vtv-wrap.vtv-sticky .vtv-epg{display:none}
|
| 90 |
+
.vtv-wrap.vtv-sticky .vtv-controls{display:none}
|
| 91 |
+
.vtv-wrap.vtv-sticky .vtv-tabs{padding:3px 8px}
|
| 92 |
+
.vtv-wrap.vtv-sticky .vtv-tab{padding:3px 7px;font-size:8px}
|
| 93 |
+
.vtv-wrap.vtv-sticky .vtv-frame{max-height:140px;min-height:100px}
|
| 94 |
+
.vtv-wrap.vtv-sticky .vtv-frame video{max-height:140px}
|
| 95 |
+
.vtv-wrap.vtv-sticky .vtv-load{height:100px}
|
| 96 |
+
.vtv-wrap.vtv-sticky .vtv-err{height:100px}
|
| 97 |
+
.vtv-wrap.vtv-sticky .vtv-head{padding:5px 10px}
|
| 98 |
+
.vtv-wrap.vtv-sticky .vtv-title{font-size:11px}
|
| 99 |
+
.vtv-wrap.vtv-sticky .vtv-badge{font-size:8px}
|
| 100 |
+
.vtv-wrap.vtv-sticky .vtv-pin-btn{top:4px;right:6px}
|
| 101 |
+
.vtv-rec-btn{background:#660000;border:1px solid #990000;color:#ff6666;font-size:9px;padding:3px 8px;border-radius:6px;cursor:pointer;transition:all .2s;display:flex;align-items:center;gap:4px;font-weight:700}
|
| 102 |
+
.vtv-rec-btn:hover{background:#990000;color:#fff}
|
| 103 |
+
.vtv-rec-btn.recording{background:#cc0000;border-color:#ff0000;color:#fff;animation:vtv-rec-pulse 1s infinite}
|
| 104 |
+
@keyframes vtv-rec-pulse{0%,100%{opacity:1}50%{opacity:.5}}
|
| 105 |
+
.vtv-rec-btn svg{width:12px;height:12px;fill:currentColor}
|
| 106 |
+
.vtv-inline-rec{display:none;padding:8px 10px;background:#0a0a1a;border-top:1px solid #1a1a3a}
|
| 107 |
+
.vtv-inline-rec.show{display:block}
|
| 108 |
+
.vtv-inline-rec .rec-bar{position:relative;height:32px;background:#000;border-radius:4px;overflow:hidden;cursor:pointer;border:1px solid #2a2a4a;margin-bottom:6px;user-select:none}
|
| 109 |
+
.vtv-inline-rec .rec-bar .rec-progress{position:absolute;top:0;bottom:0;background:rgba(155,89,182,.3);left:0;width:0%;pointer-events:none}
|
| 110 |
+
.vtv-inline-rec .rec-bar .rec-marker{position:absolute;top:0;bottom:0;width:4px;z-index:2;border-radius:2px}
|
| 111 |
+
.vtv-inline-rec .rec-bar .rec-marker.s{background:#2ecc71}
|
| 112 |
+
.vtv-inline-rec .rec-bar .rec-marker.e{background:#e74c3c}
|
| 113 |
+
.vtv-inline-rec .rec-time{display:flex;justify-content:space-between;font-size:9px;color:#888;margin-bottom:6px}
|
| 114 |
+
.vtv-inline-rec .rec-controls{display:flex;gap:4px}
|
| 115 |
+
.vtv-inline-rec .rec-controls button{flex:1;padding:6px;border:none;border-radius:6px;font-size:10px;font-weight:700;cursor:pointer}
|
| 116 |
+
.vtv-inline-rec .rec-controls .rec-set-start{background:#1a3a1a;border:1px solid #2d6a2d;color:#5cb87a}
|
| 117 |
+
.vtv-inline-rec .rec-controls .rec-set-end{background:#3a1a1a;border:1px solid #6a2d2d;color:#e74c3c}
|
| 118 |
+
.vtv-inline-rec .rec-controls .rec-go{background:#1a0a3a;border:1px solid #3a2a6a;color:#9b59b6}
|
| 119 |
+
.vtv-inline-rec .rec-controls .rec-reset{background:#222;border:1px solid #333;color:#888}
|
| 120 |
+
.vtv-inline-rec .rec-hint{font-size:9px;color:#666;text-align:center;margin-top:4px}
|
| 121 |
+
.vtv-inline-rec .rec-status{font-size:10px;color:#888;text-align:center;padding:4px;margin-top:4px;background:#111;border-radius:4px}
|
| 122 |
+
.vtv-inline-rec .rec-status.ok{color:#2ecc71}
|
| 123 |
+
.vtv-inline-rec .rec-status.err{color:#e74c3c}
|
| 124 |
+
.vtv-inline-rec .rec-status.recording{color:#e74c3c;animation:vtv-rec-pulse 1s infinite}
|
| 125 |
+
.vtv-rec-panel{display:none;padding:10px;background:#0d0d20;border-top:1px solid #2a1a4a}
|
| 126 |
+
.vtv-rec-panel.show{display:block}
|
| 127 |
+
.vtv-rec-panel .rec-panel-title{font-size:11px;font-weight:700;color:#9b59b6;margin-bottom:8px}
|
| 128 |
+
.vtv-rec-panel .rec-preview-wrap{margin-bottom:8px;text-align:center}
|
| 129 |
+
.vtv-rec-panel .rec-preview-wrap video{max-width:100%;max-height:180px;border-radius:6px;background:#000}
|
| 130 |
+
.vtv-rec-panel .rec-ratio-row{display:flex;gap:4px;margin-bottom:8px}
|
| 131 |
+
.vtv-rec-panel .rec-ratio-row button{flex:1;padding:6px;background:#1a1a2e;border:1px solid #2a2a4a;border-radius:6px;color:#888;font-size:10px;cursor:pointer}
|
| 132 |
+
.vtv-rec-panel .rec-ratio-row button.active{border-color:#9b59b6;color:#9b59b6;background:#2a1a4a}
|
| 133 |
+
.vtv-rec-panel .rec-actions{display:flex;gap:4px}
|
| 134 |
+
.vtv-rec-panel .rec-actions button{flex:1;padding:8px;border:none;border-radius:6px;font-size:11px;font-weight:700;cursor:pointer}
|
| 135 |
+
.vtv-rec-panel .rec-actions .rec-download{background:#2d8659;color:#fff}
|
| 136 |
+
.vtv-rec-panel .rec-actions .rec-share{background:#9b59b6;color:#fff}
|
| 137 |
+
.vtv-rec-panel .rec-proc{text-align:center;padding:12px;color:#9b59b6;font-size:12px;display:none}
|
| 138 |
+
.vtv-rec-panel .rec-title-input{width:100%;background:#1a1a2e;border:1px solid #2a2a4a;border-radius:6px;padding:8px;color:#ccc;font-size:11px;margin-bottom:8px;box-sizing:border-box}
|
| 139 |
+
.vtv-rec-panel .rec-title-input:focus{border-color:#9b59b6;outline:none}
|
| 140 |
+
.vtv-rec-panel .rec-ai-title-row{display:flex;gap:4px;margin-bottom:8px}
|
| 141 |
+
.vtv-rec-panel .rec-ai-title-row button{flex:1;padding:6px;background:#1a1a2e;border:1px solid #2a2a4a;border-radius:6px;color:#888;font-size:10px;cursor:pointer}
|
| 142 |
+
.vtv-rec-panel .rec-ai-title-row button:hover{border-color:#9b59b6;color:#9b59b6}
|
| 143 |
+
.vtv-rec-panel .rec-ai-title-row button:disabled{opacity:.4;cursor:not-allowed}
|
| 144 |
+
.vtv-mini{position:fixed;top:0;left:0;right:0;z-index:99990;background:#000;border-bottom:2px solid #0066cc;box-shadow:0 4px 20px rgba(0,102,204,.4);display:none;transition:transform .3s ease}
|
| 145 |
+
.vtv-mini.show{display:block}
|
| 146 |
+
.vtv-mini.hidden{transform:translateY(-88%)}
|
| 147 |
+
.vtv-mini-frame{position:relative;width:100%;aspect-ratio:16/9;background:#000;max-height:180px}
|
| 148 |
+
.vtv-mini-frame video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain}
|
| 149 |
+
.vtv-mini-bar{display:flex;align-items:center;justify-content:space-between;padding:3px 8px;background:linear-gradient(90deg,#003366,#1a1a1a)}
|
| 150 |
+
.vtv-mini-ch{font-size:10px;font-weight:700;color:#00ccff}
|
| 151 |
+
.vtv-mini-epg{font-size:9px;color:#8ab4d8;max-width:180px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-left:8px}
|
| 152 |
+
.vtv-mini-btns{display:flex;gap:3px}
|
| 153 |
+
.vtv-mini-btn{background:#1a2a3a;border:1px solid #2a3a4a;color:#8ab4d8;font-size:9px;padding:2px 6px;border-radius:4px;cursor:pointer}
|
| 154 |
+
.vtv-mini-btn:hover{background:#0b4a7a;color:#fff}
|
| 155 |
+
.vtv-mini-btn.x{background:#600;border-color:#900;color:#f66}
|
| 156 |
+
.vtv-mini-btn.x:hover{background:#900;color:#fff}
|
| 157 |
+
.vtv-mini-peek{position:absolute;bottom:-18px;right:10px;background:#0066cc;color:#fff;font-size:9px;padding:2px 8px;border-radius:0 0 6px 6px;cursor:pointer;display:none}
|
| 158 |
+
.vtv-mini.hidden .vtv-mini-peek{display:block}
|
| 159 |
+
.vtv-popup{position:fixed;top:0;left:0;right:0;margin:8px auto 0;background:rgba(0,0,0,.95);z-index:99999;display:none;flex-direction:column;max-height:calc(100vh - 16px);max-width:800px;border-radius:12px;overflow:hidden}
|
| 160 |
+
.vtv-popup.show{display:flex}
|
| 161 |
+
.vtv-popup:has(#vtv-popup-hdr[style*="none"]) .vtv-popup-frame{height:100%}
|
| 162 |
+
.vtv-popup-header{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:#111;border-bottom:1px solid #333}
|
| 163 |
+
.vtv-popup-title{font-size:14px;font-weight:700;color:#00ccff}
|
| 164 |
+
.vtv-popup-close{background:#333;border:none;color:#fff;font-size:18px;width:32px;height:32px;border-radius:6px;cursor:pointer}
|
| 165 |
+
.vtv-popup-frame{flex:1;position:relative;background:#000;min-height:300px}
|
| 166 |
+
.vtv-popup-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:none}
|
| 167 |
+
.vtv-popup-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:none}
|
| 168 |
+
.vtv-popup-loader{display:flex;align-items:center;justify-content:center;height:280px;color:#00ccff;font-size:12px;flex-direction:column;gap:8px}
|
| 169 |
+
.vtv-popup-btn{background:#1a2a3a;border:1px solid #2a3a4a;color:#8ab4d8;font-size:9px;padding:3px 8px;border-radius:6px;cursor:pointer;margin-left:4px}
|
| 170 |
+
.vtv-popup-btn:hover{background:#0b4a7a;color:#fff}
|
| 171 |
+
`;
|
| 172 |
+
document.head.appendChild(style);
|