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 @@
+
-
+
-
-
+
+
@@ -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