library+fs
This commit is contained in:
parent
f0d4f1c3b0
commit
8dc753b815
21 changed files with 247 additions and 74 deletions
|
@ -83,4 +83,6 @@ select {
|
||||||
@import "elements/range.less";
|
@import "elements/range.less";
|
||||||
@import "elements/playlist.less";
|
@import "elements/playlist.less";
|
||||||
@import "elements/library.less";
|
@import "elements/library.less";
|
||||||
@import "elements/artist.less";
|
@import "elements/tag.less";
|
||||||
|
@import "elements/back.less";
|
||||||
|
@import "elements/path.less";
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
cyp-artist {
|
|
||||||
.item;
|
|
||||||
}
|
|
3
app/css/elements/back.less
Normal file
3
app/css/elements/back.less
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
cyp-back {
|
||||||
|
.item;
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
cyp-library {
|
cyp-library {
|
||||||
|
cyp-song .subtitle { display: none; }
|
||||||
}
|
}
|
||||||
|
|
3
app/css/elements/path.less
Normal file
3
app/css/elements/path.less
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
cyp-path {
|
||||||
|
.item;
|
||||||
|
}
|
3
app/css/elements/tag.less
Normal file
3
app/css/elements/tag.less
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
cyp-tag {
|
||||||
|
.item;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
1
app/icons/keyboard-backspace.svg
Normal file
1
app/icons/keyboard-backspace.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M21,11H6.83L10.41,7.41L9,6L3,12L9,18L10.41,16.58L6.83,13H21V11Z" /></svg>
|
After Width: | Height: | Size: 358 B |
|
@ -105,5 +105,8 @@
|
||||||
<script type="module" src="js/elements/yt.js"></script>
|
<script type="module" src="js/elements/yt.js"></script>
|
||||||
<script type="module" src="js/elements/song.js"></script>
|
<script type="module" src="js/elements/song.js"></script>
|
||||||
<script type="module" src="js/elements/library.js"></script>
|
<script type="module" src="js/elements/library.js"></script>
|
||||||
|
<script type="module" src="js/elements/tag.js"></script>
|
||||||
|
<script type="module" src="js/elements/back.js"></script>
|
||||||
|
<script type="module" src="js/elements/path.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import * as html from "../html.js";
|
|
||||||
import Item from "../item.js";
|
|
||||||
|
|
||||||
|
|
||||||
export default class Artist extends Item {
|
|
||||||
constructor(name) {
|
|
||||||
super();
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
html.icon("artist", this);
|
|
||||||
this._buildTitle(this.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("cyp-artist", Artist);
|
|
16
app/js/elements/back.js
Normal file
16
app/js/elements/back.js
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import Item from "../item.js";
|
||||||
|
import * as html from "../html.js";
|
||||||
|
|
||||||
|
|
||||||
|
export default class Back extends Item {
|
||||||
|
constructor(title) {
|
||||||
|
super();
|
||||||
|
this._title = title;
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
this.appendChild(html.icon("keyboard-backspace"));
|
||||||
|
this._buildTitle(this._title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("cyp-back", Back);
|
|
@ -1,11 +1,32 @@
|
||||||
import * as html from "../html.js";
|
import * as html from "../html.js";
|
||||||
import Component from "../component.js";
|
import Component from "../component.js";
|
||||||
import Artist from "./artist.js";
|
import Tag from "./tag.js";
|
||||||
|
import Path from "./path.js";
|
||||||
|
import Back from "./back.js";
|
||||||
|
import Song from "./song.js";
|
||||||
|
import { escape, serializeFilter } from "../mpd.js";
|
||||||
|
|
||||||
|
|
||||||
|
const SORT = "-Track";
|
||||||
|
|
||||||
|
function createEnqueueCommand(node) {
|
||||||
|
if (node instanceof Song) {
|
||||||
|
return `add "${escape(node.data["file"])}"`;
|
||||||
|
} else if (node instanceof Tag) {
|
||||||
|
return [
|
||||||
|
"findadd",
|
||||||
|
serializeFilter(node.createChildFilter()),
|
||||||
|
`sort ${SORT}`
|
||||||
|
].join(" ");
|
||||||
|
} else {
|
||||||
|
throw new Exception(`Cannot create enqueue command for "${node.nodeName}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Library extends Component {
|
class Library extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({selection:"multi"});
|
super({selection:"multi"});
|
||||||
|
this._initCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAppLoad() {
|
_onAppLoad() {
|
||||||
|
@ -26,7 +47,7 @@ class Library extends Component {
|
||||||
.addEventListener("click", _ => this._listTags("AlbumArtist"));
|
.addEventListener("click", _ => this._listTags("AlbumArtist"));
|
||||||
|
|
||||||
html.button({icon:"folder"}, "Files and directories", this)
|
html.button({icon:"folder"}, "Files and directories", this)
|
||||||
.addEventListener("click", _ => this._listFS(""));
|
.addEventListener("click", _ => this._listPath(""));
|
||||||
|
|
||||||
html.button({icon:"magnify"}, "Search", this)
|
html.button({icon:"magnify"}, "Search", this)
|
||||||
.addEventListener("click", _ => this._showSearch());
|
.addEventListener("click", _ => this._showSearch());
|
||||||
|
@ -34,29 +55,115 @@ class Library extends Component {
|
||||||
|
|
||||||
async _listTags(tag, filter = {}) {
|
async _listTags(tag, filter = {}) {
|
||||||
const values = await this._mpd.listTags(tag, filter);
|
const values = await this._mpd.listTags(tag, filter);
|
||||||
|
|
||||||
html.clear(this);
|
html.clear(this);
|
||||||
|
|
||||||
values.forEach(value => this._buildTagValue(tag, value));
|
if ("AlbumArtist" in filter) { this._buildBack(filter); }
|
||||||
|
values.forEach(value => this._buildTag(tag, value, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _listFS(path) {
|
async _listPath(path) {
|
||||||
|
let paths = await this._mpd.listPath(path);
|
||||||
|
html.clear(this);
|
||||||
|
|
||||||
|
path && this._buildBack(path);
|
||||||
|
paths["directory"].forEach(path => this._buildPath(path));
|
||||||
|
paths["file"].forEach(path => this._buildPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
async _listSongs(filter) {
|
||||||
|
const songs = await this._mpd.listSongs(filter);
|
||||||
|
html.clear(this);
|
||||||
|
this._buildBack(filter);
|
||||||
|
songs.forEach(song => this.appendChild(new Song(song)));
|
||||||
}
|
}
|
||||||
|
|
||||||
_showSearch() {
|
_showSearch() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_buildTagValue(tag, value) {
|
_buildTag(tag, value, filter) {
|
||||||
let node;
|
let node;
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case "AlbumArtist":
|
case "AlbumArtist":
|
||||||
node = new Artist(value);
|
node = new Tag(tag, value, filter);
|
||||||
node.onClick = () => this._listTags("Album", {[tag]:value});
|
this.appendChild(node);
|
||||||
|
node.onClick = () => this._listTags("Album", node.createChildFilter());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Album":
|
||||||
|
node = new Tag(tag, value, filter);
|
||||||
|
this.appendChild(node);
|
||||||
|
node.addButton("chevron-double-right", _ => this._listSongs(node.createChildFilter()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildBack(filterOrPath) {
|
||||||
|
if (typeof(filterOrPath) == "string") {
|
||||||
|
const path = filterOrPath.split("/").slice(0, -1).join("");
|
||||||
|
const node = new Back("..");
|
||||||
this.appendChild(node);
|
this.appendChild(node);
|
||||||
|
node.onClick = () => {
|
||||||
|
this.selection.clear();
|
||||||
|
this._listPath(path);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filter = Object.assign({}, filterOrPath)
|
||||||
|
let tag, title;
|
||||||
|
|
||||||
|
if ("Album" in filter) {
|
||||||
|
tag = "Album";
|
||||||
|
title = filter["AlbumArtist"];
|
||||||
|
} else if ("AlbumArtist" in filter) {
|
||||||
|
tag = "AlbumArtist";
|
||||||
|
title = "Artists";
|
||||||
|
}
|
||||||
|
|
||||||
|
delete filter[tag];
|
||||||
|
const node = new Back(title);
|
||||||
|
this.appendChild(node);
|
||||||
|
node.onClick = () => {
|
||||||
|
this.selection.clear();
|
||||||
|
this._listTags(tag, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_buildPath(data) {
|
||||||
|
let node = new Path(data);
|
||||||
|
this.appendChild(node);
|
||||||
|
|
||||||
|
if ("directory" in data) {
|
||||||
|
const path = data["directory"];
|
||||||
|
node.addButton("chevron-double-right", _ => this._listPath(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_initCommands() {
|
||||||
|
const sel = this.selection;
|
||||||
|
|
||||||
|
sel.addCommandAll();
|
||||||
|
|
||||||
|
sel.addCommand(async items => {
|
||||||
|
const commands = [
|
||||||
|
"clear",
|
||||||
|
...items.map(createEnqueueCommand),
|
||||||
|
"play"
|
||||||
|
];
|
||||||
|
await this._mpd.command(commands);
|
||||||
|
this.selection.clear();
|
||||||
|
this._app.dispatchEvent(new CustomEvent("queue-change")); // fixme notification?
|
||||||
|
}, {label:"Play", icon:"play"});
|
||||||
|
|
||||||
|
sel.addCommand(async items => {
|
||||||
|
const commands = items.map(createEnqueueCommand);
|
||||||
|
await this._mpd.command(commands);
|
||||||
|
this.selection.clear();
|
||||||
|
this._app.dispatchEvent(new CustomEvent("queue-change")); // fixme notification?
|
||||||
|
}, {label:"Enqueue", icon:"plus"});
|
||||||
|
|
||||||
|
sel.addCommandCancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
app/js/elements/path.js
Normal file
28
app/js/elements/path.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import Item from "../item.js";
|
||||||
|
import * as html from "../html.js";
|
||||||
|
|
||||||
|
|
||||||
|
function baseName(path) {
|
||||||
|
return path.split("/").pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Path extends Item {
|
||||||
|
constructor(data) {
|
||||||
|
super();
|
||||||
|
this.data = data;
|
||||||
|
// FIXME spis ._data a .url
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
let path;
|
||||||
|
if ("directory" in this.data) {
|
||||||
|
this.appendChild(html.icon("folder"));
|
||||||
|
path = this.data["directory"];
|
||||||
|
} else {
|
||||||
|
this.appendChild(html.icon("music"));
|
||||||
|
path = this.data["file"];
|
||||||
|
}
|
||||||
|
this._buildTitle(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("cyp-path", Path);
|
|
@ -1,7 +1,7 @@
|
||||||
import * as html from "../html.js";
|
import * as html from "../html.js";
|
||||||
import Component from "../component.js";
|
import Component from "../component.js";
|
||||||
import Playlist from "./playlist.js";
|
import Playlist from "./playlist.js";
|
||||||
|
import { escape } from "../mpd.js";
|
||||||
|
|
||||||
class Playlists extends Component {
|
class Playlists extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -31,7 +31,7 @@ class Playlists extends Component {
|
||||||
|
|
||||||
sel.addCommand(async item => {
|
sel.addCommand(async item => {
|
||||||
const name = item.name;
|
const name = item.name;
|
||||||
const commands = ["clear", `load "${this._mpd.escape(name)}"`, "play"];
|
const commands = ["clear", `load "${escape(name)}"`, "play"];
|
||||||
await this._mpd.command(commands);
|
await this._mpd.command(commands);
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
this._app.dispatchEvent(new CustomEvent("queue-change")); // fixme notification?
|
this._app.dispatchEvent(new CustomEvent("queue-change")); // fixme notification?
|
||||||
|
@ -39,7 +39,7 @@ class Playlists extends Component {
|
||||||
|
|
||||||
sel.addCommand(async item => {
|
sel.addCommand(async item => {
|
||||||
const name = item.name;
|
const name = item.name;
|
||||||
await this._mpd.command(`load "${this._mpd.escape(name)}"`);
|
await this._mpd.command(`load "${escape(name)}"`);
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
this._app.dispatchEvent(new CustomEvent("queue-change")); // fixme notification?
|
this._app.dispatchEvent(new CustomEvent("queue-change")); // fixme notification?
|
||||||
}, {label:"Enqueue", icon:"plus"});
|
}, {label:"Enqueue", icon:"plus"});
|
||||||
|
@ -48,7 +48,7 @@ class Playlists extends Component {
|
||||||
const name = item.name;
|
const name = item.name;
|
||||||
if (!confirm(`Really delete playlist '${name}'?`)) { return; }
|
if (!confirm(`Really delete playlist '${name}'?`)) { return; }
|
||||||
|
|
||||||
await this._mpd.command(`rm "${this._mpd.escape(name)}"`);
|
await this._mpd.command(`rm "${escape(name)}"`);
|
||||||
this._sync();
|
this._sync();
|
||||||
}, {label:"Delete", icon:"delete"});
|
}, {label:"Delete", icon:"delete"});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import * as html from "../html.js";
|
import * as html from "../html.js";
|
||||||
import Component from "../component.js";
|
import Component from "../component.js";
|
||||||
import Song from "./song.js";
|
import Song from "./song.js";
|
||||||
|
import { escape } from "../mpd.js";
|
||||||
|
|
||||||
|
|
||||||
function generateMoveCommands(items, diff, all) {
|
function generateMoveCommands(items, diff, all) {
|
||||||
|
@ -69,8 +70,7 @@ class Queue extends Component {
|
||||||
const node = new Song(song);
|
const node = new Song(song);
|
||||||
this.appendChild(node);
|
this.appendChild(node);
|
||||||
|
|
||||||
html.button({icon:"play"}, "", node).addEventListener("click", async e => {
|
node.addButton("play", async _ => {
|
||||||
e.stopPropagation(); // do not select
|
|
||||||
await this._mpd.command(`playid ${song["Id"]}`);
|
await this._mpd.command(`playid ${song["Id"]}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -99,9 +99,9 @@ class Queue extends Component {
|
||||||
let name = prompt("Save selected songs as a playlist?", "name");
|
let name = prompt("Save selected songs as a playlist?", "name");
|
||||||
if (name === null) { return; }
|
if (name === null) { return; }
|
||||||
|
|
||||||
name = this._mpd.escape(name);
|
name = escape(name);
|
||||||
const commands = items.map(item => {
|
const commands = items.map(item => {
|
||||||
return `playlistadd "${name}" "${this._mpd.escape(item.data["file"])}"`;
|
return `playlistadd "${name}" "${escape(item.data["file"])}"`;
|
||||||
});
|
});
|
||||||
|
|
||||||
await this._mpd.command(commands); // FIXME notify?
|
await this._mpd.command(commands); // FIXME notify?
|
||||||
|
|
29
app/js/elements/tag.js
Normal file
29
app/js/elements/tag.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import * as html from "../html.js";
|
||||||
|
import Item from "../item.js";
|
||||||
|
|
||||||
|
const ICONS = {
|
||||||
|
"AlbumArtist": "artist",
|
||||||
|
"Album": "album"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default class Tag extends Item {
|
||||||
|
constructor(type, value, filter) {
|
||||||
|
super();
|
||||||
|
this._type = type;
|
||||||
|
this._value = value;
|
||||||
|
this._filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
const icon = ICONS[this._type];
|
||||||
|
html.icon(icon, this);
|
||||||
|
this._buildTitle(this._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
createChildFilter() {
|
||||||
|
return Object.assign({[this._type]:this._value}, this._filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("cyp-tag", Tag);
|
|
@ -1,6 +1,6 @@
|
||||||
import * as html from "../html.js";
|
import * as html from "../html.js";
|
||||||
import * as conf from "../conf.js";
|
import * as conf from "../conf.js";
|
||||||
|
import { escape } from "../mpd.js";
|
||||||
import Component from "../component.js";
|
import Component from "../component.js";
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class YT extends Component {
|
||||||
this.classList.remove("pending");
|
this.classList.remove("pending");
|
||||||
|
|
||||||
if (response.status == 200) {
|
if (response.status == 200) {
|
||||||
this._mpd.command(`update ${this._mpd.escape(conf.ytPath)}`);
|
this._mpd.command(`update ${escape(conf.ytPath)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ ICONS["artist"] = `<svg viewBox="0 0 24 24">
|
||||||
ICONS["volume-off"] = `<svg viewBox="0 0 24 24">
|
ICONS["volume-off"] = `<svg viewBox="0 0 24 24">
|
||||||
<path d="M12,4L9.91,6.09L12,8.18M4.27,3L3,4.27L7.73,9H3V15H7L12,20V13.27L16.25,17.53C15.58,18.04 14.83,18.46 14,18.7V20.77C15.38,20.45 16.63,19.82 17.68,18.96L19.73,21L21,19.73L12,10.73M19,12C19,12.94 18.8,13.82 18.46,14.64L19.97,16.15C20.62,14.91 21,13.5 21,12C21,7.72 18,4.14 14,3.23V5.29C16.89,6.15 19,8.83 19,12M16.5,12C16.5,10.23 15.5,8.71 14,7.97V10.18L16.45,12.63C16.5,12.43 16.5,12.21 16.5,12Z"/>
|
<path d="M12,4L9.91,6.09L12,8.18M4.27,3L3,4.27L7.73,9H3V15H7L12,20V13.27L16.25,17.53C15.58,18.04 14.83,18.46 14,18.7V20.77C15.38,20.45 16.63,19.82 17.68,18.96L19.73,21L21,19.73L12,10.73M19,12C19,12.94 18.8,13.82 18.46,14.64L19.97,16.15C20.62,14.91 21,13.5 21,12C21,7.72 18,4.14 14,3.23V5.29C16.89,6.15 19,8.83 19,12M16.5,12C16.5,10.23 15.5,8.71 14,7.97V10.18L16.45,12.63C16.5,12.43 16.5,12.21 16.5,12Z"/>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
|
ICONS["keyboard-backspace"] = `<svg viewBox="0 0 24 24">
|
||||||
|
<path d="M21,11H6.83L10.41,7.41L9,6L3,12L9,18L10.41,16.58L6.83,13H21V11Z"/>
|
||||||
|
</svg>`;
|
||||||
ICONS["cancel"] = `<svg viewBox="0 0 24 24">
|
ICONS["cancel"] = `<svg viewBox="0 0 24 24">
|
||||||
<path d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12C4,13.85 4.63,15.55 5.68,16.91L16.91,5.68C15.55,4.63 13.85,4 12,4M12,20A8,8 0 0,0 20,12C20,10.15 19.37,8.45 18.32,7.09L7.09,18.32C8.45,19.37 10.15,20 12,20Z"/>
|
<path d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12C4,13.85 4.63,15.55 5.68,16.91L16.91,5.68C15.55,4.63 13.85,4 12,4M12,20A8,8 0 0,0 20,12C20,10.15 19.37,8.45 18.32,7.09L7.09,18.32C8.45,19.37 10.15,20 12,20Z"/>
|
||||||
</svg>`;
|
</svg>`;
|
||||||
|
|
|
@ -6,6 +6,13 @@ export default class Item extends HTMLElement {
|
||||||
this.addEventListener("click", _ => this.onClick());
|
this.addEventListener("click", _ => this.onClick());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addButton(icon, cb) {
|
||||||
|
html.button({icon}, "", this).addEventListener("click", e => {
|
||||||
|
e.stopPropagation(); // do not select
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onClick() { this.parentNode.selection.toggle(this); }
|
onClick() { this.parentNode.selection.toggle(this); }
|
||||||
|
|
||||||
_buildTitle(title) {
|
_buildTitle(title) {
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
import * as mpd from "./mpd.js";
|
|
||||||
|
|
||||||
export const escape = mpd.escape;
|
|
||||||
|
|
||||||
export function command(cmd) {
|
export function command(cmd) {
|
||||||
console.warn(`mpd-mock does not know "${cmd}"`);
|
console.warn(`mpd-mock does not know "${cmd}"`);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +30,7 @@ export function listQueue() {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listPlaylists() {
|
export function listPlaylists() {
|
||||||
return [
|
return [
|
||||||
"Playlist 1",
|
"Playlist 1",
|
||||||
"Playlist 2",
|
"Playlist 2",
|
||||||
|
@ -42,34 +38,33 @@ export async function listPlaylists() {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function enqueueByFilter(filter, sort = null) {
|
export function listPath(path) {
|
||||||
let tokens = ["findadd"];
|
return {
|
||||||
tokens.push(serializeFilter(filter));
|
"directory": [
|
||||||
// sort && tokens.push("sort", sort); FIXME not implemented in MPD
|
{"directory": "Dir 1"},
|
||||||
return command(tokens.join(" "));
|
{"directory": "Dir 2"},
|
||||||
|
{"directory": "Dir 3"}
|
||||||
|
],
|
||||||
|
"file": [
|
||||||
|
{"file": "File 1"},
|
||||||
|
{"file": "File 2"},
|
||||||
|
{"file": "File 3"}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listPath(path) {
|
export function listTags(tag, filter = null) {
|
||||||
let lines = await command(`lsinfo "${escape(path)}"`);
|
|
||||||
return parser.pathContents(lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listTags(tag, filter = null) {
|
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case "AlbumArtist": return ["Artist 1", "Artist 2", "Artist 3"];
|
case "AlbumArtist": return ["Artist 1", "Artist 2", "Artist 3"];
|
||||||
case "Album": return ["Album 1", "Album 2", "Album 3"];
|
case "Album": return ["Album 1", "Album 2", "Album 3"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function listSongs(filter, window = null) {
|
export function listSongs(filter, window = null) {
|
||||||
let tokens = ["find"];
|
return listQueue();
|
||||||
tokens.push(serializeFilter(filter));
|
|
||||||
if (window) { tokens.push("window", window.join(":")); }
|
|
||||||
let lines = await command(tokens.join(" "));
|
|
||||||
return parser.songList(lines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function albumArt(songUrl) {
|
export function albumArt(songUrl) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ function processQueue() {
|
||||||
ws.send(current.cmd);
|
ws.send(current.cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
function serializeFilter(filter) {
|
export function serializeFilter(filter) {
|
||||||
let tokens = ["("];
|
let tokens = ["("];
|
||||||
Object.entries(filter).forEach(([key, value], index) => {
|
Object.entries(filter).forEach(([key, value], index) => {
|
||||||
index && tokens.push(" AND ");
|
index && tokens.push(" AND ");
|
||||||
|
@ -90,13 +90,6 @@ export async function listPlaylists() {
|
||||||
return (list instanceof Array ? list : [list]);
|
return (list instanceof Array ? list : [list]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function enqueueByFilter(filter, sort = null) {
|
|
||||||
let tokens = ["findadd"];
|
|
||||||
tokens.push(serializeFilter(filter));
|
|
||||||
// sort && tokens.push("sort", sort); FIXME not implemented in MPD
|
|
||||||
return command(tokens.join(" "));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function listPath(path) {
|
export async function listPath(path) {
|
||||||
let lines = await command(`lsinfo "${escape(path)}"`);
|
let lines = await command(`lsinfo "${escape(path)}"`);
|
||||||
return parser.pathContents(lines);
|
return parser.pathContents(lines);
|
||||||
|
|
Loading…
Reference in a new issue