cyp/app/js/elements/player.js

149 lines
4.1 KiB
JavaScript
Raw Normal View History

2020-03-10 05:24:31 +08:00
import * as art from "../art.js";
import * as html from "../html.js";
import * as format from "../format.js";
import Component from "../component.js";
2019-03-21 17:32:58 +08:00
2020-03-14 06:01:16 +08:00
2019-04-12 19:48:00 +08:00
const DELAY = 1000;
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
class Player extends Component {
constructor() {
2020-03-10 17:42:13 +08:00
super();
2020-03-09 05:11:46 +08:00
this._current = {};
this._toggledVolume = 0;
this._idleTimeout = null;
this._dom = this._initDOM();
2020-03-09 16:26:10 +08:00
}
2020-03-09 21:26:39 +08:00
async update() {
this._clearIdle();
const data = await this._mpd.status();
this._sync(data);
this._idle();
}
2020-03-09 16:26:10 +08:00
_onAppLoad() {
2020-03-09 21:26:39 +08:00
this.update();
2020-03-09 05:11:46 +08:00
}
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
_initDOM() {
const DOM = {};
const all = this.querySelectorAll("[class]");
Array.from(all).forEach(node => DOM[node.className] = node);
2019-04-12 19:34:28 +08:00
2020-03-09 05:11:46 +08:00
DOM.progress = DOM.timeline.querySelector("x-range");
DOM.volume = DOM.volume.querySelector("x-range");
2019-04-12 19:34:28 +08:00
2020-03-09 05:11:46 +08:00
DOM.play.addEventListener("click", _ => this._command("play"));
DOM.pause.addEventListener("click", _ => this._command("pause 1"));
DOM.prev.addEventListener("click", _ => this._command("previous"));
DOM.next.addEventListener("click", _ => this._command("next"));
2019-04-12 19:34:28 +08:00
2020-03-09 05:11:46 +08:00
DOM.random.addEventListener("click", _ => this._command(`random ${this._current["random"] == "1" ? "0" : "1"}`));
DOM.repeat.addEventListener("click", _ => this._command(`repeat ${this._current["repeat"] == "1" ? "0" : "1"}`));
2019-04-12 19:34:28 +08:00
2020-03-09 05:11:46 +08:00
DOM.volume.addEventListener("input", e => this._command(`setvol ${e.target.valueAsNumber}`));
DOM.progress.addEventListener("input", e => this._command(`seekcur ${e.target.valueAsNumber}`));
2019-04-09 22:08:09 +08:00
2020-03-09 05:11:46 +08:00
DOM.mute.addEventListener("click", _ => this._command(`setvol ${this._toggledVolume}`));
2019-03-30 19:57:01 +08:00
2020-03-09 05:11:46 +08:00
return DOM;
2019-03-21 17:32:58 +08:00
}
2020-03-09 05:11:46 +08:00
async _command(cmd) {
this._clearIdle();
2020-03-09 16:26:10 +08:00
const data = await this._mpd.commandAndStatus(cmd);
2020-03-09 05:11:46 +08:00
this._sync(data);
this._idle();
2019-03-21 17:32:58 +08:00
}
2020-03-09 05:11:46 +08:00
_idle() {
2020-03-09 21:26:39 +08:00
this._idleTimeout = setTimeout(() => this.update(), DELAY);
2020-03-09 05:11:46 +08:00
}
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
_clearIdle() {
this._idleTimeout && clearTimeout(this._idleTimeout);
this._idleTimeout = null;
}
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
_sync(data) {
const DOM = this._dom;
if ("volume" in data) {
data["volume"] = Number(data["volume"]);
2019-03-22 22:35:04 +08:00
2020-03-09 05:11:46 +08:00
DOM.mute.disabled = false;
DOM.volume.disabled = false;
DOM.volume.value = data["volume"];
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
if (data["volume"] == 0 && this._current["volume"] > 0) { // muted
this._toggledVolume = this._current["volume"];
html.clear(DOM.mute);
DOM.mute.appendChild(html.icon("volume-off"));
}
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
if (data["volume"] > 0 && this._current["volume"] == 0) { // restored
this._toggledVolume = 0;
html.clear(DOM.mute);
DOM.mute.appendChild(html.icon("volume-high"));
}
2019-04-11 19:34:24 +08:00
2020-03-09 05:11:46 +08:00
} else {
DOM.mute.disabled = true;
DOM.volume.disabled = true;
DOM.volume.value = 50;
}
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
// changed time
let elapsed = Number(data["elapsed"] || 0);
DOM.progress.value = elapsed;
DOM.elapsed.textContent = format.time(elapsed);
if (data["file"] != this._current["file"]) { // changed song
if (data["file"]) { // playing at all?
let duration = Number(data["duration"]);
DOM.duration.textContent = format.time(duration);
DOM.progress.max = duration;
DOM.progress.disabled = false;
2020-03-14 06:01:16 +08:00
DOM.title.textContent = data["Title"] || format.fileName(data["file"]);
2020-03-09 05:11:46 +08:00
DOM.subtitle.textContent = format.subtitle(data, {duration:false});
} else {
DOM.title.textContent = "";
DOM.subtitle.textContent = "";
DOM.progress.value = 0;
DOM.progress.disabled = true;
}
2019-04-10 20:37:02 +08:00
2020-03-09 05:11:46 +08:00
this._dispatchSongChange(data);
}
2019-04-12 19:34:28 +08:00
2020-03-09 05:11:46 +08:00
let artistNew = data["AlbumArtist"] || data["Artist"];
let artistOld = this._current["AlbumArtist"] || this._current["Artist"];
2020-03-14 06:01:16 +08:00
2020-03-09 05:11:46 +08:00
if (artistNew != artistOld || data["Album"] != this._current["Album"]) { // changed album (art)
html.clear(DOM.art);
2020-03-13 23:52:24 +08:00
art.get(this._mpd, artistNew, data["Album"], data["file"]).then(src => {
2020-03-09 05:11:46 +08:00
if (src) {
html.node("img", {src}, "", DOM.art);
} else {
html.icon("music", DOM.art);
}
});
}
2019-03-21 17:32:58 +08:00
2020-03-09 05:11:46 +08:00
let flags = [];
if (data["random"] == "1") { flags.push("random"); }
if (data["repeat"] == "1") { flags.push("repeat"); }
this.dataset.flags = flags.join(" ");
this.dataset.state = data["state"];
2020-03-09 01:06:54 +08:00
2020-03-09 05:11:46 +08:00
this._current = data;
}
2020-03-09 01:06:54 +08:00
2020-03-09 16:26:10 +08:00
_dispatchSongChange(detail) {
2020-03-09 05:11:46 +08:00
const e = new CustomEvent("song-change", {detail});
2020-03-09 16:26:10 +08:00
this._app.dispatchEvent(e);
2020-03-09 05:11:46 +08:00
}
2020-03-09 01:06:54 +08:00
}
2020-03-09 05:11:46 +08:00
customElements.define("cyp-player", Player);