Files

102 lines
4.9 KiB
JavaScript

'use strict';
(function () {
const $ = id => document.getElementById(id);
const roomId = decodeURIComponent((location.pathname.match(/^\/room\/([A-Za-z0-9_-]+)\/?$/) || [])[1] || '');
let adminSecret = new URLSearchParams(location.hash.slice(1)).get('key') || '';
let adminLink = '';
let audienceUrl = roomId ? location.origin + '/watch/' + roomId : '';
function show(id) {
for (const section of ['loading', 'denied', 'room']) $(section).hidden = section !== id;
}
function setStatus(id, state, text) {
$(id + 'Status').textContent = text;
window.CaptionStatus?.set(id + 'Dot', state, text);
}
function fail(message) {
setStatus('room', 'danger', message);
$('deniedText').textContent = message; show('denied');
}
async function checkService() {
try {
const response = await fetch('/health', {credentials: 'same-origin', signal: AbortSignal.timeout(10000)});
if (!response.ok) throw new Error();
const info = await response.json();
setStatus('service', info.ready ? 'good' : 'warn', info.ready ? 'Speech service ready' : 'Speech service starting');
} catch (_) {
setStatus('service', 'danger', 'Speech service unavailable');
}
}
async function api(path, options = {}) {
const headers = new Headers(options.headers || {});
if (options.body) headers.set('Content-Type', 'application/json');
return fetch(path, {...options, headers, credentials: 'same-origin', signal: AbortSignal.timeout(10000)});
}
function setAdminLink(value) {
adminLink = value;
$('adminLink').textContent = value || 'Not available in this tab — create a fresh link below.';
$('copyAdmin').disabled = !value;
}
async function copy(value, button, label) {
try {
await navigator.clipboard.writeText(value);
button.textContent = 'Copied';
setTimeout(() => { button.textContent = label; }, 1500);
} catch (_) {
$('result').textContent = 'Select the link above and copy it.';
}
}
function renderRoom(room, canonicalAudience) {
const name = (room.label || '').trim() || 'Caption Admin Room';
$('roomName').textContent = name;
document.title = name === 'Caption Admin Room' ? name : name + ' — Caption Admin Room';
$('roomId').textContent = room.id;
$('created').textContent = room.created ? new Date(room.created * 1000).toLocaleString() : '';
if (canonicalAudience) audienceUrl = canonicalAudience;
$('captureLink').href = '/capture-local.html';
$('editorLink').href = '/room/' + encodeURIComponent(room.id) + '/edit';
$('audienceLink').href = audienceUrl;
$('audienceLinkText').textContent = audienceUrl;
window.CaptionRoomMenu?.set({roomId: room.id, audienceUrl});
setAdminLink(adminLink);
setStatus('room', 'good', 'Room active');
show('room');
}
async function boot() {
if (!roomId) { fail('This room address is invalid.'); return; }
if (adminSecret) {
const response = await api('/api/rooms/' + encodeURIComponent(roomId) + '/session', {
method: 'POST', body: JSON.stringify({key: adminSecret})
});
if (!response.ok) { fail('This admin link is invalid or the room has been closed.'); return; }
adminLink = location.origin + '/room/' + roomId + '#key=' + adminSecret;
history.replaceState(null, '', '/room/' + roomId);
}
const response = await api('/api/rooms/' + encodeURIComponent(roomId));
if (response.status === 401) { fail('Open this room with its private admin link.'); return; }
if (!response.ok) { fail('This room is closed or unavailable.'); return; }
const data = await response.json();
renderRoom(data.room, data.audienceUrl);
}
$('copyAdmin').onclick = () => copy(adminLink, $('copyAdmin'), 'Copy admin link');
$('copyAudience').onclick = () => copy(audienceUrl, $('copyAudience'), 'Copy audience link');
$('rotate').onclick = async () => {
if (!confirm('Replace the admin link? The old admin link and existing editor sessions will stop working. Audience links keep working.')) return;
const response = await api('/api/rooms/' + encodeURIComponent(roomId) + '/rotate', {method: 'POST'});
const data = await response.json().catch(() => ({}));
if (!response.ok) { $('result').textContent = data.detail || 'Could not create a new link.'; return; }
adminSecret = data.adminUrl.split('#key=')[1] || '';
setAdminLink(adminSecret ? location.origin + '/room/' + roomId + '#key=' + adminSecret : '');
$('result').textContent = 'Fresh admin link created. Copy it now and keep it private.';
};
$('close').onclick = async () => {
if (!confirm('Close this admin room? Admin, editor and audience links will stop working.')) return;
const response = await api('/api/rooms/' + encodeURIComponent(roomId), {method: 'DELETE'});
if (!response.ok) { $('result').textContent = 'This admin room could not be closed.'; return; }
setStatus('room', 'danger', 'Room closed');
fail('This admin room has been closed.');
};
checkService(); setInterval(checkService, 30000);
boot().catch(() => fail('The service could not be reached. Try again.'));
})();