status features
This commit is contained in:
parent
17b5040766
commit
9f14bc261a
5 changed files with 94 additions and 42 deletions
|
@ -36,12 +36,14 @@
|
||||||
<span class="artist"></span>
|
<span class="artist"></span>
|
||||||
<span class="album"></span>
|
<span class="album"></span>
|
||||||
<span class="time1"></span>/<span class="time2"></span>
|
<span class="time1"></span>/<span class="time2"></span>
|
||||||
<button class="status"></button>
|
<span class="status">
|
||||||
<button class="stop"></button>
|
<button class="play">play</button>
|
||||||
<button class="prev"></button>
|
<button class="pause">pause</button>
|
||||||
<button class="next"></button>
|
</span>
|
||||||
<button class="repeat"></button>
|
<button class="prev">prev</button>
|
||||||
<button class="random"></button>
|
<button class="next">next</button>
|
||||||
|
<button class="repeat">repeat</button>
|
||||||
|
<button class="random">random</button>
|
||||||
</footer>
|
</footer>
|
||||||
<script type="module" src="js/app.js"></script>
|
<script type="module" src="js/app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -6,11 +6,6 @@ async function init() {
|
||||||
await mpd.init();
|
await mpd.init();
|
||||||
status.init();
|
status.init();
|
||||||
window.mpd = mpd;
|
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();
|
init();
|
||||||
|
|
|
@ -10,8 +10,6 @@ async function getImageData(songUrl) {
|
||||||
while (1) {
|
while (1) {
|
||||||
let params = ["albumart", `"${mpd.escape(songUrl)}"`, offset];
|
let params = ["albumart", `"${mpd.escape(songUrl)}"`, offset];
|
||||||
let lines = await mpd.command(params.join(" "));
|
let lines = await mpd.command(params.join(" "));
|
||||||
if (lines.length == 1) { return null; }
|
|
||||||
|
|
||||||
data = data.concat(lines[2]);
|
data = data.concat(lines[2]);
|
||||||
let metadata = parser.linesToStruct(lines.slice(0, 2));
|
let metadata = parser.linesToStruct(lines.slice(0, 2));
|
||||||
if (data.length >= Number(metadata["size"])) { return data; }
|
if (data.length >= Number(metadata["size"])) { return data; }
|
||||||
|
@ -38,14 +36,27 @@ async function resize(image) {
|
||||||
return new Promise(resolve => canvas.toBlob(resolve));
|
return new Promise(resolve => canvas.toBlob(resolve));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(songUrl) {
|
export async function get(artist, album, songUrl = null) {
|
||||||
if (songUrl in cache) { return cache[songUrl]; }
|
let key = `${artist}-${album}`;
|
||||||
|
if (key in cache) { return cache[key]; }
|
||||||
|
|
||||||
|
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 data = await getImageData(songUrl);
|
||||||
let bytes = new Uint8Array(data);
|
let bytes = new Uint8Array(data);
|
||||||
let image = await bytesToImage(bytes);
|
let image = await bytesToImage(bytes);
|
||||||
let blob = await resize(image);
|
let blob = await resize(image);
|
||||||
let url = URL.createObjectURL(blob);
|
let url = URL.createObjectURL(blob);
|
||||||
cache[songUrl] = url;
|
cache[key] = url;
|
||||||
return url;
|
resolve(url);
|
||||||
|
} catch (e) {
|
||||||
|
cache[key] = null;
|
||||||
|
}
|
||||||
|
return cache[key];
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,18 @@ import * as parser from "./parser.js";
|
||||||
|
|
||||||
let ws;
|
let ws;
|
||||||
let commandQueue = [];
|
let commandQueue = [];
|
||||||
let pendingResolve;
|
let current;
|
||||||
|
|
||||||
function onMessage(e) {
|
function onMessage(e) {
|
||||||
if (pendingResolve) {
|
if (current) {
|
||||||
pendingResolve(JSON.parse(e.data)); // FIXME tady test na ACK
|
let lines = JSON.parse(e.data);
|
||||||
pendingResolve = null;
|
let last = lines.pop();
|
||||||
|
if (last.startsWith("OK")) {
|
||||||
|
current.resolve(lines);
|
||||||
|
} else {
|
||||||
|
current.reject(last);
|
||||||
|
}
|
||||||
|
current = null;
|
||||||
}
|
}
|
||||||
processQueue();
|
processQueue();
|
||||||
}
|
}
|
||||||
|
@ -23,11 +29,9 @@ function onClose(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function processQueue() {
|
function processQueue() {
|
||||||
if (pendingResolve || commandQueue.length == 0) { return; }
|
if (current || commandQueue.length == 0) { return; }
|
||||||
let {cmd, resolve} = commandQueue.shift();
|
current = commandQueue.shift();
|
||||||
pendingResolve = resolve;
|
ws.send(current.cmd);
|
||||||
if (cmd instanceof Array) { cmd = ["command_list_begin", ...cmd, "command_list_end"].join("\n"); }
|
|
||||||
ws.send(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function escape(str) {
|
export function escape(str) {
|
||||||
|
@ -35,24 +39,30 @@ export function escape(str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function command(cmd) {
|
export async function command(cmd) {
|
||||||
return new Promise(resolve => {
|
if (cmd instanceof Array) { cmd = ["command_list_begin", ...cmd, "command_list_end"].join("\n"); }
|
||||||
commandQueue.push({cmd, resolve});
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
commandQueue.push({cmd, resolve, reject});
|
||||||
processQueue();
|
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"]);
|
let lines = await command(["status", "currentsong"]);
|
||||||
lines.pop(); // "OK"
|
|
||||||
return parser.linesToStruct(lines);
|
return parser.linesToStruct(lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function init() {
|
export async function init() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
ws = new WebSocket("ws://localhost:8080?server=raspberrypi.local");
|
ws = new WebSocket("ws://localhost:8080");
|
||||||
} catch (e) { reject(e); }
|
} catch (e) { reject(e); }
|
||||||
pendingResolve = resolve;
|
current = {resolve, reject};
|
||||||
|
|
||||||
ws.addEventListener("error", onError);
|
ws.addEventListener("error", onError);
|
||||||
ws.addEventListener("message", onMessage);
|
ws.addEventListener("message", onMessage);
|
||||||
|
|
|
@ -1,18 +1,52 @@
|
||||||
import * as mpd from "./mpd.js";
|
import * as mpd from "./mpd.js";
|
||||||
|
import * as art from "./art.js";
|
||||||
|
|
||||||
const DELAY = 2000;
|
const DELAY = 2000;
|
||||||
const DOM = {};
|
const DOM = {};
|
||||||
|
|
||||||
|
let current = {};
|
||||||
|
|
||||||
async function tick() {
|
async function tick() {
|
||||||
let data = await mpd.getStatus();
|
let data = await mpd.status();
|
||||||
DOM.title.textContent = data["Title"];
|
|
||||||
|
update(data);
|
||||||
|
|
||||||
// console.log(data);
|
// console.log(data);
|
||||||
setTimeout(tick, DELAY);
|
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() {
|
export function init() {
|
||||||
let node = document.querySelector("footer");
|
let all = document.querySelectorAll("footer [class]");
|
||||||
DOM.title = node.querySelector(".title");
|
Array.from(all).forEach(node => DOM[node.className] = node);
|
||||||
|
|
||||||
|
DOM.play.addEventListener("click", e => play());
|
||||||
|
DOM.pause.addEventListener("click", e => pause());
|
||||||
|
|
||||||
tick();
|
tick();
|
||||||
}
|
}
|
Loading…
Reference in a new issue