mirror of
git://f0xx.org/ac/ac-be-issues
synced 2026-07-29 07:39:36 +03:00
114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
(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, '>')
|
|
.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 = '<tr><td colspan="8" class="muted">No sessions in this window.</td></tr>';
|
|
return;
|
|
}
|
|
tbody.innerHTML = sessions.map(function (s) {
|
|
var joinUrl = s.join_short_url || '';
|
|
var joinCell = joinUrl
|
|
? '<a href="' + escapeHtml(joinUrl) + '" target="_blank" rel="noopener">Open</a>'
|
|
: '—';
|
|
return (
|
|
'<tr>' +
|
|
'<td><span class="' + statusClass(s.status) + '">' + escapeHtml(s.status) + '</span></td>' +
|
|
'<td>' + escapeHtml(s.owner_username || '—') + '</td>' +
|
|
'<td>' + escapeHtml(s.platform || '—') + '</td>' +
|
|
'<td>' + escapeHtml(s.codec_video || '—') + '</td>' +
|
|
'<td>' + durationS(s.started_at_ms, s.ended_at_ms) + '</td>' +
|
|
'<td>' + formatMs(s.last_heartbeat_ms) + '</td>' +
|
|
'<td>' + Number(s.join_opens || 0) + '</td>' +
|
|
'<td>' + joinCell + '</td>' +
|
|
'</tr>'
|
|
);
|
|
}).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();
|
|
}
|
|
})();
|