Spaces:
Running
Running
Fix: VTV sticky only on manual pin button, no auto-sticky
Browse files- static/yt_live.js +44 -73
static/yt_live.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
// === VNEWS — VTV1-VTV10 + VTVPrime LIVE CHANNELS ===
|
| 2 |
// Default channel: VTV6
|
| 3 |
// Features: PiP button, floating mini-player when reading articles/videos
|
| 4 |
-
// Fixed
|
| 5 |
|
| 6 |
(function(){
|
| 7 |
if(window._ytLiveLoaded) return;
|
|
@@ -31,27 +31,11 @@
|
|
| 31 |
let _streamsLoaded = false;
|
| 32 |
let _pipActive = false;
|
| 33 |
let _miniActive = false;
|
| 34 |
-
let
|
| 35 |
|
| 36 |
// ===== STYLES =====
|
| 37 |
const style = document.createElement('style');
|
| 38 |
style.textContent = `
|
| 39 |
-
/* ===== VTV STICKY / FIXED MODE ===== */
|
| 40 |
-
.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)}
|
| 41 |
-
.vtv-wrap.vtv-sticky .vtv-epg{display:none}
|
| 42 |
-
.vtv-wrap.vtv-sticky .vtv-controls{display:none}
|
| 43 |
-
.vtv-wrap.vtv-sticky .vtv-tabs{padding:3px 8px}
|
| 44 |
-
.vtv-wrap.vtv-sticky .vtv-tab{padding:3px 7px;font-size:8px}
|
| 45 |
-
.vtv-wrap.vtv-sticky .vtv-frame{max-height:140px;min-height:100px}
|
| 46 |
-
.vtv-wrap.vtv-sticky .vtv-frame video{max-height:140px}
|
| 47 |
-
.vtv-wrap.vtv-sticky .vtv-load{height:100px}
|
| 48 |
-
.vtv-wrap.vtv-sticky .vtv-err{height:100px}
|
| 49 |
-
.vtv-wrap.vtv-sticky .vtv-head{padding:5px 10px}
|
| 50 |
-
.vtv-wrap.vtv-sticky .vtv-title{font-size:11px}
|
| 51 |
-
.vtv-wrap.vtv-sticky .vtv-badge{font-size:8px}
|
| 52 |
-
.vtv-sticky-toggle{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}
|
| 53 |
-
.vtv-sticky-toggle:hover{background:#0b4a7a;color:#fff}
|
| 54 |
-
.vtv-wrap.vtv-sticky .vtv-sticky-toggle{top:4px;right:6px}
|
| 55 |
.vtv-wrap{position:relative;margin:6px 4px;background:#111;border:1px solid #0066cc;border-radius:10px;overflow:hidden}
|
| 56 |
.vtv-head{display:flex;align-items:center;gap:8px;padding:8px 10px;background:linear-gradient(90deg,#003366,#1a1a1a)}
|
| 57 |
.vtv-title{font-size:13px;font-weight:800;color:#00ccff}
|
|
@@ -92,6 +76,25 @@
|
|
| 92 |
.vtv-epg-loading{color:#00ccff;font-size:9px;padding:4px;display:flex;align-items:center;gap:6px}
|
| 93 |
.vtv-epg-sp{width:10px;height:10px;border:1px solid #333;border-top-color:#00ccff;border-radius:50%;animation:vtvspin .8s linear infinite}
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
/* ===== MINI PLAYER ===== */
|
| 96 |
.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}
|
| 97 |
.vtv-mini.show{display:block}
|
|
@@ -111,66 +114,34 @@
|
|
| 111 |
`;
|
| 112 |
document.head.appendChild(style);
|
| 113 |
|
| 114 |
-
// =====
|
| 115 |
-
function
|
| 116 |
const block = document.getElementById('vtv-block');
|
| 117 |
if(!block) return;
|
| 118 |
const header = block.querySelector('.vtv-head');
|
| 119 |
if(!header) return;
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
if(_vtvSticky){
|
| 132 |
-
block.classList.add('vtv-sticky');
|
| 133 |
-
btn.textContent = '📌';
|
| 134 |
-
btn.style.color = '#00ccff';
|
| 135 |
-
btn.style.borderColor = '#00ccff';
|
| 136 |
-
} else {
|
| 137 |
-
block.classList.remove('vtv-sticky');
|
| 138 |
-
btn.textContent = '📌';
|
| 139 |
-
btn.style.color = '#8ab4d8';
|
| 140 |
-
btn.style.borderColor = '#2a3a4a';
|
| 141 |
-
}
|
| 142 |
-
};
|
| 143 |
-
header.style.position = 'relative';
|
| 144 |
-
header.appendChild(btn);
|
| 145 |
-
}
|
| 146 |
-
|
| 147 |
-
// Auto-sticky: when VTV block scrolls out of view, make it sticky
|
| 148 |
-
let lastScrollY = 0;
|
| 149 |
-
let autoStickyOn = false;
|
| 150 |
-
|
| 151 |
-
window.addEventListener('scroll', function(){
|
| 152 |
-
const scrollY = window.scrollY || window.pageYOffset;
|
| 153 |
-
const blockRect = block.getBoundingClientRect();
|
| 154 |
-
const blockBottom = blockRect.bottom;
|
| 155 |
-
|
| 156 |
-
// If user manually toggled sticky, respect that
|
| 157 |
-
if(_vtvSticky) return;
|
| 158 |
-
|
| 159 |
-
// Auto-detect: if block bottom is above viewport top (scrolled past)
|
| 160 |
-
if(blockBottom < 0 && !autoStickyOn){
|
| 161 |
-
autoStickyOn = true;
|
| 162 |
block.classList.add('vtv-sticky');
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
} else
|
| 166 |
-
// Scrolled back up to VTV — release sticky
|
| 167 |
-
autoStickyOn = false;
|
| 168 |
block.classList.remove('vtv-sticky');
|
| 169 |
-
|
| 170 |
-
|
| 171 |
}
|
| 172 |
-
|
| 173 |
-
|
|
|
|
| 174 |
}
|
| 175 |
|
| 176 |
// ===== MINI PLAYER =====
|
|
@@ -378,8 +349,8 @@
|
|
| 378 |
if(!h||document.getElementById('vtv-block')) return;
|
| 379 |
h.insertBefore(buildBlock(), h.firstChild);
|
| 380 |
_blockInserted = true;
|
| 381 |
-
//
|
| 382 |
-
setTimeout(()=>
|
| 383 |
if(!_streamsLoaded){
|
| 384 |
loadAllStreams().then(()=>{
|
| 385 |
setTimeout(()=>window._vtvPlay(DEFAULT_CHANNEL), 300);
|
|
|
|
| 1 |
// === VNEWS — VTV1-VTV10 + VTVPrime LIVE CHANNELS ===
|
| 2 |
// Default channel: VTV6
|
| 3 |
// Features: PiP button, floating mini-player when reading articles/videos
|
| 4 |
+
// Fixed: VTV stays at top ONLY when user clicks pin button
|
| 5 |
|
| 6 |
(function(){
|
| 7 |
if(window._ytLiveLoaded) return;
|
|
|
|
| 31 |
let _streamsLoaded = false;
|
| 32 |
let _pipActive = false;
|
| 33 |
let _miniActive = false;
|
| 34 |
+
let _vtvPinned = false; // only true when user clicks pin
|
| 35 |
|
| 36 |
// ===== STYLES =====
|
| 37 |
const style = document.createElement('style');
|
| 38 |
style.textContent = `
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
.vtv-wrap{position:relative;margin:6px 4px;background:#111;border:1px solid #0066cc;border-radius:10px;overflow:hidden}
|
| 40 |
.vtv-head{display:flex;align-items:center;gap:8px;padding:8px 10px;background:linear-gradient(90deg,#003366,#1a1a1a)}
|
| 41 |
.vtv-title{font-size:13px;font-weight:800;color:#00ccff}
|
|
|
|
| 76 |
.vtv-epg-loading{color:#00ccff;font-size:9px;padding:4px;display:flex;align-items:center;gap:6px}
|
| 77 |
.vtv-epg-sp{width:10px;height:10px;border:1px solid #333;border-top-color:#00ccff;border-radius:50%;animation:vtvspin .8s linear infinite}
|
| 78 |
|
| 79 |
+
/* ===== PIN / STICKY MODE ===== */
|
| 80 |
+
.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}
|
| 81 |
+
.vtv-pin-btn:hover{background:#0b4a7a;color:#fff}
|
| 82 |
+
.vtv-pin-btn.pinned{background:#0066cc;border-color:#00ccff;color:#fff}
|
| 83 |
+
|
| 84 |
+
.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)}
|
| 85 |
+
.vtv-wrap.vtv-sticky .vtv-epg{display:none}
|
| 86 |
+
.vtv-wrap.vtv-sticky .vtv-controls{display:none}
|
| 87 |
+
.vtv-wrap.vtv-sticky .vtv-tabs{padding:3px 8px}
|
| 88 |
+
.vtv-wrap.vtv-sticky .vtv-tab{padding:3px 7px;font-size:8px}
|
| 89 |
+
.vtv-wrap.vtv-sticky .vtv-frame{max-height:140px;min-height:100px}
|
| 90 |
+
.vtv-wrap.vtv-sticky .vtv-frame video{max-height:140px}
|
| 91 |
+
.vtv-wrap.vtv-sticky .vtv-load{height:100px}
|
| 92 |
+
.vtv-wrap.vtv-sticky .vtv-err{height:100px}
|
| 93 |
+
.vtv-wrap.vtv-sticky .vtv-head{padding:5px 10px}
|
| 94 |
+
.vtv-wrap.vtv-sticky .vtv-title{font-size:11px}
|
| 95 |
+
.vtv-wrap.vtv-sticky .vtv-badge{font-size:8px}
|
| 96 |
+
.vtv-wrap.vtv-sticky .vtv-pin-btn{top:4px;right:6px}
|
| 97 |
+
|
| 98 |
/* ===== MINI PLAYER ===== */
|
| 99 |
.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}
|
| 100 |
.vtv-mini.show{display:block}
|
|
|
|
| 114 |
`;
|
| 115 |
document.head.appendChild(style);
|
| 116 |
|
| 117 |
+
// ===== PIN BUTTON =====
|
| 118 |
+
function setupPinButton(){
|
| 119 |
const block = document.getElementById('vtv-block');
|
| 120 |
if(!block) return;
|
| 121 |
const header = block.querySelector('.vtv-head');
|
| 122 |
if(!header) return;
|
| 123 |
+
if(document.getElementById('vtv-pin-btn')) return;
|
| 124 |
+
|
| 125 |
+
const btn = document.createElement('button');
|
| 126 |
+
btn.id = 'vtv-pin-btn';
|
| 127 |
+
btn.className = 'vtv-pin-btn';
|
| 128 |
+
btn.innerHTML = '📌 Ghim';
|
| 129 |
+
btn.title = 'Ghim VTV cố định trên đầu trang';
|
| 130 |
+
btn.onclick = function(e){
|
| 131 |
+
e.stopPropagation();
|
| 132 |
+
_vtvPinned = !_vtvPinned;
|
| 133 |
+
if(_vtvPinned){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
block.classList.add('vtv-sticky');
|
| 135 |
+
btn.classList.add('pinned');
|
| 136 |
+
btn.innerHTML = '📌 Đã ghim';
|
| 137 |
+
} else {
|
|
|
|
|
|
|
| 138 |
block.classList.remove('vtv-sticky');
|
| 139 |
+
btn.classList.remove('pinned');
|
| 140 |
+
btn.innerHTML = '📌 Ghim';
|
| 141 |
}
|
| 142 |
+
};
|
| 143 |
+
header.style.position = 'relative';
|
| 144 |
+
header.appendChild(btn);
|
| 145 |
}
|
| 146 |
|
| 147 |
// ===== MINI PLAYER =====
|
|
|
|
| 349 |
if(!h||document.getElementById('vtv-block')) return;
|
| 350 |
h.insertBefore(buildBlock(), h.firstChild);
|
| 351 |
_blockInserted = true;
|
| 352 |
+
// Setup pin button after block is in DOM
|
| 353 |
+
setTimeout(()=>setupPinButton(), 500);
|
| 354 |
if(!_streamsLoaded){
|
| 355 |
loadAllStreams().then(()=>{
|
| 356 |
setTimeout(()=>window._vtvPlay(DEFAULT_CHANNEL), 300);
|