Changeset - eb5d8349c871
[Not reviewed]
default
0 2 0
drewp@bigasterisk.com - 3 years ago 2022-06-03 06:35:17
drewp@bigasterisk.com
pass timing updates in a simpler way
2 files changed with 23 insertions and 23 deletions:
0 comments (0 inline, 0 general)
light9/ascoltami/Light9AscoltamiUi.ts
Show inline comments
 
import debug from "debug";
 
import { html, LitElement } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
export { RdfdbSyncedGraph } from "../web/RdfdbSyncedGraph";
 
export { Light9TimelineAudio } from "../web/light9-timeline-audio";
 
import { classMap } from "lit/directives/class-map.js";
 
import { TimingUpdate } from "./main";
 

	
 
debug.enable("*");
 
const log = debug("asco");
 

	
 
function byId(id: string): HTMLElement {
 
  return document.getElementById(id)!;
 
}
 
async function postJson(url: string, jsBody: Object) {
 
  return fetch(url, {
 
    method: "POST",
 
    headers: { "Content-Type": "applcation/json" },
 
    body: JSON.stringify(jsBody),
 
  });
 
}
 
@customElement("light9-ascoltami-ui")
 
export class Light9AscoltamiUi extends LitElement {
 
  graph!: SyncedGraph;
 
  times!: { intro: number; post: number };
 
  currentDuration: number = 0;
 
  @property() nextText: string = "";
 
  @property() isPlaying: boolean = false;
 
  @property() song: NamedNode | null = null;
 
  @property() t: number = 0;
 
  @property() currentDuration: number = 0;
 
  render() {
 
    return html`<rdfdb-synced-graph></rdfdb-synced-graph>
 

	
 
      <link rel="stylesheet" href="./style.css" />
 

	
 
      <h1>ascoltami <a href="metrics">[metrics]</a></h1>
 

	
 
      <div class="commands">
 
        <button id="cmd-stop" @click=${this.onCmdStop} class="playMode ${classMap({ active: !this.isPlaying })}">
 
          <strong>Stop</strong>
 
          <div class="key">s</div>
 
        </button>
 
        <button id="cmd-play" @click=${this.onCmdPlay} class="playMode ${classMap({ active: this.isPlaying })}">
 
          <strong>Play</strong>
 
          <div class="key">p</div>
 
        </button>
 
        <button id="cmd-intro" @click=${this.onCmdIntro}>
 
          <strong>Skip intro</strong>
 
          <div class="key">i</div>
 
        </button>
 
        <button id="cmd-post" @click=${this.onCmdPost}>
 
          <strong>Skip to Post</strong>
 
          <div class="key">t</div>
 
        </button>
 
        <button id="cmd-go" @click=${this.onCmdGo}>
 
          <strong>Go</strong>
 
          <div class="key">g</div>
 
          <div id="next">${this.nextText}</div>
 
        </button>
 
      </div> `;
 
  }
 

	
 
  onCmdStop(ev?: MouseEvent): void {
 
    postJson("api/time", { pause: true });
 
  }
 
  onCmdPlay(ev?: MouseEvent): void {
 
    postJson("api/time", { resume: true });
 
  }
 
  onCmdIntro(ev?: MouseEvent): void {
 
    postJson("api/time", { t: this.times.intro, resume: true });
 
  }
 
  onCmdPost(ev?: MouseEvent): void {
 
    postJson("api/time", { t: this.currentDuration - this.times.post, resume: true });
 
  }
 
  onCmdGo(ev?: MouseEvent): void {
 
    postJson("api/go", {});
 
  }
 

	
 
  bindKeys() {
 
    document.addEventListener("keypress", (ev) => {
 
      if (ev.which == 115) {
 
        this.onCmdStop();
 
        return false;
 
      }
 
      if (ev.which == 112) {
 
        this.onCmdPlay();
 
        return false;
 
      }
 
      if (ev.which == 105) {
 
        this.onCmdIntro();
 
        return false;
 
      }
 
      if (ev.which == 116) {
 
        this.onCmdPost();
 
        return false;
 
      }
 

	
 
      if (ev.key == "g") {
 
        this.onCmdGo();
 
        return false;
 
      }
 
      return true;
 
    });
 
  }
 

	
 
  currentDurationChanged(newDuration: number): void {
 
    this.currentDuration = newDuration;
 
  }
 

	
 
  async musicSetup() {
 
    // shoveled over from the vanillajs version
 
    const config = await (await fetch("api/config")).json();
 
    this.times = config.times;
 
    document.title = document.title.replace("{{host}}", config.host);
 
    const h1 = document.querySelector("h1")!;
 
    h1.innerText = h1.innerText.replace("{{host}}", config.host);
 

	
 
    byId("nav").innerText = navigator.userAgent;
 
    var updateFreq = navigator.userAgent.indexOf("Linux") != -1 ? 10 : 2;
 
    if (navigator.userAgent.match(/Windows NT/)) {
 
      // helper laptop
 
      updateFreq = 10;
 
    }
 
    byId("updateReq").innerText = "" + updateFreq;
 

	
 
    (window as any).finishOldStyleSetup(
 
      this.times,
 
      updateFreq,
 
      this.currentDurationChanged.bind(this),
 
      (t: string) => {
 
        this.nextText = t;
 
      },
 
      (is: boolean) => {
 
        this.isPlaying = is;
 
      }
 
    );
 
    (window as any).finishOldStyleSetup(this.times, updateFreq, (data: TimingUpdate) => {
 
      this.nextText = data.next;
 
      this.isPlaying = data.playing;
 
      this.currentDuration = data.duration;
 
    });
 
  }
 

	
 
  constructor() {
 
    super();
 
    this.bindKeys();
 
    //   byId("cmd-stop").addEventListener("click", (ev: Event) =>
 
    // );
 

	
 
    getTopGraph().then((g) => {
 
      this.graph = g;
 
      this.musicSetup(); // async
 
    });
 
  }
 
}
light9/ascoltami/main.ts
Show inline comments
 
function byId(id: string): HTMLElement {
 
  return document.getElementById(id)!;
 
}
 

	
 
(window as any).finishOldStyleSetup = async (
 
  times: { intro: number; post: number },
 
  updateFreq: number,
 
  currentDurationChanged: (d: number) => void,
 
  setNextText: (t: string) => void,
 
  setIsPlaying: (is: boolean) => void
 
) => {
 
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 }, updateFreq: number, timingUpdate: (data: TimingUpdate) => void) => {
 
  let currentHighlightedSong = "";
 
  // let lastPlaying = false;
 

	
 
  async function updateCurrent() {
 
    const data = await (await fetch("api/time")).json();
 
    const data: TimingUpdate = await (await fetch("api/time")).json();
 
    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);
 
    currentDurationChanged(data.duration);
 
    //   document.querySelector("#timeSlider").slider({ value: data.t, max: data.duration });
 
    setIsPlaying(data.playing);
 
    setNextText(data.next);
 
    timingUpdate(data);
 
  }
 

	
 
  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);
 
  });
 

	
 
  //   var pendingSlide = false;
 
  //   $("#timeSlider").slider({
 
  //     step: 0.01,
 
  //     slide: function (event, ui) {
 
  //       if (pendingSlide) {
0 comments (0 inline, 0 general)