Files @ 69ca2b2fc133
Branch filter:

Location: light9/web/ascoltami/main.ts

drewp@bigasterisk.com
overcomplicated attempt at persisting the pane layout in the rdf graph

this was hard because we have to somehow wait for the graph to load before config'ing the panes
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);
  });

};