mirror of
git://f0xx.org/ac/ac-be-issues
synced 2026-07-29 05:58:39 +03:00
initial
This commit is contained in:
113
public/assets/js/live_sessions.js
Normal file
113
public/assets/js/live_sessions.js
Normal file
@@ -0,0 +1,113 @@
|
||||
(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();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user