diff options
| author | Danilo M. <danix@danix.xyz> | 2026-11-09 19:08:51 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-11-09 19:08:51 +0100 |
| commit | 15e384bc1d97c84df0545555bf4c298702c9eacb (patch) | |
| tree | f386400b398ebf55f9c3f2d060642e9b01255a95 /static/modules/music.js | |
| parent | 4632e6183d38bfd239f066d7e9698f3d118a3f77 (diff) | |
| download | deck-it-15e384bc1d97c84df0545555bf4c298702c9eacb.tar.gz deck-it-15e384bc1d97c84df0545555bf4c298702c9eacb.zip | |
feat: card headers, music art/seek, clearer build card
Diffstat (limited to 'static/modules/music.js')
| -rw-r--r-- | static/modules/music.js | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/static/modules/music.js b/static/modules/music.js index de9df7f..e4388f7 100644 --- a/static/modules/music.js +++ b/static/modules/music.js @@ -1,9 +1,14 @@ -async function post(action) { +function clock(s) { + s = Math.max(0, Math.floor(s || 0)); + return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`; +} + +async function post(action, body = {}) { try { await fetch(`/api/music/${action}`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: "{}", + body: JSON.stringify(body), }); } catch { // the next poll shows the real state @@ -22,27 +27,51 @@ export default { interval: 2, mount(el) { - const box = document.createElement("div"); - box.className = "music"; - box.innerHTML = ` - <div class="now"><b class="title">—</b><span class="artist muted"></span></div> - <div class="row controls"></div> - <div class="row vol"></div>`; - box.querySelector(".controls").append( - button("⏮", "prev"), button("⏯", "play"), button("⏭", "next")); - box.querySelector(".vol").append( + el.innerHTML = ` + <div class="top"> + <div class="art empty">♪</div> + <div class="meta"> + <div class="title">Nothing playing</div> + <div class="artist muted"></div> + <div class="album muted"></div> + </div> + </div> + <div class="seek"> + <input type="range" min="0" max="1" step="1" value="0" aria-label="Seek"> + <span class="time num">0:00</span> + </div> + <div class="controls"></div>`; + el.querySelector(".controls").append( + button("⏮", "prev"), button("⏯", "play"), button("⏭", "next"), button("Vol−", "voldown"), button("Mute", "mute"), button("Vol+", "volup")); - el.append(box); + const seek = el.querySelector(".seek input"); + seek.addEventListener("pointerdown", () => { el._dragging = true; }); + seek.addEventListener("pointerup", () => { el._dragging = false; }); + seek.addEventListener("change", () => post("seek", { position: Number(seek.value) })); }, update(st, el) { - const box = el.querySelector(".music"); - box.querySelector(".title").textContent = st.title || "Nothing playing"; - box.querySelector(".artist").textContent = st.artist || ""; - box.querySelector(".controls button:nth-child(2)").textContent = + if (st.art) { + let img = el.querySelector("img.art"); + if (!img) { + img = document.createElement("img"); + img.className = "art"; + img.alt = ""; + el.querySelector(".art").replaceWith(img); + } + if (img.getAttribute("src") !== st.art) img.src = st.art; + } + el.querySelector(".title").textContent = st.title || "Nothing playing"; + el.querySelector(".artist").textContent = st.artist || ""; + el.querySelector(".album").textContent = st.album || ""; + el.querySelector(".controls button:nth-child(2)").textContent = st.status === "Playing" ? "⏸" : "▶"; - const mute = box.querySelector(".vol button:nth-child(2)"); + const mute = el.querySelector(".controls button:nth-child(5)"); mute.classList.toggle("on", Boolean(st.volume?.muted)); mute.textContent = st.volume?.muted ? "Unmute" : "Mute"; + const seek = el.querySelector(".seek input"); + seek.max = Math.max(1, Math.floor(st.length || 0)); + if (!el._dragging) seek.value = Math.min(Number(seek.max), Math.floor(st.position || 0)); + el.querySelector(".time").textContent = `${clock(st.position)} / ${clock(st.length)}`; }, }; |
