2026-11-06 08:28:04 +00:00
|
|
|
async function load() {
|
|
|
|
|
try {
|
2026-11-07 15:03:14 +00:00
|
|
|
const response = await fetch(`/api/state?${windowQuery()}`, {cache: "no-store"});
|
2026-11-06 08:28:04 +00:00
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error(String(response.status));
|
|
|
|
|
}
|
|
|
|
|
const next = await response.json();
|
|
|
|
|
const previous = state.now;
|
|
|
|
|
state = next;
|
|
|
|
|
ui.offline = false;
|
|
|
|
|
if (JSON.stringify(state.settings) !== settingsSig) {
|
|
|
|
|
adoptSettings(state.settings);
|
|
|
|
|
}
|
|
|
|
|
tuneMusic(FADE / 1000);
|
|
|
|
|
drawSky();
|
|
|
|
|
announce();
|
|
|
|
|
render(false);
|
|
|
|
|
drawTime();
|
2026-11-08 21:18:55 +00:00
|
|
|
drawAgent();
|
2026-11-06 08:28:04 +00:00
|
|
|
drawStream();
|
|
|
|
|
if (motion.current.size === 0 || ui.asOf !== motion.asOf) {
|
|
|
|
|
const first = motion.current.size === 0;
|
|
|
|
|
motion.asOf = ui.asOf;
|
|
|
|
|
relayout(first ? 0 : ui.playing ? 450 : MOVE);
|
|
|
|
|
}
|
|
|
|
|
pulses(state.radio.filter((row) => row.ts > previous));
|
|
|
|
|
} catch {
|
|
|
|
|
ui.offline = true;
|
|
|
|
|
tick();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-11-12 10:20:31 +00:00
|
|
|
const SELECTION_HOLD = 20000;
|
|
|
|
|
let selectedSince = 0;
|
|
|
|
|
|
2026-11-06 08:28:04 +00:00
|
|
|
function refresh() {
|
2026-11-12 10:20:31 +00:00
|
|
|
const selected = String(window.getSelection()).length > 0;
|
|
|
|
|
selectedSince = selected ? selectedSince || Date.now() : 0;
|
|
|
|
|
if (!ui.busy && !ui.playing && !document.hidden && (!selected || Date.now() - selectedSince >= SELECTION_HOLD)) {
|
2026-11-06 08:28:04 +00:00
|
|
|
load();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function follow() {
|
|
|
|
|
if (ui.screen === "stream" && live() && !document.hidden) {
|
|
|
|
|
fetchEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|