(function () { 'use strict'; function basePath() { return document.body.getAttribute('data-base-path') || ''; } function el(id) { return document.getElementById(id); } function escapeHtml(s) { return String(s || '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function formatMs(ms) { if (!ms) return '—'; try { return new Date(ms).toLocaleString(); } catch (e) { return String(ms); } } function durationS(startMs, endMs) { if (!startMs) return '—'; var end = endMs || Date.now(); var sec = Math.max(0, Math.round((end - startMs) / 1000)); if (sec < 60) return sec + 's'; return Math.floor(sec / 60) + 'm ' + (sec % 60) + 's'; } function statusClass(status) { if (status === 'live' || status === 'intent') return 'tag-pill tag-pill--ok'; if (status === 'expired') return 'tag-pill tag-pill--warn'; return 'tag-pill'; } function renderRows(sessions) { var tbody = el('live-sessions-tbody'); if (!tbody) return; if (!sessions || !sessions.length) { tbody.innerHTML = 'No sessions in this window.'; return; } tbody.innerHTML = sessions.map(function (s) { var joinUrl = s.join_short_url || ''; var joinCell = joinUrl ? 'Open' : '—'; return ( '' + '' + escapeHtml(s.status) + '' + '' + escapeHtml(s.owner_username || '—') + '' + '' + escapeHtml(s.platform || '—') + '' + '' + escapeHtml(s.codec_video || '—') + '' + '' + durationS(s.started_at_ms, s.ended_at_ms) + '' + '' + formatMs(s.last_heartbeat_ms) + '' + '' + Number(s.join_opens || 0) + '' + '' + joinCell + '' + '' ); }).join(''); } function load() { var status = el('live-sessions-status'); var daysSel = el('live-sessions-days'); var days = daysSel && daysSel.value ? daysSel.value : '14'; if (status) status.textContent = 'Loading…'; var xhr = new XMLHttpRequest(); xhr.open('GET', basePath() + '/api/live_cast.php?action=list&days=' + encodeURIComponent(days), true); xhr.onload = function () { var payload = null; try { payload = JSON.parse(xhr.responseText); } catch (e) { if (status) status.textContent = 'Invalid response'; return; } if (!payload || !payload.ok) { if (status) status.textContent = (payload && payload.error) || 'Failed'; return; } renderRows(payload.sessions || []); if (status) { status.textContent = 'Loaded ' + (payload.sessions || []).length + ' session(s) · ' + days + 'd window'; } }; xhr.onerror = function () { if (status) status.textContent = 'Network error'; }; xhr.send(); } function boot() { if (!el('live-sessions-app')) return; var daysSel = el('live-sessions-days'); if (daysSel) daysSel.addEventListener('change', load); load(); setInterval(load, 60000); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', boot); } else { boot(); } })();