feat: Allow deleting files and directories
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m40s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 4s
Run unit tests on host / Run-Unit-Tests (push) Successful in 8s
Run pytests / Check-Pytest (push) Successful in 10s
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m40s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 4s
Run unit tests on host / Run-Unit-Tests (push) Successful in 8s
Run pytests / Check-Pytest (push) Successful in 10s
Signed-off-by: Matthias Blankertz <matthias@blankertz.org>
This commit is contained in:
@@ -235,51 +235,22 @@
|
|||||||
<div class="scroll-container">
|
<div class="scroll-container">
|
||||||
<div class="tree" id="playlist-filebrowser-tree">
|
<div class="tree" id="playlist-filebrowser-tree">
|
||||||
<ul><li>Loading...</li></ul>
|
<ul><li>Loading...</li></ul>
|
||||||
<!--<ul>
|
|
||||||
<li>
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="node">Fruits</span>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="node">Apple</span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="node">Citrus</span>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="node">Orange</span>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="node">Lemon</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<span class="caret"></span>
|
|
||||||
<span class="node">Strawberry</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul> -->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-horizontal">
|
<div class="flex-horizontal">
|
||||||
<button id="playlist-filebrowser-cancel">Cancel</button>
|
<button id="playlist-filebrowser-cancel">Cancel</button>
|
||||||
|
<button id="playlist-filebrowser-delete" style="background-color: orangered">Delete selected</button>
|
||||||
<button id="playlist-filebrowser-addtrack">Add track(s)</button>
|
<button id="playlist-filebrowser-addtrack">Add track(s)</button>
|
||||||
</div>
|
</div>
|
||||||
<label>Upload files</label>
|
<hr>
|
||||||
<div class="flex-horizontal">
|
<div class="flex-horizontal">
|
||||||
<input type="file" id="playlist-filebrowser-upload-files" multiple accept="audio/mpeg" />
|
<input type="file" id="playlist-filebrowser-upload-files" multiple accept="audio/mpeg" />
|
||||||
|
<progress id="playlist-filebrowser-upload-progress" max="100" value="0" style:"flex-grow: 1">0%</progress>
|
||||||
<button id="playlist-filebrowser-upload">Upload</button>
|
<button id="playlist-filebrowser-upload">Upload</button>
|
||||||
<progress id="playlist-filebrowser-upload-progress" max="100" value="0">0%</progress>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-horizontal">
|
<div class="flex-horizontal">
|
||||||
<input type="text" id="playlist-filebrowser-mkdir-name" />
|
<input type="text" id="playlist-filebrowser-mkdir-name" placeholder="Directory Name" />
|
||||||
<button id="playlist-filebrowser-mkdir">Create directory</button>
|
<button id="playlist-filebrowser-mkdir" style="width: 20%">Create directory</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -752,6 +723,9 @@
|
|||||||
document.getElementById('playlist-filebrowser-mkdir').addEventListener("click", (e) => {
|
document.getElementById('playlist-filebrowser-mkdir').addEventListener("click", (e) => {
|
||||||
createDirectory();
|
createDirectory();
|
||||||
});
|
});
|
||||||
|
document.getElementById('playlist-filebrowser-delete').addEventListener("click", (e) => {
|
||||||
|
deleteItems();
|
||||||
|
});
|
||||||
tree.init();
|
tree.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -908,6 +882,27 @@
|
|||||||
onShow();
|
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 = (() => {
|
||||||
let tree = null;
|
let tree = null;
|
||||||
function init() {
|
function init() {
|
||||||
|
|||||||
@@ -161,7 +161,11 @@ class PlayerApp:
|
|||||||
self._onIdle()
|
self._onIdle()
|
||||||
if filename is not None:
|
if filename is not None:
|
||||||
print(f'Playing {filename!r}')
|
print(f'Playing {filename!r}')
|
||||||
|
try:
|
||||||
self.mp3file = open(filename, 'rb')
|
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.player.play(self.mp3file, offset)
|
||||||
self.paused = False
|
self.paused = False
|
||||||
self._onActive()
|
self._onActive()
|
||||||
|
|||||||
@@ -223,3 +223,26 @@ async def audiofile_upload(request):
|
|||||||
return '', 204
|
return '', 204
|
||||||
else:
|
else:
|
||||||
return 'size mismatch', 500
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user