jaynesmax commited on
Commit
0ac5ee3
·
verified ·
1 Parent(s): 90089fa

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +53 -16
index.html CHANGED
@@ -122,6 +122,12 @@
122
  .jtv-b{margin-left:auto; background:rgba(255,255,255,.18); color:#fff; border:0; border-radius:8px; padding:5px 10px; font:inherit; font-size:12px;}
123
  .jtv-epg{margin-top:6px; max-height:38vh; overflow:auto; border-top:1px solid rgba(255,255,255,.2); padding-top:6px;}
124
  .jtv-epg div{padding:3px 0;} .jtv-epg span{display:inline-block; min-width:48px; opacity:.7;}
 
 
 
 
 
 
125
  .rank-num{position:absolute; left:6px; bottom:0; font-size:58px; font-weight:900; line-height:1; letter-spacing:-3px; color:transparent;
126
  -webkit-text-stroke:2px rgba(255,255,255,.92); text-shadow:0 4px 14px rgba(0,0,0,.65); pointer-events:none; z-index:2;}
127
  .poster-art:has(.rank-num)::after{content:''; position:absolute; inset:auto 0 0 0; height:46%; background:linear-gradient(transparent,rgba(0,0,0,.7)); pointer-events:none;}
@@ -3610,40 +3616,71 @@ function jtvNow(s, nowMs) { // kipindi cha sasa + vinavyofuata, kwa saa: kila mt
3610
  }
3611
  async function openJaynesTV() {
3612
  openPlayerShell('JaynesTV');
3613
- const s = await jtvSchedule(true);
3614
  if (!s) return statusMsg('<span style="color:#ffb4ab">' + esc(T('jtv_down')) + '</span>');
3615
  stage.style.position = 'relative';
3616
- stage.innerHTML = '<video id="vid" controls autoplay playsinline></video><div class="jtv-bar" id="jtvBar"></div>';
3617
- const v = document.getElementById('vid'), bar = document.getElementById('jtvBar');
 
 
3618
  attachPlayerEnhancements(v); ensureSound(v);
3619
- const bad = new Set(); let cur = null, epg = false, hideT = null, last = null;
3620
  const hhmm = ms => new Date(ms).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
 
3621
  const show = (ms) => { bar.classList.remove('hide'); clearTimeout(hideT); if (ms) hideT = setTimeout(() => { if (!epg) bar.classList.add('hide'); }, ms); };
 
 
 
 
 
 
 
 
 
 
3622
  const draw = (n, it) => {
3623
- const nx = n.upcoming[0];
3624
- bar.innerHTML = '<div class="jtv-row"><span class="jtv-live">● LIVE</span><b>' + esc(it.title) + '</b>' + (it.dj ? '<span class="jtv-m">' + esc(it.dj) + '</span>' : '') +
 
 
 
 
 
 
 
 
 
3625
  '<button class="jtv-b" data-j="epg">' + esc(T('jtv_schedule')) + '</button></div>' +
3626
- '<div class="jtv-m">' + esc(T('jtv_next')) + ': ' + esc(nx.item.title) + ' · ' + hhmm(nx.at) + '</div>' +
3627
- (epg ? '<div class="jtv-epg">' + n.upcoming.map(u => '<div><span>' + hhmm(u.at) + '</span> ' + esc(u.item.title) + '</div>').join('') + '</div>' : '');
 
 
3628
  };
3629
  const sync = () => {
 
 
 
 
 
 
3630
  const n = jtvNow(s, Date.now()), isBad = bad.has(n.idx);
3631
  const it = isBad ? n.upcoming[0].item : n.item, off = isBad ? 0 : n.offset; // video mbovu: cheza inayofuata kutoka mwanzo
3632
  if (cur !== it.url) {
3633
- cur = it.url; v.src = it.url + '#t=' + Math.floor(off);
3634
- v.addEventListener('loadedmetadata', () => { if (Math.abs(v.currentTime - off) > 3) v.currentTime = off; const p = v.play(); if (p && p.catch) p.catch(() => {}); }, { once: true });
3635
- show(8000);
3636
  } else if (!isBad && v.readyState > 1 && Math.abs(v.currentTime - off) > 4) v.currentTime = off; // rudi kwenye 'live'
3637
  last = n; draw(n, it);
3638
  };
3639
- bar.onclick = (e) => { if (e.target.closest('[data-j="epg"]')) { epg = !epg; draw(last, last.item); show(epg ? 0 : 6000); } };
 
3640
  v.addEventListener('ended', sync);
3641
  v.addEventListener('play', sync);
3642
- v.addEventListener('seeked', () => { if (last && Math.abs(v.currentTime - last.offset) > 6) sync(); });
3643
- v.addEventListener('error', () => { if (last) { bad.add(last.idx); sync(); } });
3644
  v.addEventListener('click', () => show(6000));
3645
- const timer = setInterval(sync, 15000);
3646
- window.__jtvStop = () => { clearInterval(timer); clearTimeout(hideT); };
 
3647
  sync();
3648
  }
3649
 
 
122
  .jtv-b{margin-left:auto; background:rgba(255,255,255,.18); color:#fff; border:0; border-radius:8px; padding:5px 10px; font:inherit; font-size:12px;}
123
  .jtv-epg{margin-top:6px; max-height:38vh; overflow:auto; border-top:1px solid rgba(255,255,255,.2); padding-top:6px;}
124
  .jtv-epg div{padding:3px 0;} .jtv-epg span{display:inline-block; min-width:48px; opacity:.7;}
125
+ .jtv-logo{position:absolute; right:12px; bottom:56px; width:64px; max-height:40px; object-fit:contain; opacity:.75; z-index:4; pointer-events:none; filter:drop-shadow(0 1px 3px rgba(0,0,0,.6));}
126
+ .jtv-ad{position:absolute; left:12px; bottom:56px; z-index:6; background:#ffc53d; color:#1b1230; font-weight:900; font-size:11px; letter-spacing:1px; padding:3px 9px; border-radius:6px; display:none;}
127
+ .jtv-ad.on{display:block;}
128
+ .jtv-ad i{font-style:normal; font-weight:700; opacity:.8; margin-left:6px;}
129
+ .jtv-epg .now{color:#ffc53d; font-weight:700;}
130
+ .jtv-epg .k{font-size:10px; opacity:.6; margin-left:6px;}
131
  .rank-num{position:absolute; left:6px; bottom:0; font-size:58px; font-weight:900; line-height:1; letter-spacing:-3px; color:transparent;
132
  -webkit-text-stroke:2px rgba(255,255,255,.92); text-shadow:0 4px 14px rgba(0,0,0,.65); pointer-events:none; z-index:2;}
133
  .poster-art:has(.rank-num)::after{content:''; position:absolute; inset:auto 0 0 0; height:46%; background:linear-gradient(transparent,rgba(0,0,0,.7)); pointer-events:none;}
 
3616
  }
3617
  async function openJaynesTV() {
3618
  openPlayerShell('JaynesTV');
3619
+ let s = await jtvSchedule(true);
3620
  if (!s) return statusMsg('<span style="color:#ffb4ab">' + esc(T('jtv_down')) + '</span>');
3621
  stage.style.position = 'relative';
3622
+ stage.innerHTML = '<video id="vid" controls autoplay playsinline></video><div class="jtv-bar" id="jtvBar"></div>' +
3623
+ '<div class="jtv-ad" id="jtvAd">TANGAZO<i></i></div>' + (s.logo ? '<img class="jtv-logo" id="jtvLogo" alt="" src="' + esc(s.logo) + '">' : '');
3624
+ const v = document.getElementById('vid'), bar = document.getElementById('jtvBar'), adEl = document.getElementById('jtvAd');
3625
+ const logoEl = document.getElementById('jtvLogo'); if (logoEl) logoEl.onerror = () => logoEl.remove();
3626
  attachPlayerEnhancements(v); ensureSound(v);
3627
+ const bad = new Set(); let cur = null, epg = false, hideT = null, last = null, liveOn = false, hls = null;
3628
  const hhmm = ms => new Date(ms).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
3629
+ const kindOf = it => (it && it.kind) || 'program';
3630
  const show = (ms) => { bar.classList.remove('hide'); clearTimeout(hideT); if (ms) hideT = setTimeout(() => { if (!epg) bar.classList.add('hide'); }, ms); };
3631
+ const nextProgram = n => (n.upcoming.find(u => kindOf(u.item) === 'program') || n.upcoming[0]);
3632
+ const stopHls = () => { if (hls) { try { hls.destroy(); } catch (_) {} hls = null; } };
3633
+ const playSrc = (url, off) => { // MP4 au HLS (.m3u8) — live ya studio ni HLS
3634
+ stopHls();
3635
+ const isHls = /\.m3u8(\?|$)/i.test(url);
3636
+ if (isHls && !v.canPlayType('application/vnd.apple.mpegurl') && window.Hls && Hls.isSupported()) {
3637
+ hls = new Hls(); hls.loadSource(url); hls.attachMedia(v);
3638
+ } else v.src = isHls ? url : url + '#t=' + Math.floor(off || 0);
3639
+ v.addEventListener('loadedmetadata', () => { if (!isHls && Math.abs(v.currentTime - off) > 3) v.currentTime = off; const p = v.play(); if (p && p.catch) p.catch(() => {}); }, { once: true });
3640
+ };
3641
  const draw = (n, it) => {
3642
+ if (liveOn) {
3643
+ bar.innerHTML = '<div class="jtv-row"><span class="jtv-live">● LIVE</span><b>' + esc(s.live.title || 'Matangazo ya moja kwa moja') + '</b>' +
3644
+ '<span class="jtv-m">Studio</span></div>';
3645
+ adEl.classList.remove('on'); return;
3646
+ }
3647
+ const k = kindOf(it), nx = nextProgram(n);
3648
+ adEl.classList.toggle('on', k === 'ad');
3649
+ if (k === 'ad') adEl.querySelector('i').textContent = Math.max(0, Math.ceil(n.left)) + 's';
3650
+ const nowTitle = k === 'program' ? it.title : (nx.item.title); // wakati wa tangazo/kitambulisho: "inaanza punde"
3651
+ bar.innerHTML = '<div class="jtv-row"><span class="jtv-live">● LIVE</span><b>' + (k === 'program' ? '' : 'Punde: ') + esc(nowTitle) + '</b>' +
3652
+ (k === 'program' && it.dj ? '<span class="jtv-m">' + esc(it.dj) + '</span>' : '') +
3653
  '<button class="jtv-b" data-j="epg">' + esc(T('jtv_schedule')) + '</button></div>' +
3654
+ (k === 'program' ? '<div class="jtv-m">Sasa hivi · ' + T('jtv_next') + ': ' + esc(nx.item.title) + ' · ' + hhmm(nx.at) + '</div>' : '') +
3655
+ (epg ? '<div class="jtv-epg">' +
3656
+ (k === 'program' ? '<div class="now"><span>' + hhmm(Date.now() - (it.dur - n.left) * 1000) + '</span> ' + esc(it.title) + '<span class="k">SASA</span></div>' : '') +
3657
+ n.upcoming.filter(u => kindOf(u.item) === 'program').map(u => '<div><span>' + hhmm(u.at) + '</span> ' + esc(u.item.title) + '</div>').join('') + '</div>' : '');
3658
  };
3659
  const sync = () => {
3660
+ const liveUrl = s.live && s.live.active && s.live.url;
3661
+ if (liveUrl) { // studio iko hewani: hamia live yenyewe
3662
+ if (!liveOn || cur !== liveUrl) { liveOn = true; cur = liveUrl; playSrc(liveUrl, 0); show(8000); }
3663
+ draw(null, null); return;
3664
+ }
3665
+ if (liveOn) { liveOn = false; cur = null; } // live imeisha: rudi kwenye ratiba
3666
  const n = jtvNow(s, Date.now()), isBad = bad.has(n.idx);
3667
  const it = isBad ? n.upcoming[0].item : n.item, off = isBad ? 0 : n.offset; // video mbovu: cheza inayofuata kutoka mwanzo
3668
  if (cur !== it.url) {
3669
+ cur = it.url; playSrc(it.url, off);
3670
+ if (kindOf(it) === 'program') show(8000); else bar.classList.add('hide');
 
3671
  } else if (!isBad && v.readyState > 1 && Math.abs(v.currentTime - off) > 4) v.currentTime = off; // rudi kwenye 'live'
3672
  last = n; draw(n, it);
3673
  };
3674
+ const refresh = async () => { const ns = await jtvSchedule(true); if (ns) { s = ns; sync(); } }; // kuangalia live/ratiba mpya
3675
+ bar.onclick = (e) => { if (e.target.closest('[data-j="epg"]') && last) { epg = !epg; draw(last, bad.has(last.idx) ? last.upcoming[0].item : last.item); show(epg ? 0 : 6000); } };
3676
  v.addEventListener('ended', sync);
3677
  v.addEventListener('play', sync);
3678
+ v.addEventListener('seeked', () => { if (!liveOn && last && Math.abs(v.currentTime - last.offset) > 6) sync(); });
3679
+ v.addEventListener('error', () => { if (liveOn) { s = Object.assign({}, s, { live: { active: false } }); cur = null; sync(); } else if (last) { bad.add(last.idx); sync(); } });
3680
  v.addEventListener('click', () => show(6000));
3681
+ const timer = setInterval(sync, 15000), tick = setInterval(() => { if (last && !liveOn && adEl.classList.contains('on')) draw(jtvNow(s, Date.now()), jtvNow(s, Date.now()).item); }, 1000);
3682
+ const liveTimer = setInterval(refresh, 60000);
3683
+ window.__jtvStop = () => { clearInterval(timer); clearInterval(tick); clearInterval(liveTimer); clearTimeout(hideT); stopHls(); };
3684
  sync();
3685
  }
3686