2020-03-10 05:24:31 +08:00
|
|
|
import * as html from "../html.js";
|
|
|
|
import Component from "../component.js";
|
|
|
|
import Song from "./song.js";
|
2019-03-22 22:35:04 +08:00
|
|
|
|
2020-03-10 17:07:30 +08:00
|
|
|
|
2020-03-10 21:08:18 +08:00
|
|
|
function generateMoveCommands(items, diff, all) {
|
|
|
|
const COMPARE = (a, b) => all.indexOf(a) - all.indexOf(b);
|
|
|
|
|
|
|
|
return items.sort(COMPARE)
|
|
|
|
.map(item => {
|
|
|
|
let index = all.indexOf(item) + diff;
|
|
|
|
if (index < 0 || index >= all.length) { return null; } // this does not move
|
|
|
|
return `moveid ${item.data["Id"]} ${index}`;
|
|
|
|
})
|
|
|
|
.filter(command => command);
|
|
|
|
}
|
|
|
|
|
2020-03-09 05:11:46 +08:00
|
|
|
class Queue extends Component {
|
|
|
|
constructor() {
|
2020-03-10 17:07:30 +08:00
|
|
|
super({selection:"multi"});
|
2020-03-09 05:11:46 +08:00
|
|
|
this._currentId = null;
|
2020-03-10 05:24:31 +08:00
|
|
|
this._initCommands();
|
2020-03-09 05:11:46 +08:00
|
|
|
}
|
2019-03-22 22:35:04 +08:00
|
|
|
|
2020-03-09 05:11:46 +08:00
|
|
|
handleEvent(e) {
|
|
|
|
switch (e.type) {
|
|
|
|
case "song-change":
|
|
|
|
this._currentId = e.detail["Id"];
|
|
|
|
this._updateCurrent();
|
|
|
|
break;
|
2019-03-22 22:35:04 +08:00
|
|
|
|
2020-03-09 05:11:46 +08:00
|
|
|
case "queue-change":
|
|
|
|
this._sync();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-03-26 17:09:26 +08:00
|
|
|
|
2020-03-09 16:26:10 +08:00
|
|
|
_onAppLoad() {
|
|
|
|
this._app.addEventListener("song-change", this);
|
|
|
|
this._app.addEventListener("queue-change", this);
|
|
|
|
this._sync();
|
|
|
|
}
|
|
|
|
|
2020-03-09 05:11:46 +08:00
|
|
|
_onComponentChange(c, isThis) {
|
|
|
|
this.hidden = !isThis;
|
2019-03-26 17:09:26 +08:00
|
|
|
|
2020-03-09 05:11:46 +08:00
|
|
|
isThis && this._sync();
|
|
|
|
}
|
2019-03-22 22:35:04 +08:00
|
|
|
|
2020-03-09 05:11:46 +08:00
|
|
|
async _sync() {
|
2020-03-09 16:26:10 +08:00
|
|
|
let songs = await this._mpd.listQueue();
|
2020-03-09 05:11:46 +08:00
|
|
|
this._buildSongs(songs);
|
|
|
|
|
|
|
|
// FIXME pubsub?
|
|
|
|
document.querySelector("#queue-length").textContent = `(${songs.length})`;
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateCurrent() {
|
2020-03-09 21:26:39 +08:00
|
|
|
Array.from(this.children).forEach(/** @param {HTMLElement} node */ node => {
|
2020-03-09 05:11:46 +08:00
|
|
|
node.classList.toggle("current", node.dataset.songId == this._currentId);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
_buildSongs(songs) {
|
2020-03-09 21:26:39 +08:00
|
|
|
html.clear(this);
|
2020-03-10 17:07:30 +08:00
|
|
|
this.selection.clear();
|
2020-03-09 05:11:46 +08:00
|
|
|
|
2020-03-11 05:11:36 +08:00
|
|
|
songs.forEach(song => {
|
|
|
|
const node = new Song(song);
|
|
|
|
this.appendChild(node);
|
|
|
|
|
|
|
|
html.button({icon:"play"}, "", node).addEventListener("click", async e => {
|
|
|
|
e.stopPropagation(); // do not select
|
|
|
|
await this._mpd.command(`playid ${song["Id"]}`);
|
|
|
|
});
|
|
|
|
});
|
2020-03-09 05:11:46 +08:00
|
|
|
|
|
|
|
this._updateCurrent();
|
|
|
|
}
|
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
_initCommands() {
|
|
|
|
const sel = this.selection;
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
sel.addCommandAll();
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 21:08:18 +08:00
|
|
|
sel.addCommand(async items => {
|
|
|
|
const commands = generateMoveCommands(items, -1, Array.from(this.children));
|
|
|
|
await this._mpd.command(commands);
|
|
|
|
this._sync();
|
|
|
|
}, {label:"Up", icon:"arrow-up-bold"});
|
|
|
|
|
|
|
|
sel.addCommand(async items => {
|
|
|
|
const commands = generateMoveCommands(items, +1, Array.from(this.children));
|
|
|
|
await this._mpd.command(commands.reverse()); // move last first
|
|
|
|
this._sync();
|
|
|
|
}, {label:"Down", icon:"arrow-down-bold"});
|
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
sel.addCommand(async items => {
|
|
|
|
let name = prompt("Save selected songs as a playlist?", "name");
|
|
|
|
if (name === null) { return; }
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
name = this._mpd.escape(name);
|
|
|
|
const commands = items.map(item => {
|
|
|
|
return `playlistadd "${name}" "${this._mpd.escape(item.data["file"])}"`;
|
|
|
|
});
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 21:08:18 +08:00
|
|
|
await this._mpd.command(commands); // FIXME notify?
|
2020-03-10 05:24:31 +08:00
|
|
|
}, {label:"Save", icon:"content-save"});
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
sel.addCommand(async items => {
|
|
|
|
if (!confirm(`Remove these ${items.length} songs from the queue?`)) { return; }
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
const commands = items.map(item => `deleteid ${item.data["Id"]}`);
|
|
|
|
await this._mpd.command(commands);
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
this._sync();
|
|
|
|
}, {label:"Remove", icon:"delete"});
|
2020-03-09 21:26:39 +08:00
|
|
|
|
2020-03-10 17:07:30 +08:00
|
|
|
sel.addCommandCancel();
|
2020-03-09 21:26:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-10 05:24:31 +08:00
|
|
|
customElements.define("cyp-queue", Queue);
|