jaynesmax commited on
Commit
5188aeb
Β·
verified Β·
1 Parent(s): 2c965a0

Upload admin.html

Browse files
Files changed (1) hide show
  1. admin.html +22 -3
admin.html CHANGED
@@ -64,6 +64,10 @@ textarea{resize:vertical;min-height:70px}
64
  .pcard small{padding:0 8px;color:var(--mu);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
65
  .pcard:active{border-color:var(--rd)}
66
  @media(prefers-reduced-motion:reduce){.toast{transition:none}}
 
 
 
 
67
  </style>
68
  </head>
69
  <body>
@@ -179,7 +183,7 @@ const WEBHOOK_SECRET='89cbf19e2ae535da463bcb554e7980ed64b01d6ad5cf96da';
179
  const T={
180
  sw:{mvSrcNew:'Mpya (MP4)',mvSrcOld:'Za zamani',mvAll:'Zote',mvImport:'⬇️ Leta zenye MP4',mvImporting:'Inaleta… {n}/{t}',mvImported:'Imekamilika: +{a} mpya, {u} zimesasishwa',mvPub:'Publish',mvUnpub:'Rudisha Draft',gSub:'Ingia kusimamia app, watumiaji na maudhui.',gPw:'Password',gBtn:'Ingia',gBad:'Password si sahihi.',gHttps:'Fungua ukurasa huu kupitia https.',logout:'Toka',loading:'Inapakia...',refresh:'Onyesha upya',save:'Hifadhi',cancel:'Ghairi',yes:'Ndiyo',no:'Hapana',del:'Futa',none:'Hakuna kitu bado.',err:'Hitilafu: ',saved:'Imehifadhiwa.',deleted:'Imefutwa.',
181
  nOv:'Muhtasari',nMv:'Filamu',nUs:'Watumiaji',nPu:'Push',nAn:'Matangazo',nHm:'Home',nSt:'Mipangilio',search:'Tafuta kwa jina au DJ...',searchEmail:'Tafuta kwa email...',
182
- oUsers:'Jumla ya watumiaji',oNew:'Wapya wiki hii',oActive:'Waliingia wiki hii',oWl:'Vitu vya Watchlist',oPin:'PIN ya Wazazi imewashwa',oBan:'Wamezuiwa',oMv:'Filamu',oAn:'Matangazo active',oNote:'Takwimu za watumiaji zinatoka kwenye data ya wingu (user_profiles); wasio na akaunti hawaonekani.',
183
  mType:'Aina',tMovie:'Movie (sehemu moja)',tSeries:'Series (episode nyingi)',mUrls:'URL za movie (unaweza kuweka sehemu nyingi)',mAddPart:'+ Ongeza sehemu',mBulk:'Bandika URL nyingi kwa pamoja',mBulkPh:'URL moja kila mstari (mstari 1 = Sehemu 1, mstari 2 = Sehemu 2...)',mSplit:'Gawanya kuwa sehemu',mSeasons:'Seasons na episodes',mAddSeason:'+ Ongeza season',delSeason:'Futa season',addEp:'+ Ongeza episode',needUrl:'Weka URL angalau moja.',partsSet:'Sehemu {n} zimewekwa.',epsToParts:'Episodes {n} zimekuwa sehemu {n}.',partsB:'Sehemu',mvNew:'Filamu mpya',mvAdd:'Ongeza filamu / series',mvEdit:'Hariri: ',mvSave:'Hifadhi filamu',mvUpd:'Sasisha filamu',mTitle:'Jina (title)',mYear:'Mwaka',mCat:'Kategoria',cNormal:'Kawaida',cAdult:'Wakubwa',mPrice:'Bei (TZS)',mStatus:'Hali',mDesc:'Maelezo',mCast:'Waigizaji (tenganisha kwa koma)',mEps:'Episode / Video URLs',mAddEp:'+ Ongeza episode',edit:'Hariri',needTitle:'Jaza jina la filamu.',connect:'Function URL ya filamu haipatikani. Weka config.js kwenye folda moja na admin.html.',confirmMv:'Futa filamu hii? Haiwezi kurudishwa.',noMv:'Hakuna filamu zinazolingana.',
184
  email:'Email',joined:'Amejiunga',lastIn:'Mwisho kuingia',wl:'Watchlist',locked:'Locked',pin:'PIN Wazazi',state:'Hali',act:'Vitendo',banned:'Amezuiwa',normal:'Kawaida',ban:'Zuia',unban:'Fungua',noUs:'Hakuna watumiaji.',confirmBan:'Kumzuia mtumiaji huyu?',confirmUser:'KUFUTA akaunti ya {x}? Hatua hii haiwezi kurudishwa.',
185
  kLive:'πŸ“Ί Live TV',kVod:'🎬 VOD',kGen:'πŸ”” Jumla',nLive:'Jina la channel',nVod:'Jina la filamu / kipindi',nGen:'Kichwa',msg:'Ujumbe',img:'Picha (URL)',imgH:'Hiari. https, uwiano 2:1 (mf. 1024Γ—512) unaonekana vizuri.',target:'Ikibonyezwa, fungua app kwenye',saveIn:'Hifadhi pia ndani ya app',saveInH:'Inaonekana kwenye kengele ya notifications.',send:'Tuma sasa',sending:'Inatuma...',fill:'Jaza jina na ujumbe.',confirmP:'Tuma kwa watumiaji wote?',okSave:'Imehifadhiwa na push imetumwa kwa wote.',okPush:'Push imetumwa: ',badSecret:'Neno la siri si sahihi.',liveT:'πŸ“Ί Live TV: {n}',liveM:'Inaonyeshwa sasa. Bonyeza kutazama!',vodT:'🎬 Mpya: {n}',vodM:'Sasa inapatikana kwenye JAYNES MAX. Tazama sasa!',pvT:'Kichwa',pvM:'Ujumbe utaonekana hapa',needId:'Weka ID ya ukurasa unaotaka kufungua.',badImg:'Picha lazima ianze na https://',
@@ -189,7 +193,7 @@ hOrder:'Mpangilio wa sehemu (juu β†’ chini)',hBanner:'Bango la juu',hShow:'Onyes
189
  sAdmin:'Admin API',sTok:'Admin token (hiari)',sTokH:'Ukiacha wazi, inatumika thamani ya msingi (jaynes-max-tv).',sMovie:'Filamu (Supabase)',sHint:'Zinahifadhiwa kwenye kivinjari hiki tu. URL na key ya filamu zinasomwa kiotomatiki kutoka config.js; hapa unabadilisha tu ukihitaji.',sClear:'Futa taarifa hizi'},
190
  en:{mvSrcNew:'New (MP4)',mvSrcOld:'Old',mvAll:'All',mvImport:'⬇️ Import MP4 movies',mvImporting:'Importing… {n}/{t}',mvImported:'Done: +{a} new, {u} updated',mvPub:'Publish',mvUnpub:'Back to Draft',gSub:'Sign in to manage the app, users and content.',gPw:'Password',gBtn:'Sign in',gBad:'Wrong password.',gHttps:'Open this page over https.',logout:'Sign out',loading:'Loading...',refresh:'Refresh',save:'Save',cancel:'Cancel',yes:'Yes',no:'No',del:'Delete',none:'Nothing here yet.',err:'Error: ',saved:'Saved.',deleted:'Deleted.',
191
  nOv:'Overview',nMv:'Movies',nUs:'Users',nPu:'Push',nAn:'Announcements',nHm:'Home',nSt:'Settings',search:'Search by title or DJ...',searchEmail:'Search by email...',
192
- oUsers:'Total users',oNew:'New this week',oActive:'Signed in this week',oWl:'Watchlist items',oPin:'Parental PIN on',oBan:'Banned',oMv:'Movies',oAn:'Active announcements',oNote:'User stats come from cloud profiles (user_profiles); people without an account are not counted.',
193
  mType:'Type',tMovie:'Movie (single part)',tSeries:'Series (many episodes)',mUrls:'Movie URLs (you can add several parts)',mAddPart:'+ Add part',mBulk:'Paste many URLs at once',mBulkPh:'One URL per line (line 1 = Part 1, line 2 = Part 2...)',mSplit:'Split into parts',mSeasons:'Seasons and episodes',mAddSeason:'+ Add season',delSeason:'Delete season',addEp:'+ Add episode',needUrl:'Enter at least one URL.',partsSet:'{n} parts set.',epsToParts:'{n} episodes became {n} parts.',partsB:'parts',mvNew:'New movie',mvAdd:'Add movie / series',mvEdit:'Edit: ',mvSave:'Save movie',mvUpd:'Update movie',mTitle:'Title',mYear:'Year',mCat:'Category',cNormal:'Regular',cAdult:'Adults',mPrice:'Price (TZS)',mStatus:'Status',mDesc:'Description',mCast:'Cast (comma separated)',mEps:'Episode / video URLs',mAddEp:'+ Add episode',edit:'Edit',needTitle:'Enter the movie title.',connect:'Movies Function URL not found. Put config.js in the same folder as admin.html.',confirmMv:'Delete this movie? This cannot be undone.',noMv:'No matching movies.',
194
  email:'Email',joined:'Joined',lastIn:'Last sign-in',wl:'Watchlist',locked:'Locked',pin:'Parental PIN',state:'Status',act:'Actions',banned:'Banned',normal:'Active',ban:'Ban',unban:'Unban',noUs:'No users.',confirmBan:'Ban this user?',confirmUser:'DELETE the account of {x}? This cannot be undone.',
195
  kLive:'πŸ“Ί Live TV',kVod:'🎬 VOD',kGen:'πŸ”” General',nLive:'Channel name',nVod:'Movie / show title',nGen:'Title',msg:'Message',img:'Image (URL)',imgH:'Optional. Use https; a 2:1 ratio (e.g. 1024Γ—512) looks best.',target:'When tapped, open the app on',saveIn:'Also save inside the app',saveInH:'Shows in the in-app notification bell.',send:'Send now',sending:'Sending...',fill:'Fill in the name and message.',confirmP:'Send to all users?',okSave:'Saved and push sent to all subscribers.',okPush:'Push sent: ',badSecret:'Invalid secret.',liveT:'πŸ“Ί Live TV: {n}',liveM:'Live now. Tap to watch!',vodT:'🎬 New: {n}',vodM:'Now available on JAYNES MAX. Watch now!',pvT:'Title',pvM:'Message will appear here',needId:'Enter the ID of the page to open.',badImg:'Image must start with https://',
@@ -252,13 +256,27 @@ async function mreq(method,body){let url=MOVIE_FN;if(method==='POST_IMPORT'){url
252
 
253
  /* ───────── Overview ───────── */
254
  let users=[],movies=[],anns=[];
 
 
 
 
 
 
 
 
 
 
 
255
  function renderOv(){
256
  const now=Date.now(),wk=now-6048e5,isB=u=>u.banned_until&&new Date(u.banned_until)>new Date();
257
  const c=[[users.length,'oUsers',1],[users.filter(u=>new Date(u.created_at)>wk).length,'oNew'],[users.filter(u=>u.last_sign_in_at&&new Date(u.last_sign_in_at)>wk).length,'oActive'],
258
  [users.reduce((s,u)=>s+(u.profile?u.profile.watchlist_count:0),0),'oWl'],[users.filter(u=>u.profile&&u.profile.parental_enabled).length,'oPin'],[users.filter(isB).length,'oBan'],
259
  [movies.length,'oMv'],[anns.filter(a=>a.active).length,'oAn']];
260
  $('ovArea').className='';
261
- $('ovArea').innerHTML=`<div class="stats">${c.map(x=>`<div class="stat${x[2]?' hot':''}"><b>${x[0]}</b><span>${t(x[1])}</span></div>`).join('')}</div><div class="hint">${t('oNote')}</div>`;
 
 
 
262
  }
263
 
264
  /* ───────── Users ───────── */
@@ -635,6 +653,7 @@ document.addEventListener('click',e=>{const b=e.target.closest('[data-a]');if(b&
635
  /* ───────── Init ───────── */
636
  function init(){mvReset(false);loadUsers();loadAnn();loadHome();loadMovies()}
637
  applyLang();show('ov');init();
 
638
  </script>
639
  </body>
640
  </html>
 
64
  .pcard small{padding:0 8px;color:var(--mu);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
65
  .pcard:active{border-color:var(--rd)}
66
  @media(prefers-reduced-motion:reduce){.toast{transition:none}}
67
+
68
+ .stat.live b{color:var(--ok)}
69
+ .stat.live span::before{content:"";display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--ok);margin-right:6px;animation:jmP 1.6s infinite}
70
+ @keyframes jmP{50%{opacity:.25}}
71
  </style>
72
  </head>
73
  <body>
 
183
  const T={
184
  sw:{mvSrcNew:'Mpya (MP4)',mvSrcOld:'Za zamani',mvAll:'Zote',mvImport:'⬇️ Leta zenye MP4',mvImporting:'Inaleta… {n}/{t}',mvImported:'Imekamilika: +{a} mpya, {u} zimesasishwa',mvPub:'Publish',mvUnpub:'Rudisha Draft',gSub:'Ingia kusimamia app, watumiaji na maudhui.',gPw:'Password',gBtn:'Ingia',gBad:'Password si sahihi.',gHttps:'Fungua ukurasa huu kupitia https.',logout:'Toka',loading:'Inapakia...',refresh:'Onyesha upya',save:'Hifadhi',cancel:'Ghairi',yes:'Ndiyo',no:'Hapana',del:'Futa',none:'Hakuna kitu bado.',err:'Hitilafu: ',saved:'Imehifadhiwa.',deleted:'Imefutwa.',
185
  nOv:'Muhtasari',nMv:'Filamu',nUs:'Watumiaji',nPu:'Push',nAn:'Matangazo',nHm:'Home',nSt:'Mipangilio',search:'Tafuta kwa jina au DJ...',searchEmail:'Tafuta kwa email...',
186
+ oOnline:'Online sasa',oOnHour:'Saa 1 iliyopita',oOnToday:'Leo (vifaa)',oOnNew:'Vifaa vipya leo',oOn7d:'Siku 7 (vifaa)',oOnTotal:'Vifaa vyote',oOnNote:'Online = kifaa kilichotuma ishara ndani ya dakika 2.5. Ni vifaa, si watu (mtu mwenye simu 2 anahesabiwa mara 2).',oUsers:'Jumla ya watumiaji',oNew:'Wapya wiki hii',oActive:'Waliingia wiki hii',oWl:'Vitu vya Watchlist',oPin:'PIN ya Wazazi imewashwa',oBan:'Wamezuiwa',oMv:'Filamu',oAn:'Matangazo active',oNote:'Takwimu za watumiaji zinatoka kwenye data ya wingu (user_profiles); wasio na akaunti hawaonekani.',
187
  mType:'Aina',tMovie:'Movie (sehemu moja)',tSeries:'Series (episode nyingi)',mUrls:'URL za movie (unaweza kuweka sehemu nyingi)',mAddPart:'+ Ongeza sehemu',mBulk:'Bandika URL nyingi kwa pamoja',mBulkPh:'URL moja kila mstari (mstari 1 = Sehemu 1, mstari 2 = Sehemu 2...)',mSplit:'Gawanya kuwa sehemu',mSeasons:'Seasons na episodes',mAddSeason:'+ Ongeza season',delSeason:'Futa season',addEp:'+ Ongeza episode',needUrl:'Weka URL angalau moja.',partsSet:'Sehemu {n} zimewekwa.',epsToParts:'Episodes {n} zimekuwa sehemu {n}.',partsB:'Sehemu',mvNew:'Filamu mpya',mvAdd:'Ongeza filamu / series',mvEdit:'Hariri: ',mvSave:'Hifadhi filamu',mvUpd:'Sasisha filamu',mTitle:'Jina (title)',mYear:'Mwaka',mCat:'Kategoria',cNormal:'Kawaida',cAdult:'Wakubwa',mPrice:'Bei (TZS)',mStatus:'Hali',mDesc:'Maelezo',mCast:'Waigizaji (tenganisha kwa koma)',mEps:'Episode / Video URLs',mAddEp:'+ Ongeza episode',edit:'Hariri',needTitle:'Jaza jina la filamu.',connect:'Function URL ya filamu haipatikani. Weka config.js kwenye folda moja na admin.html.',confirmMv:'Futa filamu hii? Haiwezi kurudishwa.',noMv:'Hakuna filamu zinazolingana.',
188
  email:'Email',joined:'Amejiunga',lastIn:'Mwisho kuingia',wl:'Watchlist',locked:'Locked',pin:'PIN Wazazi',state:'Hali',act:'Vitendo',banned:'Amezuiwa',normal:'Kawaida',ban:'Zuia',unban:'Fungua',noUs:'Hakuna watumiaji.',confirmBan:'Kumzuia mtumiaji huyu?',confirmUser:'KUFUTA akaunti ya {x}? Hatua hii haiwezi kurudishwa.',
189
  kLive:'πŸ“Ί Live TV',kVod:'🎬 VOD',kGen:'πŸ”” Jumla',nLive:'Jina la channel',nVod:'Jina la filamu / kipindi',nGen:'Kichwa',msg:'Ujumbe',img:'Picha (URL)',imgH:'Hiari. https, uwiano 2:1 (mf. 1024Γ—512) unaonekana vizuri.',target:'Ikibonyezwa, fungua app kwenye',saveIn:'Hifadhi pia ndani ya app',saveInH:'Inaonekana kwenye kengele ya notifications.',send:'Tuma sasa',sending:'Inatuma...',fill:'Jaza jina na ujumbe.',confirmP:'Tuma kwa watumiaji wote?',okSave:'Imehifadhiwa na push imetumwa kwa wote.',okPush:'Push imetumwa: ',badSecret:'Neno la siri si sahihi.',liveT:'πŸ“Ί Live TV: {n}',liveM:'Inaonyeshwa sasa. Bonyeza kutazama!',vodT:'🎬 Mpya: {n}',vodM:'Sasa inapatikana kwenye JAYNES MAX. Tazama sasa!',pvT:'Kichwa',pvM:'Ujumbe utaonekana hapa',needId:'Weka ID ya ukurasa unaotaka kufungua.',badImg:'Picha lazima ianze na https://',
 
193
  sAdmin:'Admin API',sTok:'Admin token (hiari)',sTokH:'Ukiacha wazi, inatumika thamani ya msingi (jaynes-max-tv).',sMovie:'Filamu (Supabase)',sHint:'Zinahifadhiwa kwenye kivinjari hiki tu. URL na key ya filamu zinasomwa kiotomatiki kutoka config.js; hapa unabadilisha tu ukihitaji.',sClear:'Futa taarifa hizi'},
194
  en:{mvSrcNew:'New (MP4)',mvSrcOld:'Old',mvAll:'All',mvImport:'⬇️ Import MP4 movies',mvImporting:'Importing… {n}/{t}',mvImported:'Done: +{a} new, {u} updated',mvPub:'Publish',mvUnpub:'Back to Draft',gSub:'Sign in to manage the app, users and content.',gPw:'Password',gBtn:'Sign in',gBad:'Wrong password.',gHttps:'Open this page over https.',logout:'Sign out',loading:'Loading...',refresh:'Refresh',save:'Save',cancel:'Cancel',yes:'Yes',no:'No',del:'Delete',none:'Nothing here yet.',err:'Error: ',saved:'Saved.',deleted:'Deleted.',
195
  nOv:'Overview',nMv:'Movies',nUs:'Users',nPu:'Push',nAn:'Announcements',nHm:'Home',nSt:'Settings',search:'Search by title or DJ...',searchEmail:'Search by email...',
196
+ oOnline:'Online now',oOnHour:'Last hour',oOnToday:'Today (devices)',oOnNew:'New devices today',oOn7d:'7 days (devices)',oOnTotal:'All devices',oOnNote:'Online = a device that sent a signal in the last 2.5 minutes. These are devices, not people (one person with 2 phones counts twice).',oUsers:'Total users',oNew:'New this week',oActive:'Signed in this week',oWl:'Watchlist items',oPin:'Parental PIN on',oBan:'Banned',oMv:'Movies',oAn:'Active announcements',oNote:'User stats come from cloud profiles (user_profiles); people without an account are not counted.',
197
  mType:'Type',tMovie:'Movie (single part)',tSeries:'Series (many episodes)',mUrls:'Movie URLs (you can add several parts)',mAddPart:'+ Add part',mBulk:'Paste many URLs at once',mBulkPh:'One URL per line (line 1 = Part 1, line 2 = Part 2...)',mSplit:'Split into parts',mSeasons:'Seasons and episodes',mAddSeason:'+ Add season',delSeason:'Delete season',addEp:'+ Add episode',needUrl:'Enter at least one URL.',partsSet:'{n} parts set.',epsToParts:'{n} episodes became {n} parts.',partsB:'parts',mvNew:'New movie',mvAdd:'Add movie / series',mvEdit:'Edit: ',mvSave:'Save movie',mvUpd:'Update movie',mTitle:'Title',mYear:'Year',mCat:'Category',cNormal:'Regular',cAdult:'Adults',mPrice:'Price (TZS)',mStatus:'Status',mDesc:'Description',mCast:'Cast (comma separated)',mEps:'Episode / video URLs',mAddEp:'+ Add episode',edit:'Edit',needTitle:'Enter the movie title.',connect:'Movies Function URL not found. Put config.js in the same folder as admin.html.',confirmMv:'Delete this movie? This cannot be undone.',noMv:'No matching movies.',
198
  email:'Email',joined:'Joined',lastIn:'Last sign-in',wl:'Watchlist',locked:'Locked',pin:'Parental PIN',state:'Status',act:'Actions',banned:'Banned',normal:'Active',ban:'Ban',unban:'Unban',noUs:'No users.',confirmBan:'Ban this user?',confirmUser:'DELETE the account of {x}? This cannot be undone.',
199
  kLive:'πŸ“Ί Live TV',kVod:'🎬 VOD',kGen:'πŸ”” General',nLive:'Channel name',nVod:'Movie / show title',nGen:'Title',msg:'Message',img:'Image (URL)',imgH:'Optional. Use https; a 2:1 ratio (e.g. 1024Γ—512) looks best.',target:'When tapped, open the app on',saveIn:'Also save inside the app',saveInH:'Shows in the in-app notification bell.',send:'Send now',sending:'Sending...',fill:'Fill in the name and message.',confirmP:'Send to all users?',okSave:'Saved and push sent to all subscribers.',okPush:'Push sent: ',badSecret:'Invalid secret.',liveT:'πŸ“Ί Live TV: {n}',liveM:'Live now. Tap to watch!',vodT:'🎬 New: {n}',vodM:'Now available on JAYNES MAX. Watch now!',pvT:'Title',pvM:'Message will appear here',needId:'Enter the ID of the page to open.',badImg:'Image must start with https://',
 
256
 
257
  /* ───────── Overview ───────── */
258
  let users=[],movies=[],anns=[];
259
+ let onl=null,onlErr='';
260
+ async function loadOnline(){
261
+ if(document.hidden)return;
262
+ try{
263
+ const base=USERS_FN.url.split('/functions/')[0];
264
+ const r=await fetch(base+'/rest/v1/rpc/jm_online_stats',{method:'POST',headers:{apikey:USERS_FN.anon,Authorization:'Bearer '+USERS_FN.anon,'Content-Type':'application/json'},body:'{}'});
265
+ if(!r.ok)throw new Error('Online: HTTP '+r.status+' β€” je, online-users.sql imeendeshwa kwenye project ya PROFILE?');
266
+ onl=await r.json();onlErr='';
267
+ }catch(e){onlErr=e.message||String(e)}
268
+ if(!$('p-ov').hidden)renderOv();
269
+ }
270
  function renderOv(){
271
  const now=Date.now(),wk=now-6048e5,isB=u=>u.banned_until&&new Date(u.banned_until)>new Date();
272
  const c=[[users.length,'oUsers',1],[users.filter(u=>new Date(u.created_at)>wk).length,'oNew'],[users.filter(u=>u.last_sign_in_at&&new Date(u.last_sign_in_at)>wk).length,'oActive'],
273
  [users.reduce((s,u)=>s+(u.profile?u.profile.watchlist_count:0),0),'oWl'],[users.filter(u=>u.profile&&u.profile.parental_enabled).length,'oPin'],[users.filter(isB).length,'oBan'],
274
  [movies.length,'oMv'],[anns.filter(a=>a.active).length,'oAn']];
275
  $('ovArea').className='';
276
+ const oc=onl?[[onl.online_now,'oOnline',1],[onl.last_hour,'oOnHour'],[onl.today,'oOnToday'],[onl.new_today,'oOnNew'],[onl.last_7d,'oOn7d'],[onl.total,'oOnTotal']]:[];
277
+ const plat=onl?Object.entries(onl.by_platform||{}).map(([k,v])=>esc(k)+': '+v).join(' Β· '):'';
278
+ const onHtml=onl?`<div class="stats">${oc.map(x=>`<div class="stat${x[2]?' live':''}"><b>${x[0]}</b><span>${t(x[1])}</span></div>`).join('')}</div><div class="hint" style="margin:-4px 0 16px">${plat?plat+' β€” ':''}${t('oOnNote')}</div>`:(onlErr?`<div class="hint er" style="margin-bottom:16px">${esc(onlErr)}</div>`:'');
279
+ $('ovArea').innerHTML=onHtml+`<div class="stats">${c.map(x=>`<div class="stat${x[2]?' hot':''}"><b>${x[0]}</b><span>${t(x[1])}</span></div>`).join('')}</div><div class="hint">${t('oNote')}</div>`;
280
  }
281
 
282
  /* ───────── Users ───────── */
 
653
  /* ───────── Init ───────── */
654
  function init(){mvReset(false);loadUsers();loadAnn();loadHome();loadMovies()}
655
  applyLang();show('ov');init();
656
+ loadOnline();setInterval(loadOnline,15000);document.addEventListener('visibilitychange',()=>{if(!document.hidden)loadOnline()});
657
  </script>
658
  </body>
659
  </html>