bep40 commited on
Commit
128ba87
·
verified ·
1 Parent(s): abae002

Fix: VTV sticky only on manual pin button, no auto-sticky

Browse files
Files changed (1) hide show
  1. 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 sticky: VTV stays visible at top when scrolling down
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 _vtvSticky = false;
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
- // ===== STICKY SCROLL DETECTION =====
115
- function enableStickyVTV(){
116
  const block = document.getElementById('vtv-block');
117
  if(!block) return;
118
  const header = block.querySelector('.vtv-head');
119
  if(!header) return;
120
-
121
- // Add sticky toggle button to header
122
- if(!document.getElementById('vtv-sticky-btn')){
123
- const btn = document.createElement('button');
124
- btn.id = 'vtv-sticky-btn';
125
- btn.className = 'vtv-sticky-toggle';
126
- btn.textContent = '📌';
127
- btn.title = 'Giữ VTV cố định khi cuộn';
128
- btn.onclick = function(e){
129
- e.stopPropagation();
130
- _vtvSticky = !_vtvSticky;
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
- const btn = document.getElementById('vtv-sticky-btn');
164
- if(btn){btn.textContent='📌';btn.style.color='#00ccff';btn.style.borderColor='#00ccff';}
165
- } else if(blockRect.top >= 0 && autoStickyOn && scrollY < lastScrollY){
166
- // Scrolled back up to VTV — release sticky
167
- autoStickyOn = false;
168
  block.classList.remove('vtv-sticky');
169
- const btn = document.getElementById('vtv-sticky-btn');
170
- if(btn){btn.textContent='📌';btn.style.color='#8ab4d8';btn.style.borderColor='#2a3a4a';}
171
  }
172
- lastScrollY = scrollY;
173
- }, {passive: true});
 
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
- // Enable sticky behavior after block is inserted
382
- setTimeout(()=>enableStickyVTV(), 500);
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);