import debug from "debug"; import { css, html, LitElement, PropertyValues } from "lit"; import { customElement, property } from "lit/decorators.js"; import { NamedNode } from "n3"; import { PlainViewState } from "../Light9CursorCanvas"; import { getTopGraph } from "../RdfdbSyncedGraph"; import { SyncedGraph } from "../SyncedGraph"; import { PlayerState } from "./PlayerState"; export { RdfdbSyncedGraph } from "../RdfdbSyncedGraph"; export { ResourceDisplay } from "../ResourceDisplay"; export { Light9AscoltamiTimeline } from "./Light9AscoltamiTimeline"; export { Light9SongListing } from "./Light9SongListing"; debug.enable("*"); const log = debug("asco"); 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; @property() show: NamedNode | null = null; @property() song: NamedNode | null = null; @property() selectedSong: NamedNode | null = null; @property() viewState: PlainViewState | null = null; @property() host: any; @property() playerState: PlayerState = { duration: null, endOfSong: null, pausedSongTime: null, playing: null, song: null, wallStartTime: null }; @property() playerTime: number = 0; static styles = [ css` :host { display: flex; flex-direction: column; } .keyCap { color: #ccc; background: #525252; display: inline-block; border: 1px outset #b3b3b3; padding: 2px 3px; margin: 3px 0; margin-left: 0.4em; font-size: 16px; box-shadow: 0.9px 0.9px 0px 2px #565656; border-radius: 2px; } button { min-height: 48pt; min-width: 65pt; } #mainRow { display: flex; flex-direction: row; } light9-song-listing { flex-grow: 1; } th { text-align: right; } #bigTime { color: green; font-size: 60pt; } `, ]; constructor() { super(); getTopGraph().then((g) => { this.graph = g; this.graph.runHandler(this.updatePlayState.bind(this), "playstate-ui"); }); setInterval(this.updateT.bind(this), 100); } protected async firstUpdated(_changedProperties: PropertyValues) { this.bindKeys(); const config = await (await fetch("/service/ascoltami/config")).json(); document.title = document.title.replace("{{host}}", config.host); this.host = config.host; } updatePlayState() { const U = this.graph.U(); const asco = U(":ascoltami"); this.playerState = { duration: this.graph.optionalFloatValue(asco, U(":duration")), endOfSong: this.graph.optionalBooleanValue(asco, U(":endOfSong")), pausedSongTime: this.graph.optionalFloatValue(asco, U(":pausedSongTime")), wallStartTime: this.graph.optionalFloatValue(asco, U(":wallStartTime")), playing: this.graph.optionalBooleanValue(asco, U(":playing")), song: this.graph.optionalUriValue(asco, U(":song")), }; this.updateT(); } updateT() { if (this.playerState.wallStartTime !== null) { this.playerTime = Date.now() / 1000 - this.playerState.wallStartTime; } else if (this.playerState.pausedSongTime !== null) { this.playerTime = this.playerState.pausedSongTime; } else { this.playerTime = 0; } } render() { return html`

ascoltami on ${this.host}

{ this.selectedSong = ev.detail.song; }} .selectedSong=${this.selectedSong} >
t=${this.playerTime.toFixed(1)}
${this.renderPlayerStateTable()}
`; } renderPlayerStateTable() { return html`
duration ${this.playerState.duration}
endOfSong ${this.playerState.endOfSong}
pausedSongTime ${this.playerState.pausedSongTime?.toFixed(3)}
playing ${this.playerState.playing}
song ${this.playerState.song?.value}
wallStartTime ${this.playerState.wallStartTime}
t ${this.playerTime.toFixed(3)}
`; } onSelectSong(song: NamedNode, ev: MouseEvent) { if (this.selectedSong && song.equals(this.selectedSong)) { this.selectedSong = null; } else { this.selectedSong = song; } } async onLoadSelected() { if (!this.selectedSong) { return; } await fetch("/service/ascoltami/song", { method: "POST", body: this.selectedSong.value }); this.selectedSong = null; } onCmdStop(ev?: MouseEvent): void { postJson("/service/ascoltami/time", { pause: true }); } onCmdPlay(ev?: MouseEvent): void { postJson("/service/ascoltami/time", { resume: true }); } onCmdGo(ev?: MouseEvent): void { postJson("/service/ascoltami/go", {}); } onCmdZero(ev?: MouseEvent): void { postJson("/service/ascoltami/time", { t: 0 }); } bindKeys() { document.addEventListener("keypress", (ev) => { if (ev.key == "l") { this.onLoadSelected(); } else if (ev.key == "z") { this.onCmdZero(); } else if (ev.key == "p") { this.onCmdPlay(); } else if (ev.key == "s") { this.onCmdStop(); } else if (ev.key == "g") { this.onCmdGo(); } else { return true; } }); } }