2 Commits

Author SHA1 Message Date
d96350c1a7 feat: frontend: Allow creating directories
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m38s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 9s
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>
2025-12-21 14:23:34 +01:00
eec3703b7e feat: Extend audiofiles API
Extend the audiofiles GET API to return both directories and audio
files. Also change the JSON format to include the name and type of all
entries.

Signed-off-by: Matthias Blankertz <matthias@blankertz.org>
2025-12-21 14:22:38 +01:00
2 changed files with 41 additions and 10 deletions

View File

@@ -277,6 +277,10 @@
<button id="playlist-filebrowser-upload">Upload</button>
<progress id="playlist-filebrowser-upload-progress" max="100" value="0">0%</progress>
</div>
<div class="flex-horizontal">
<input type="text" id="playlist-filebrowser-mkdir-name" />
<button id="playlist-filebrowser-mkdir">Create directory</button>
</div>
</div>
</div>
@@ -565,6 +569,7 @@
function selectTag(tag) {
const container = document.getElementById('playlist-exist-list');
if (tag.tag === null) return;
const tagtext = bytesToHex(tag.tag);
document.getElementById('playlist-exist-list')
.querySelectorAll("li")
@@ -744,6 +749,9 @@
document.getElementById('playlist-filebrowser-upload').addEventListener("click", (e) => {
uploadFiles();
});
document.getElementById('playlist-filebrowser-mkdir').addEventListener("click", (e) => {
createDirectory();
});
tree.init();
}
@@ -797,17 +805,16 @@
const rootnode = document.createElement('ul');
tree.appendChild(rootnode);
files.sort();
files.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0));
for (const file of files) {
const path = file.split('/').slice(1);
const path = file.name.split('/').slice(1);
let treeIterator = rootnode;
let curPath = ''
for (const elem of path) {
curPath += '/' + elem;
let node = findChildByName(treeIterator, elem);
if (node === null) {
const isFile = path.slice(-1)[0] === elem;
node = addTreeNode(treeIterator, elem, isFile ? 'file':'directory', curPath);
node = addTreeNode(treeIterator, elem, file.type, curPath);
}
treeIterator = node;
}
@@ -881,6 +888,25 @@
xhr.overrideMimeType("audio/mpeg");
xhr.send(files[0]);
}
async function createDirectory() {
const name = document.getElementById('playlist-filebrowser-mkdir-name');
const selectedNodes = [...tree.querySelectorAll(".selected")];
const files = [...document.getElementById("playlist-filebrowser-upload-files").files];
if (selectedNodes.length > 1 ||
(selectedNodes.length === 1 &&
selectedNodes[0].getAttribute('data-type') !== "directory")) {
alert("Please select a single directory for upload");
return;
}
const location = selectedNodes.length === 1
? selectedNodes[0].getAttribute('data-path') + '/' + name.value
: '/' + name.value;
const saveRes = await fetch(`/api/v1/audiofiles?type=directory&location=${location}`,
{method: 'POST'});
// Reload file list from device
onShow();
}
let tree = (() => {
let tree = null;

View File

@@ -162,6 +162,15 @@ async def audiofiles_get(request):
def directory_iterator():
yield '['
first = True
def make_json_str(obj):
nonlocal first
jsonpath = json.dumps(obj)
if not first:
jsonpath = ',' + jsonpath
first = False
return jsonpath
dirstack = [fsroot]
while dirstack:
current_dir = dirstack.pop()
@@ -170,15 +179,11 @@ async def audiofiles_get(request):
type_ = entry[1]
current_path = current_dir + b'/' + name
if type_ == 0x4000:
yield make_json_str({'name': current_path[len(fsroot):], 'type': 'directory'})
dirstack.append(current_path)
elif type_ == 0x8000:
if name.lower().endswith('.mp3'):
jsonpath = json.dumps(current_path[len(fsroot):])
if not first:
yield ','+jsonpath
else:
yield jsonpath
first = False
yield make_json_str({'name': current_path[len(fsroot):], 'type': 'file'})
yield ']'
return directory_iterator(), {'Content-Type': 'application/json; charset=UTF-8'}