This commit is contained in:
2026-05-01 22:08:50 -07:00
parent 8b7a1f81ad
commit e51aeae54e
9 changed files with 196 additions and 15 deletions

View File

@@ -5,6 +5,8 @@ const elements = {
url: document.querySelector('#stream-url'),
next: document.querySelector('#next'),
entryMessage: document.querySelector('#entry-message'),
recentPanel: document.querySelector('#recent-panel'),
recentList: document.querySelector('#recent-list'),
audio: document.querySelector('#audio'),
canvas: document.querySelector('#screen'),
stage: document.querySelector('#video-stage'),
@@ -28,8 +30,11 @@ const state = {
frameCount: 0,
controlsVisible: true,
hideControlsTimer: 0,
recentUrls: [],
};
void loadRecentUrls();
elements.form.addEventListener('submit', async (event) => {
event.preventDefault();
setEntryMessage('');
@@ -51,6 +56,7 @@ elements.form.addEventListener('submit', async (event) => {
}
showPlayer();
void loadRecentUrls();
startSession(payload);
} catch (error) {
stopSession();
@@ -60,6 +66,23 @@ elements.form.addEventListener('submit', async (event) => {
}
});
elements.recentList.addEventListener('click', (event) => {
const button = event.target.closest('[data-recent-index]');
if (!button) {
return;
}
const item = state.recentUrls[Number(button.dataset.recentIndex)];
if (!item) {
return;
}
elements.url.value = item.url;
elements.form.requestSubmit();
});
elements.stage.addEventListener('pointerup', (event) => {
if (!state.session || event.target.closest('.controls')) {
return;
@@ -387,6 +410,7 @@ function syncControlLabels() {
function showEntry() {
elements.playerScreen.hidden = true;
elements.entryScreen.hidden = false;
void loadRecentUrls();
elements.url.focus();
}
@@ -410,4 +434,40 @@ function setEntryMessage(message) {
function setFormBusy(isBusy) {
elements.url.disabled = isBusy;
elements.next.disabled = isBusy;
for (const button of elements.recentList.querySelectorAll('button')) {
button.disabled = isBusy;
}
}
async function loadRecentUrls() {
try {
const response = await fetch('/api/recent-urls', { cache: 'no-store' });
if (!response.ok) {
throw new Error('Failed to load recent URLs.');
}
const payload = await response.json();
state.recentUrls = Array.isArray(payload.urls) ? payload.urls : [];
renderRecentUrls();
} catch {
state.recentUrls = [];
renderRecentUrls();
}
}
function renderRecentUrls() {
elements.recentList.replaceChildren(
...state.recentUrls.map((item, index) => {
const button = document.createElement('button');
button.type = 'button';
button.className = 'recent-url';
button.dataset.recentIndex = String(index);
button.textContent = item.displayUrl || item.url;
return button;
}),
);
elements.recentPanel.hidden = state.recentUrls.length === 0;
}