diff web/ascoltami/main.ts @ 2376:4556eebe5d73

topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author drewp@bigasterisk.com
date Sun, 12 May 2024 19:02:10 -0700
parents light9/web/ascoltami/main.ts@06bf6dae8e64
children cc69faa87c27
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/ascoltami/main.ts	Sun May 12 19:02:10 2024 -0700
@@ -0,0 +1,100 @@
+function byId(id: string): HTMLElement {
+  return document.getElementById(id)!;
+}
+
+export interface TimingUpdate {
+  // GET /ascoltami/time response
+  duration: number;
+  next: string; // e.g. 'play'
+  playing: boolean;
+  song: string;
+  started: number; // unix sec
+  t: number; // seconds into song
+  state: { current: { name: string }; pending: { name: string } };
+}
+
+(window as any).finishOldStyleSetup = async (times: { intro: number; post: number }, timingUpdate: (data: TimingUpdate) => void) => {
+  let currentHighlightedSong = "";
+  // let lastPlaying = false;
+
+  
+  const events = new EventSource("../service/ascoltami/time/stream");
+  events.addEventListener("message", (m)=>{
+    const update = JSON.parse(m.data) as TimingUpdate
+    updateCurrent(update)
+    markUpdateTiming();
+  })
+
+  async function updateCurrent(data:TimingUpdate) {
+    byId("currentSong").innerText = data.song;
+    if (data.song != currentHighlightedSong) {
+      showCurrentSong(data.song);
+    }
+    byId("currentTime").innerText = data.t.toFixed(1);
+    byId("leftTime").innerText = (data.duration - data.t).toFixed(1);
+    byId("leftAutoStopTime").innerText = Math.max(0, data.duration - times.post - data.t).toFixed(1);
+    byId("states").innerText = JSON.stringify(data.state);
+    //   document.querySelector("#timeSlider").slider({ value: data.t, max: data.duration });
+    timingUpdate(data);
+  }
+  let recentUpdates: Array<number> = [];
+  function markUpdateTiming() {
+    recentUpdates.push(+new Date());
+    recentUpdates = recentUpdates.slice(Math.max(recentUpdates.length - 5, 0));
+  }
+
+  function refreshUpdateFreqs() {
+    if (recentUpdates.length > 1) {
+      if (+new Date() - recentUpdates[recentUpdates.length - 1] > 1000) {
+        byId("updateActual").innerText = "(stalled)";
+        return;
+      }
+
+      var avgMs = (recentUpdates[recentUpdates.length - 1] - recentUpdates[0]) / (recentUpdates.length - 1);
+      byId("updateActual").innerText = "" + Math.round(1000 / avgMs);
+    }
+  }
+  setInterval(refreshUpdateFreqs, 2000);
+
+  function showCurrentSong(uri: string) {
+    document.querySelectorAll(".songs div").forEach((row: Element, i: number) => {
+      if (row.querySelector("button")!.dataset.uri == uri) {
+        row.classList.add("currentSong");
+      } else {
+        row.classList.remove("currentSong");
+      }
+    });
+    currentHighlightedSong = uri;
+  }
+
+  const data = await (await fetch("api/songs")).json();
+  data.songs.forEach((song: { uri: string; label: string }) => {
+    const button = document.createElement("button");
+    // link is just for dragging, not clicking
+    const link = document.createElement("a");
+    const n = document.createElement("span");
+    n.classList.add("num");
+    n.innerText = song.label.slice(0, 2);
+    link.appendChild(n);
+
+    const sn = document.createElement("span");
+    sn.classList.add("song-name");
+    sn.innerText = song.label.slice(2).trim();
+    link.appendChild(sn);
+    link.setAttribute("href", song.uri);
+    link.addEventListener("click", (ev) => {
+      ev.stopPropagation();
+      button.click();
+    });
+    button.appendChild(link);
+    button.dataset.uri = song.uri;
+    button.addEventListener("click", async (ev) => {
+      await fetch("api/song", { method: "POST", body: song.uri });
+      showCurrentSong(song.uri);
+    });
+    const dv = document.createElement("div");
+    dv.appendChild(button);
+    document.querySelector(".songs")!.appendChild(dv);
+  });
+
+};