From 9f14bc261a1b0bb1f8adf6349fd1d0a1159736ea Mon Sep 17 00:00:00 2001 From: Ondrej Zara Date: Wed, 20 Mar 2019 16:20:17 +0100 Subject: [PATCH] status features --- app/index.html | 14 ++++++++------ app/js/app.js | 5 ----- app/js/art.js | 33 ++++++++++++++++++++++----------- app/js/mpd.js | 40 +++++++++++++++++++++++++--------------- app/js/status.js | 44 +++++++++++++++++++++++++++++++++++++++----- 5 files changed, 94 insertions(+), 42 deletions(-) diff --git a/app/index.html b/app/index.html index 300d997..bad3dee 100644 --- a/app/index.html +++ b/app/index.html @@ -36,12 +36,14 @@ / - - - - - - + + + + + + + + diff --git a/app/js/app.js b/app/js/app.js index 7619f63..f7e4164 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -6,11 +6,6 @@ async function init() { await mpd.init(); status.init(); window.mpd = mpd; - art.get("NAS/ABBA/Greatest Hits/01 Dancing Queen.mp3").then(src => { - let image = document.createElement("img"); - image.src = src; - document.querySelector("main").appendChild(image); - }); } init(); diff --git a/app/js/art.js b/app/js/art.js index 6f25f14..c3f5672 100644 --- a/app/js/art.js +++ b/app/js/art.js @@ -10,8 +10,6 @@ async function getImageData(songUrl) { while (1) { let params = ["albumart", `"${mpd.escape(songUrl)}"`, offset]; let lines = await mpd.command(params.join(" ")); - if (lines.length == 1) { return null; } - data = data.concat(lines[2]); let metadata = parser.linesToStruct(lines.slice(0, 2)); if (data.length >= Number(metadata["size"])) { return data; } @@ -38,14 +36,27 @@ async function resize(image) { return new Promise(resolve => canvas.toBlob(resolve)); } -export async function get(songUrl) { - if (songUrl in cache) { return cache[songUrl]; } +export async function get(artist, album, songUrl = null) { + let key = `${artist}-${album}`; + if (key in cache) { return cache[key]; } - let data = await getImageData(songUrl); - let bytes = new Uint8Array(data); - let image = await bytesToImage(bytes); - let blob = await resize(image); - let url = URL.createObjectURL(blob); - cache[songUrl] = url; - return url; + if (!songUrl) { return null; } + + // promise to be returned in the meantime + let resolve; + let promise = new Promise(res => resolve = res); + cache[key] = promise; + + try { + let data = await getImageData(songUrl); + let bytes = new Uint8Array(data); + let image = await bytesToImage(bytes); + let blob = await resize(image); + let url = URL.createObjectURL(blob); + cache[key] = url; + resolve(url); + } catch (e) { + cache[key] = null; + } + return cache[key]; } diff --git a/app/js/mpd.js b/app/js/mpd.js index 3eb664b..7f6ba28 100644 --- a/app/js/mpd.js +++ b/app/js/mpd.js @@ -2,12 +2,18 @@ import * as parser from "./parser.js"; let ws; let commandQueue = []; -let pendingResolve; +let current; function onMessage(e) { - if (pendingResolve) { - pendingResolve(JSON.parse(e.data)); // FIXME tady test na ACK - pendingResolve = null; + if (current) { + let lines = JSON.parse(e.data); + let last = lines.pop(); + if (last.startsWith("OK")) { + current.resolve(lines); + } else { + current.reject(last); + } + current = null; } processQueue(); } @@ -23,11 +29,9 @@ function onClose(e) { } function processQueue() { - if (pendingResolve || commandQueue.length == 0) { return; } - let {cmd, resolve} = commandQueue.shift(); - pendingResolve = resolve; - if (cmd instanceof Array) { cmd = ["command_list_begin", ...cmd, "command_list_end"].join("\n"); } - ws.send(cmd); + if (current || commandQueue.length == 0) { return; } + current = commandQueue.shift(); + ws.send(current.cmd); } export function escape(str) { @@ -35,24 +39,30 @@ export function escape(str) { } export async function command(cmd) { - return new Promise(resolve => { - commandQueue.push({cmd, resolve}); + if (cmd instanceof Array) { cmd = ["command_list_begin", ...cmd, "command_list_end"].join("\n"); } + + return new Promise((resolve, reject) => { + commandQueue.push({cmd, resolve, reject}); processQueue(); }); } -export async function getStatus() { +export async function commandAndStatus(cmd) { + let lines = await command([cmd, "status", "currentsong"]); + return parser.linesToStruct(lines); +} + +export async function status() { let lines = await command(["status", "currentsong"]); - lines.pop(); // "OK" return parser.linesToStruct(lines); } export async function init() { return new Promise((resolve, reject) => { try { - ws = new WebSocket("ws://localhost:8080?server=raspberrypi.local"); + ws = new WebSocket("ws://localhost:8080"); } catch (e) { reject(e); } - pendingResolve = resolve; + current = {resolve, reject}; ws.addEventListener("error", onError); ws.addEventListener("message", onMessage); diff --git a/app/js/status.js b/app/js/status.js index 053dd04..33afa16 100644 --- a/app/js/status.js +++ b/app/js/status.js @@ -1,18 +1,52 @@ import * as mpd from "./mpd.js"; +import * as art from "./art.js"; const DELAY = 2000; const DOM = {}; +let current = {}; + async function tick() { - let data = await mpd.getStatus(); - DOM.title.textContent = data["Title"]; + let data = await mpd.status(); + + update(data); + // console.log(data); setTimeout(tick, DELAY); } +function update(data) { + if (data["Title"] != current["Title"]) { DOM.title.textContent = data["Title"]; } + + if (data["Artist"] != current["Artist"] || data["Album"] != current["Album"]) { + DOM.art.innerHTML = ""; + art.get(data["Artist"], data["Album"], data["file"]).then(src => { + if (!src) { return; } + let image = document.createElement("img"); + image.src = src; + DOM.art.appendChild(image); + }); + } + + current = data; +} + +async function play() { + let data = await mpd.commandAndStatus("pause 0"); + update(data); +} + +async function pause() { + let data = await mpd.commandAndStatus("pause 1"); + update(data); +} + export function init() { - let node = document.querySelector("footer"); - DOM.title = node.querySelector(".title"); + let all = document.querySelectorAll("footer [class]"); + Array.from(all).forEach(node => DOM[node.className] = node); + + DOM.play.addEventListener("click", e => play()); + DOM.pause.addEventListener("click", e => pause()); tick(); -} \ No newline at end of file +}