From 7be038d0d1060f68a806ca54d3439943f253e10e Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Sun, 21 Dec 2025 15:12:31 +0100 Subject: [PATCH] feat: Allow deleting files and directories Signed-off-by: Matthias Blankertz --- software/frontend/index.html | 63 +++++++++++++++++------------------- software/src/app.py | 6 +++- software/src/webserver.py | 23 +++++++++++++ 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/software/frontend/index.html b/software/frontend/index.html index 533c725..c812b44 100644 --- a/software/frontend/index.html +++ b/software/frontend/index.html @@ -235,51 +235,22 @@
  • Loading...
-
+
- +
+ 0% - 0%
- - + +
@@ -752,6 +723,9 @@ document.getElementById('playlist-filebrowser-mkdir').addEventListener("click", (e) => { createDirectory(); }); + document.getElementById('playlist-filebrowser-delete').addEventListener("click", (e) => { + deleteItems(); + }); tree.init(); } @@ -907,6 +881,27 @@ // Reload file list from device onShow(); } + + async function deleteItems() { + const tree = document.getElementById("playlist-filebrowser-tree"); + const selectedNodes = [...tree.querySelectorAll(".selected")]; + if (selectedNodes.length === 0) { + alert("Please select something to delete"); + return; + } + const items = selectedNodes.map(n => n.getAttribute('data-path')); + items.sort(); + items.reverse(); + for (const item of items) { + const saveRes = await fetch(`/api/v1/audiofiles?location=${item}`, + {method: 'DELETE'}); + if (!saveRes.ok) { + alert(`Failed to delete item ${item}: ${await saveRes.text()}`); + } + } + // Reload file list from device + onShow(); + } let tree = (() => { let tree = null; diff --git a/software/src/app.py b/software/src/app.py index 344abed..fc29d88 100644 --- a/software/src/app.py +++ b/software/src/app.py @@ -161,7 +161,11 @@ class PlayerApp: self._onIdle() if filename is not None: print(f'Playing {filename!r}') - self.mp3file = open(filename, 'rb') + try: + self.mp3file = open(filename, 'rb') + except OSError as ex: + print(f"Could not play file {filename}: {ex}") + return self.player.play(self.mp3file, offset) self.paused = False self._onActive() diff --git a/software/src/webserver.py b/software/src/webserver.py index c56fad2..2347a7b 100644 --- a/software/src/webserver.py +++ b/software/src/webserver.py @@ -223,3 +223,26 @@ async def audiofile_upload(request): return '', 204 else: return 'size mismatch', 500 + + +def recursive_delete(path): + stat = os.stat(path) + if stat[0] == 0x8000: + os.remove(path) + elif stat[0] == 0x4000: + for entry in os.ilistdir(path): + entry_path = path + '/' + entry[0] + recursive_delete(entry_path) + os.rmdir(path) + + +@webapp.route('/api/v1/audiofiles', methods=['DELETE']) +async def audiofile_delete(request): + if 'location' not in request.args: + return 'missing location', 400 + location = request.args['location'] + if '..' in location or len(location) == 0: + return 'bad location', 400 + path = fsroot + '/' + request.args['location'] + recursive_delete(path) + return '', 204