diff --git a/modules/web.py b/modules/web.py index ab89a75..1fd4a2b 100644 --- a/modules/web.py +++ b/modules/web.py @@ -71,7 +71,7 @@ async def ws_handler(websocket: ServerConnection, shared_data: dict, imc_q: mult await broadcast({"data": result, "event": "toplay"}) elif action == "remove_toplay" or action == "toggle_official_toplay": idx = msg.get("indexes") - if not isinstance(songs, list): await websocket.send(json.dumps({"error": "songs must be a list"})) + if not isinstance(idx, list): await websocket.send(json.dumps({"error": "indexes must be a list"})) else: imc_q.put({"name": "activemod", "data": {"action": action, "indexes": idx}}) result = await get_imc("activemod", {"action": "get_toplay"}) diff --git a/modules/web/index.html b/modules/web/index.html index d34e820..c61ccd8 100644 --- a/modules/web/index.html +++ b/modules/web/index.html @@ -193,7 +193,6 @@ - @@ -251,10 +250,6 @@
-
- - -
diff --git a/modules/web/web.js b/modules/web/web.js index 8147bcb..a71c12d 100644 --- a/modules/web/web.js +++ b/modules/web/web.js @@ -4,10 +4,8 @@ let playlist = []; let queue = []; let currentTrackPath = ""; let currentTrackIndex = 0; -let selectedPlaylistPath = null; let selectedPlaylistIndex = null; let selectedDir = null; -let selectedSubFile = null; let basePath = ""; let subBasePath = ""; let skipCount = 0; @@ -231,7 +229,7 @@ function renderQueue() { queue.forEach(path => { const li = document.createElement("li"); li.dataset.idx = i++; - + var c = path.replace(basePath, ""); if(c.startsWith("!")) c = "(unofficial) " + c.slice(2) else c = "(official) " + c.slice(1) @@ -260,34 +258,26 @@ function updateDirs(payload) { box.innerHTML = ""; basePath = payload.base || ""; - const addItem = (name, onClick) => { + const addItem = (name, onClick, onContext) => { const node = document.createElement("div"); node.className = "item"; node.textContent = name; - node.addEventListener("click", () => onClick(node)); + node.addEventListener("click", (e) => onClick(node, e)); + if(onContext !== undefined) node.addEventListener("contextmenu", () => onContext(node, e)); box.appendChild(node); }; (payload.dirs || []).sort().forEach(name => { - if (!name.startsWith(".")) addItem(name, node => onDirClicked(name, node)); + if (!name.startsWith(".")) addItem(name, (node, e) => onDirClicked(name, node)); }); (payload.files || []).sort().forEach(name => { if (!name.startsWith(".")) { - addItem(name, node => { - if (node.classList.contains("selected")) { - node.classList.remove("selected"); - selectedDir = null; - selectedSubFile = null; - return; - } - clearListSelections("playlist-ul", "subdir-box"); - Array.from(box.children).forEach(c => c.classList.remove("selected")); - node.classList.add("selected"); - node.dataset.type = "file"; - selectedDir = null; - selectedSubFile = null; - document.getElementById("subdir-box").innerHTML = ""; + addItem(name, () => { + wsSend({ action: "add_to_toplay", songs: [basePath.replace(/\/$/, "") + "/" + name], top: false }) + }, (node, e) => { + e.preventDefault() + wsSend({ action: "add_to_toplay", songs: [basePath.replace(/\/$/, "") + "/" + name], top: true }) }); } }); @@ -297,14 +287,12 @@ function onDirClicked(name, node) { if (node.classList.contains("selected")) { node.classList.remove("selected"); selectedDir = null; - selectedSubFile = null; document.getElementById("subdir-box").innerHTML = ""; return; } clearListSelections("dirs-box", "playlist-ul"); node.classList.add("selected"); selectedDir = name; - selectedSubFile = null; wsSend({ action: "request_dir", what: selectedDir }); } @@ -319,91 +307,26 @@ function applySubdir(payload) { node.className = "item"; node.textContent = f; node.addEventListener("click", () => { - if (node.classList.contains("selected")) { - node.classList.remove("selected"); - selectedSubFile = null; - return; - } - clearListSelections("subdir-box", "playlist-ul"); - Array.from(document.getElementById("dirs-box").children).forEach(c => c.classList.remove("selected")); - - // Re-select the parent dir node - Array.from(document.getElementById("dirs-box").children).forEach(c => { - if (c.textContent === selectedDir) c.classList.add("selected"); - }); - - node.classList.add("selected"); - selectedSubFile = f; + wsSend({ action: "add_to_toplay", songs: [subBasePath.replace(/\/$/, "") + "/" + f], top: false }); + }); + node.addEventListener("contextmenu", (e) => { + e.preventDefault() + wsSend({ action: "add_to_toplay", songs: [subBasePath.replace(/\/$/, "") + "/" + f], top: true }); }); box.appendChild(node); }); } function selectPlaylistItem(i, el) { - const path = el.dataset.path; - if (el.classList.contains("selected")) { - el.classList.remove("selected"); - selectedPlaylistPath = null; - updateControls(); - return; - } - clearListSelections("playlist-ul", "dirs-box", "subdir-box"); - el.classList.add("selected"); - selectedPlaylistPath = path; - selectedPlaylistIndex = i; + const action = skippedIndices.includes(i) + ? { action: "skipi", remove: i } + : { action: "skipi", add: i }; + wsSend(action); updateControls(); } -function addSelectedFileToQueue(top) { - let fullPath = null; - - if (selectedPlaylistPath != null) { - const selected = playlist.find(t => t.path === selectedPlaylistPath); - if (!selected) return false; - const path = (selected.official ? "" : "!") + selected.path; - wsSend({ action: "add_to_toplay", songs: [path], top }); - clearListSelections("playlist-ul"); - selectedPlaylistPath = null; - selectedPlaylistIndex = null; - updateControls(); - return true; - } - - if (selectedSubFile && selectedDir) { - fullPath = subBasePath.replace(/\/$/, "") + "/" + selectedSubFile; - } else { - const selectedFileEl = Array.from(document.getElementById("dirs-box").children).find(el => el.classList.contains("selected") && el.dataset.type === "file"); - if (selectedFileEl) { - fullPath = basePath.replace(/\/$/, "") + "/" + selectedFileEl.textContent; - } - } - - if (fullPath) { - wsSend({ action: "add_to_toplay", songs: [fullPath], top }); - // Dir/subdir selections are intentionally preserved here - return true; - } - - return false; -} - function updateControls() { document.getElementById("clear-btn").disabled = queue.length === 0; - - const btn = document.getElementById("skipidx-btn"); - if (selectedPlaylistIndex == null) { - btn.textContent = "⏭+ Skip in playlist"; - btn.disabled = true; - btn.classList.remove("activated"); - } else if (skippedIndices.includes(selectedPlaylistIndex)) { - btn.textContent = "✓ Unskip in playlist"; - btn.disabled = false; - btn.classList.add("activated"); - } else { - btn.textContent = "⏭+ Skip in playlist"; - btn.disabled = false; - btn.classList.remove("activated"); - } } document.getElementById("skip-btn").addEventListener("click", () => wsSend({ action: "skip" })); @@ -416,26 +339,14 @@ document.getElementById("jingle-btn").addEventListener("contextmenu", e => { wsSend({ action: "jingle", top: true }); }); -document.getElementById("skipidx-btn").addEventListener("click", () => { - if (selectedPlaylistIndex == null) return; - const action = skippedIndices.includes(selectedPlaylistIndex) - ? { action: "skipi", remove: selectedPlaylistIndex } - : { action: "skipi", add: selectedPlaylistIndex }; - wsSend(action); -}); - document.getElementById("queue-title").addEventListener("click", () => toggleSection("section-queue")); document.getElementById("clear-btn").addEventListener("click", e => { e.stopPropagation(); wsSend({ action: "clear_toplay" }); }); -document.getElementById("add-to-queue-btn").addEventListener("click", () => addSelectedFileToQueue(false)); -document.getElementById("add-to-queue2-btn").addEventListener("click", () => addSelectedFileToQueue(true)); - document.addEventListener("keydown", e => { if (e.target.tagName === "INPUT") return; - if (e.key === "Enter" && addSelectedFileToQueue(e.shiftKey)) e.preventDefault(); else if (e.key === "s") wsSend({ action: "skip" }); else if (e.key === "n") wsSend({ action: "skipc", add: 1 }); else if (e.key === "m") wsSend({ action: "skipc", remove: -1 });