library refactor

This commit is contained in:
Ondrej Zara 2019-03-30 12:57:01 +01:00
parent 9d8a81ebc8
commit 181c988649
9 changed files with 118 additions and 74 deletions

View file

@ -12,7 +12,7 @@ body {
line-height: 1; line-height: 1;
background-color: var(--bg); background-color: var(--bg);
color: var(--fg); color: var(--fg);
text-shadow: 0 1px 1px #000; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
max-width: 800px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
overflow: hidden; overflow: hidden;
@ -137,14 +137,14 @@ nav ul li.active {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.component .grid li { .component li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px; padding: 0 4px;
white-space: nowrap; white-space: nowrap;
} }
.component .grid h2 { .component h2 {
flex-grow: 1; flex-grow: 1;
font-size: 100%; font-size: 100%;
font-weight: normal; font-weight: normal;
@ -152,15 +152,15 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.component .grid h2 .icon { .component h2 .icon {
margin-right: 4px; margin-right: 4px;
color: var(--primary); color: var(--primary);
} }
.component .grid li:nth-child(odd) { .component li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
@media (pointer: coarse) { @media (pointer: coarse) {
.component .grid .icon { .component .icon {
width: 32px; width: 32px;
} }
} }
@ -176,14 +176,14 @@ nav ul li.active {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#queue .grid li { #queue li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px; padding: 0 4px;
white-space: nowrap; white-space: nowrap;
} }
#queue .grid h2 { #queue h2 {
flex-grow: 1; flex-grow: 1;
font-size: 100%; font-size: 100%;
font-weight: normal; font-weight: normal;
@ -191,15 +191,15 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#queue .grid h2 .icon { #queue h2 .icon {
margin-right: 4px; margin-right: 4px;
color: var(--primary); color: var(--primary);
} }
#queue .grid li:nth-child(odd) { #queue li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
@media (pointer: coarse) { @media (pointer: coarse) {
#queue .grid .icon { #queue .icon {
width: 32px; width: 32px;
} }
} }
@ -218,14 +218,14 @@ nav ul li.active {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#library .grid li { #library li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px; padding: 0 4px;
white-space: nowrap; white-space: nowrap;
} }
#library .grid h2 { #library h2 {
flex-grow: 1; flex-grow: 1;
font-size: 100%; font-size: 100%;
font-weight: normal; font-weight: normal;
@ -233,26 +233,33 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#library .grid h2 .icon { #library h2 .icon {
margin-right: 4px; margin-right: 4px;
color: var(--primary); color: var(--primary);
} }
#library .grid li:nth-child(odd) { #library li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
@media (pointer: coarse) { @media (pointer: coarse) {
#library .grid .icon { #library .icon {
width: 32px; width: 32px;
} }
} }
#library .tiles { #library .tiles {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap: 2px;
} }
#library .tiles li { #library .tiles li {
border: 3px solid lime; text-align: center;
cursor: pointer;
background-color: rgba(255, 255, 255, 0.08);
height: 200px; height: 200px;
} }
#library .tiles li h2 {
font-size: 150%;
margin: 4px 0;
}
#fs { #fs {
height: 100%; height: 100%;
display: flex; display: flex;
@ -265,14 +272,14 @@ nav ul li.active {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#fs .grid li { #fs li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px; padding: 0 4px;
white-space: nowrap; white-space: nowrap;
} }
#fs .grid h2 { #fs h2 {
flex-grow: 1; flex-grow: 1;
font-size: 100%; font-size: 100%;
font-weight: normal; font-weight: normal;
@ -280,15 +287,15 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#fs .grid h2 .icon { #fs h2 .icon {
margin-right: 4px; margin-right: 4px;
color: var(--primary); color: var(--primary);
} }
#fs .grid li:nth-child(odd) { #fs li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
@media (pointer: coarse) { @media (pointer: coarse) {
#fs .grid .icon { #fs .icon {
width: 32px; width: 32px;
} }
} }
@ -307,14 +314,14 @@ nav ul li.active {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
#playlists .grid li { #playlists li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
padding: 0 4px; padding: 0 4px;
white-space: nowrap; white-space: nowrap;
} }
#playlists .grid h2 { #playlists h2 {
flex-grow: 1; flex-grow: 1;
font-size: 100%; font-size: 100%;
font-weight: normal; font-weight: normal;
@ -322,15 +329,15 @@ nav ul li.active {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
#playlists .grid h2 .icon { #playlists h2 .icon {
margin-right: 4px; margin-right: 4px;
color: var(--primary); color: var(--primary);
} }
#playlists .grid li:nth-child(odd) { #playlists li:nth-child(odd) {
background-color: #555; background-color: #555;
} }
@media (pointer: coarse) { @media (pointer: coarse) {
#playlists .grid .icon { #playlists .icon {
width: 32px; width: 32px;
} }
} }

View file

@ -10,7 +10,7 @@ body {
line-height: 1; line-height: 1;
background-color: var(--bg); background-color: var(--bg);
color: var(--fg); color: var(--fg);
text-shadow: 0 1px 1px #000; text-shadow: 0 1px 1px rgba(0, 0, 0, 0.8);
max-width: 800px; max-width: 800px;
margin: 0 auto; margin: 0 auto;
overflow: hidden; overflow: hidden;

View file

@ -11,7 +11,6 @@
padding: 0; padding: 0;
} }
.grid {
li { li {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -41,5 +40,4 @@
@media (pointer: coarse) { @media (pointer: coarse) {
.icon { width: 32px; } .icon { width: 32px; }
} }
}
} }

View file

@ -3,11 +3,19 @@
.tiles { .tiles {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-gap: 2px;
li { li {
border: 3px solid lime; text-align: center;
cursor: pointer;
background-color: rgba(255, 255, 255, 0.08);
height: 200px; height: 200px;
h2 {
font-size: 150%;
margin: 4px 0;
}
} }
} }
} }

View file

@ -35,10 +35,10 @@
<button class="clear" data-icon="close" title="Clear the queue"></button> <button class="clear" data-icon="close" title="Clear the queue"></button>
<button class="save" data-icon="content-save" title="Save the queue"></button> <button class="save" data-icon="content-save" title="Save the queue"></button>
</header> </header>
<ul class="grid"></ul> <ul></ul>
</section> </section>
<section id="playlists"> <section id="playlists">
<ul class="grid"></ul> <ul></ul>
</section> </section>
<section id="library"> <section id="library">
<header></header> <header></header>
@ -46,7 +46,7 @@
</section> </section>
<section id="fs"> <section id="fs">
<header></header> <header></header>
<ul class="grid"></ul> <ul></ul>
</section> </section>
<section id="yt"> <section id="yt">
<button class="go" data-icon="download">Go!</button> <button class="go" data-icon="download">Go!</button>

View file

@ -11,6 +11,7 @@ function onMessage(e) {
if (last.startsWith("OK")) { if (last.startsWith("OK")) {
current.resolve(lines); current.resolve(lines);
} else { } else {
console.warn(last);
current.reject(last); current.reject(last);
} }
current = null; current = null;
@ -108,12 +109,13 @@ export async function listTags(tag, filter = null) {
} }
let lines = await command(tokens.join(" ")); let lines = await command(tokens.join(" "));
let parsed = parser.linesToStruct(lines); let parsed = parser.linesToStruct(lines);
return [].concat(parsed[tag] || []); return [].concat(tag in parsed ? parsed[tag] : []);
} }
export async function listSongs(filter) { export async function listSongs(filter, window = null) {
let tokens = ["find"]; let tokens = ["find"];
tokens.push(serializeFilter(filter)); tokens.push(serializeFilter(filter));
if (window) { tokens.push("window", window.join(":")); }
let lines = await command(tokens.join(" ")); let lines = await command(tokens.join(" "));
return parser.songList(lines); return parser.songList(lines);
} }

View file

@ -2,6 +2,7 @@ import * as mpd from "./mpd.js";
import * as html from "./html.js"; import * as html from "./html.js";
import * as pubsub from "./pubsub.js"; import * as pubsub from "./pubsub.js";
import * as format from "./format.js"; import * as format from "./format.js";
import * as art from "./art.js";
import * as player from "../player.js"; import * as player from "../player.js";
export const CTX_FS = 1; export const CTX_FS = 1;
@ -15,7 +16,7 @@ const TYPE_PLAYLIST = 4;
const SORT = "-Track"; const SORT = "-Track";
function enqueue(type, what) { async function enqueue(type, what) {
switch (type) { switch (type) {
case TYPE_URL: return mpd.command(`add "${mpd.escape(what)}"`); break; case TYPE_URL: return mpd.command(`add "${mpd.escape(what)}"`); break;
case TYPE_FILTER: return mpd.enqueueByFilter(what, SORT); break; case TYPE_FILTER: return mpd.enqueueByFilter(what, SORT); break;
@ -23,6 +24,28 @@ function enqueue(type, what) {
} }
} }
async function fillArt(parent, filter) {
let artist = filter["Artist"];
let album = filter["Album"];
let src = null;
if (artist && album) {
src = await art.get(artist, album);
if (!src) {
let songs = await mpd.listSongs(filter, [0,1]);
if (songs.length) {
src = await art.get(artist, album, songs[0]["file"]);
}
}
}
if (src) {
html.node("img", {src}, "", parent);
} else {
html.icon("music", parent);
}
}
function fileName(data) { function fileName(data) {
return data["file"].split("/").pop(); return data["file"].split("/").pop();
} }
@ -106,7 +129,6 @@ function addButton(type, what, parent) {
export function song(ctx, data, parent) { export function song(ctx, data, parent) {
let node = html.node("li", {className:"song"}, "", parent); let node = html.node("li", {className:"song"}, "", parent);
let title = formatTitle(ctx, data); let title = formatTitle(ctx, data);
let h2 = html.node("h2", {}, "", node); let h2 = html.node("h2", {}, "", node);
if (ctx == CTX_FS || ctx == CTX_LIBRARY) { html.icon("music", h2); } if (ctx == CTX_FS || ctx == CTX_LIBRARY) { html.icon("music", h2); }
@ -136,10 +158,16 @@ export function song(ctx, data, parent) {
export function group(ctx, label, urlOrFilter, parent) { export function group(ctx, label, urlOrFilter, parent) {
let node = html.node("li", {className:"group"}, "", parent); let node = html.node("li", {className:"group"}, "", parent);
if (ctx == CTX_LIBRARY) {
let art = html.node("span", {className:"art"}, "", node);
fillArt(art, urlOrFilter);
}
let h2 = html.node("h2", {}, "", node); let h2 = html.node("h2", {}, "", node);
if (ctx == CTX_FS) { html.icon("folder", h2); } if (ctx == CTX_FS) { html.icon("folder", h2); }
html.text(label, h2); html.text(label, h2);
let type = (ctx == CTX_FS ? TYPE_URL : TYPE_FILTER); let type = (ctx == CTX_FS ? TYPE_URL : TYPE_FILTER);
playButton(type, urlOrFilter, node); playButton(type, urlOrFilter, node);

View file

@ -44,8 +44,6 @@ function buildArtist(artist, filter, parent) {
function buildSongs(songs, filter) { function buildSongs(songs, filter) {
let ul = node.querySelector("ul"); let ul = node.querySelector("ul");
html.clear(ul); html.clear(ul);
ul.classList.remove("tiles");
ul.classList.add("grid");
songs.map(song => ui.song(ui.CTX_LIBRARY, song, ul)); songs.map(song => ui.song(ui.CTX_LIBRARY, song, ul));
} }
@ -53,8 +51,6 @@ function buildSongs(songs, filter) {
function buildAlbums(albums, filter) { function buildAlbums(albums, filter) {
let ul = node.querySelector("ul"); let ul = node.querySelector("ul");
html.clear(ul); html.clear(ul);
ul.classList.add("tiles");
ul.classList.remove("grid");
albums.map(album => buildAlbum(album, filter, ul)); albums.map(album => buildAlbum(album, filter, ul));
} }
@ -62,8 +58,6 @@ function buildAlbums(albums, filter) {
function buildArtists(artists, filter) { function buildArtists(artists, filter) {
let ul = node.querySelector("ul"); let ul = node.querySelector("ul");
html.clear(ul); html.clear(ul);
ul.classList.add("tiles");
ul.classList.remove("grid");
artists.map(artist => buildArtist(artist, filter, ul)); artists.map(artist => buildArtist(artist, filter, ul));
} }

View file

@ -15,9 +15,16 @@ function sync(data) {
DOM.elapsed.textContent = format.time(Number(data["elapsed"] || 0)); // changed time DOM.elapsed.textContent = format.time(Number(data["elapsed"] || 0)); // changed time
if (data["file"] != current["file"]) { // changed song if (data["file"] != current["file"]) { // changed song
if (data["file"]) { // playing at all?
DOM.duration.textContent = format.time(Number(data["duration"] || 0)); DOM.duration.textContent = format.time(Number(data["duration"] || 0));
DOM.title.textContent = data["Title"] || data["file"].split("/").pop(); DOM.title.textContent = data["Title"] || data["file"].split("/").pop();
DOM["artist-album"].textContent = format.artistAlbum(data["Artist"], data["Album"]); DOM["artist-album"].textContent = format.artistAlbum(data["Artist"], data["Album"]);
} else {
DOM.duration.textContent = "";
DOM.title.textContent = "";
DOM["artist-album"].textContent = "";
}
pubsub.publish("song-change", null, data); pubsub.publish("song-change", null, data);
} }