diff --git a/app/app.css b/app/app.css
index bf917cf..8750517 100644
--- a/app/app.css
+++ b/app/app.css
@@ -4,26 +4,33 @@ body {
flex-direction: column;
height: 100vh;
}
-header nav ul {
+main {
+ flex-grow: 1;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+nav ul {
margin: 0;
padding: 0;
list-style: none;
display: flex;
flex-direction: row;
}
-header nav ul li {
+nav ul li {
text-align: center;
flex-grow: 1;
line-height: 40px;
}
-header nav ul li:hover {
+nav ul li:hover {
background-color: red;
}
-main {
- flex-grow: 1;
- overflow-x: hidden;
- overflow-y: auto;
+#player:not([data-state=play]) .pause {
+ display: none;
}
-footer {
- flex-basis: 40px;
+#player[data-state=play] .play {
+ display: none;
+}
+#player:not(.random) .random,
+#player:not(.repeat) .repeat {
+ opacity: 0.5;
}
diff --git a/app/css/app.less b/app/css/app.less
index c4415c7..7bac648 100644
--- a/app/css/app.less
+++ b/app/css/app.less
@@ -5,6 +5,6 @@ body {
height: 100vh;
}
-@import "header.less";
@import "main.less";
-@import "footer.less";
+@import "nav.less";
+@import "player.less";
diff --git a/app/css/footer.less b/app/css/footer.less
deleted file mode 100644
index 6c87a64..0000000
--- a/app/css/footer.less
+++ /dev/null
@@ -1,3 +0,0 @@
-footer {
- flex-basis: 40px;
-}
diff --git a/app/css/header.less b/app/css/header.less
deleted file mode 100644
index a956045..0000000
--- a/app/css/header.less
+++ /dev/null
@@ -1,17 +0,0 @@
-header {
- nav ul {
- margin: 0;
- padding: 0;
- list-style: none;
- display: flex;
- flex-direction: row;
-
- li {
- text-align: center;
- flex-grow: 1;
- line-height: 40px;
-
- &:hover { background-color:red;}
- }
- }
-}
diff --git a/app/css/nav.less b/app/css/nav.less
new file mode 100644
index 0000000..7e653fc
--- /dev/null
+++ b/app/css/nav.less
@@ -0,0 +1,15 @@
+nav ul {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ display: flex;
+ flex-direction: row;
+
+ li {
+ text-align: center;
+ flex-grow: 1;
+ line-height: 40px;
+
+ &:hover { background-color:red;}
+ }
+}
diff --git a/app/css/player.less b/app/css/player.less
new file mode 100644
index 0000000..eac23f6
--- /dev/null
+++ b/app/css/player.less
@@ -0,0 +1,6 @@
+#player {
+ &:not([data-state=play]) .pause { display: none; }
+ &[data-state=play] .play { display: none; }
+
+ &:not(.random) .random, &:not(.repeat) .repeat { opacity: 0.5; }
+}
\ No newline at end of file
diff --git a/app/index.html b/app/index.html
index bad3dee..29d15f1 100644
--- a/app/index.html
+++ b/app/index.html
@@ -8,14 +8,19 @@
-
+
+
+
+
+
+ /
+
+
+
+
+
+
+
main
@@ -31,19 +36,14 @@
main
diff --git a/app/js/app.js b/app/js/app.js
index f7e4164..494d942 100644
--- a/app/js/app.js
+++ b/app/js/app.js
@@ -1,10 +1,10 @@
import * as mpd from "./mpd.js";
-import * as status from "./status.js";
+import * as player from "./player.js";
import * as art from "./art.js";
async function init() {
await mpd.init();
- status.init();
+ player.init();
window.mpd = mpd;
}
diff --git a/app/js/player.js b/app/js/player.js
new file mode 100644
index 0000000..1104e58
--- /dev/null
+++ b/app/js/player.js
@@ -0,0 +1,81 @@
+import * as mpd from "./mpd.js";
+import * as art from "./art.js";
+
+const DELAY = 2000;
+const DOM = {};
+
+let current = {};
+let node;
+let idleTimeout = null;
+
+function formatTime(sec) {
+ sec = Math.round(sec);
+ let m = Math.floor(sec / 60);
+ let s = sec % 60;
+ return `${m}:${s.toString().padStart(2, "0")}`;
+}
+
+function update(data) {
+ DOM.elapsed.textContent = formatTime(Number(data["elapsed"] || 0)); // changed time
+
+ if (data["file"] != current["file"]) { // changed song
+ DOM.duration.textContent = formatTime(Number(data["duration"] || 0));
+ DOM.title.textContent = data["Title"] || "";
+ DOM.album.textContent = data["Album"] || "";
+ DOM.artist.textContent = data["Artist"] || "";
+ }
+
+ if (data["Artist"] != current["Artist"] || data["Album"] != current["Album"]) { // changed album (art)
+ 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);
+ });
+ }
+
+ node.classList.toggle("random", data["random"] == "1");
+ node.classList.toggle("repeat", data["repeat"] == "1");
+ node.dataset.state = data["state"];
+
+ current = data;
+}
+
+async function sync() {
+ let data = await mpd.status();
+ update(data);
+ idle();
+}
+
+function idle() {
+ idleTimeout = setTimeout(sync, DELAY);
+}
+
+function clearIdle() {
+ idleTimeout && clearTimeout(idleTimeout);
+ idleTimeout = null;
+}
+
+async function command(cmd) {
+ clearIdle();
+ let data = await mpd.commandAndStatus(cmd);
+ update(data);
+ idle();
+}
+
+export function init() {
+ node = document.querySelector("#player");
+ let all = node.querySelectorAll("[class]");
+ Array.from(all).forEach(node => DOM[node.className] = node);
+
+ DOM.play.addEventListener("click", e => command("play"));
+ DOM.pause.addEventListener("click", e => command("pause 1"));
+ DOM.prev.addEventListener("click", e => command("previous"));
+ DOM.next.addEventListener("click", e => command("next"));
+
+ DOM.random.addEventListener("click", e => command(`random ${current["random"] == "1" ? "0" : "1"}`));
+ DOM.repeat.addEventListener("click", e => command(`repeat ${current["repeat"] == "1" ? "0" : "1"}`));
+
+ sync();
+}
diff --git a/app/js/status.js b/app/js/status.js
deleted file mode 100644
index 33afa16..0000000
--- a/app/js/status.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import * as mpd from "./mpd.js";
-import * as art from "./art.js";
-
-const DELAY = 2000;
-const DOM = {};
-
-let current = {};
-
-async function tick() {
- let data = await mpd.status();
-
- update(data);
-
-// console.log(data);
- 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() {
- let all = document.querySelectorAll("footer [class]");
- Array.from(all).forEach(node => DOM[node.className] = node);
-
- DOM.play.addEventListener("click", e => play());
- DOM.pause.addEventListener("click", e => pause());
-
- tick();
-}