diff --git a/software/frontend/index.html b/software/frontend/index.html
index 01867da..2f87fb7 100644
--- a/software/frontend/index.html
+++ b/software/frontend/index.html
@@ -213,6 +213,10 @@
+
@@ -493,7 +497,7 @@
document.getElementById('playlist-exist-button-delete')
.addEventListener('click', (e) => {
if (lastSelected === null) return;
- const tagid = lastSelected.innerText;
+ const tagid = lastSelected.getAttribute('data-tag');
if(confirm(`Really delete playlist ${tagid}?`)) {
fetch(`/api/v1/playlist/${tagid}`, {
method: 'DELETE'})
@@ -504,7 +508,7 @@
.addEventListener('click', selectLastTag);
document.getElementById('playlist-exist-button-edit').addEventListener("click", (e) => {
if (lastSelected !== null)
- showScreen("playlist_edit", {load: lastSelected.innerText});
+ showScreen("playlist_edit", {load: lastSelected.getAttribute('data-tag')});
});
document.getElementById('playlist-exist-list').addEventListener("click", (e) => {
const node = e.target.closest("li");
@@ -559,8 +563,9 @@
container.innerHTML = "";
for (const playlist of playlists) {
const li = document.createElement("li");
- li.innerHTML = playlist;
+ li.innerHTML = `${playlist.name} (${playlist.tag})`;
li.className = "node"
+ li.setAttribute('data-tag', playlist.tag);
container.appendChild(li)
}
}
@@ -585,7 +590,7 @@
document.getElementById('playlist-exist-list')
.querySelectorAll("li")
.forEach(n => {
- if (n.innerText == tagtext) {
+ if (n.getAttribute('data-tag') == tagtext) {
n.classList.add("selected");
lastSelected = n;
} else {
@@ -687,6 +692,8 @@
} else if (playlist.persist === "track" && playlist.shuffle === "no") {
playlisttype.value = "audioplay";
}
+ const playlistname = document.getElementById('playlist-edit-name');
+ playlistname.value = playlist.name;
}
async function save() {
@@ -709,6 +716,8 @@
playlistData.shuffle = "no";
break;
}
+ const playlistname = document.getElementById('playlist-edit-name');
+ playlistData.name = playlistname.value;
const container = document.getElementById('playlist-edit-list');
playlistData.paths = [...container.querySelectorAll("li")].map((node) => node.innerText);
const saveRes = await fetch(`/api/v1/playlist/${playlistId}`,
diff --git a/software/src/utils/playlistdb.py b/software/src/utils/playlistdb.py
index 546311b..770010e 100644
--- a/software/src/utils/playlistdb.py
+++ b/software/src/utils/playlistdb.py
@@ -33,12 +33,13 @@ class BTreeDB(IPlaylistDB):
PERSIST_OFFSET = b'offset'
class Playlist(IPlaylist):
- def __init__(self, parent: "BTreeDB", tag: bytes, pos: int, persist, shuffle):
+ def __init__(self, parent: "BTreeDB", tag: bytes, pos: int, persist, shuffle, name):
self.parent = parent
self.tag = tag
self.pos = pos
self.persist = persist
self.shuffle = shuffle
+ self.name = name
self.length = self.parent._getPlaylistLength(self.tag)
self._shuffle()
@@ -168,6 +169,10 @@ class BTreeDB(IPlaylistDB):
return (b''.join([tag, b'/playlist/']),
b''.join([tag, b'/playlist0']))
+ @staticmethod
+ def _keyPlaylistName(tag):
+ return b''.join([tag, b'/playlistname'])
+
def _flush(self):
"""
Flush the database and call the flush_func if it was provided.
@@ -222,12 +227,13 @@ class BTreeDB(IPlaylistDB):
raise RuntimeError("Malformed playlist key")
return int(elements[2])+1
- def _savePlaylist(self, tag, entries, persist, shuffle, flush=True):
+ def _savePlaylist(self, tag, entries, persist, shuffle, name, flush=True):
self._deletePlaylist(tag, False)
for idx, entry in enumerate(entries):
self.db[self._keyPlaylistEntry(tag, idx)] = entry
self.db[self._keyPlaylistPersist(tag)] = persist
self.db[self._keyPlaylistShuffle(tag)] = shuffle
+ self.db[self._keyPlaylistName(tag)] = name.encode()
if flush:
self._flush()
@@ -240,7 +246,7 @@ class BTreeDB(IPlaylistDB):
pass
for k in (self._keyPlaylistPos(tag), self._keyPlaylistPosOffset(tag),
self._keyPlaylistPersist(tag), self._keyPlaylistShuffle(tag),
- self._keyPlaylistShuffleSeed(tag)):
+ self._keyPlaylistShuffleSeed(tag), self._keyPlaylistName(tag)):
try:
del self.db[k]
except KeyError:
@@ -248,15 +254,18 @@ class BTreeDB(IPlaylistDB):
if flush:
self._flush()
- def getPlaylistTags(self):
+ def getPlaylists(self):
"""
- Get a keys-only dict of all defined playlists. Playlists currently do not have names, but are identified by
- their tag.
+ Get a list of all defined playlists with their tag and names.
"""
playlist_tags = set()
for item in self.db:
playlist_tags.add(item.split(b'/')[0])
- return playlist_tags
+ playlists = []
+ for tag in playlist_tags:
+ name = self.db.get(self._keyPlaylistName(tag), b'').decode()
+ playlists.append({'tag': tag, 'name': name})
+ return playlists
def getPlaylistForTag(self, tag: bytes):
"""
@@ -275,18 +284,19 @@ class BTreeDB(IPlaylistDB):
return None
if self._keyPlaylistEntry(tag, pos) not in self.db:
pos = 0
+ name = self.db.get(self._keyPlaylistName(tag), b'').decode()
shuffle = self.db.get(self._keyPlaylistShuffle(tag), self.SHUFFLE_NO)
- return self.Playlist(self, tag, pos, persist, shuffle)
+ return self.Playlist(self, tag, pos, persist, shuffle, name)
def createPlaylistForTag(self, tag: bytes, entries: typing.Iterable[bytes], persist=PERSIST_TRACK,
- shuffle=SHUFFLE_NO):
+ shuffle=SHUFFLE_NO, name: str = ''):
"""
Create and save a playlist for 'tag' and return the Playlist object. If a playlist already existed for 'tag' it
is overwritten.
"""
assert persist in (self.PERSIST_NO, self.PERSIST_TRACK, self.PERSIST_OFFSET)
assert shuffle in (self.SHUFFLE_NO, self.SHUFFLE_YES)
- self._savePlaylist(tag, entries, persist, shuffle)
+ self._savePlaylist(tag, entries, persist, shuffle, name)
return self.getPlaylistForTag(tag)
def deletePlaylistForTag(self, tag: bytes):
@@ -370,6 +380,14 @@ class BTreeDB(IPlaylistDB):
_ = int(val)
except ValueError:
fail(f' Bad playlistposoffset value for {last_tag}: {val!r}')
+ elif fields[1] == b'playlistname':
+ val = self.db[k]
+ try:
+ name = val.decode()
+ if dump:
+ print(f'\tName: {name}')
+ except UnicodeError:
+ fail(f' Bad playlistname for {last_tag}: Not valid unicode')
else:
fail(f'Unknown key {k!r}')
return result
diff --git a/software/src/webserver.py b/software/src/webserver.py
index 8808dde..f87f467 100644
--- a/software/src/webserver.py
+++ b/software/src/webserver.py
@@ -112,7 +112,7 @@ async def static(request, path):
@webapp.route('/api/v1/playlists', methods=['GET'])
async def playlists_get(request):
- return sorted(playlist_db.getPlaylistTags())
+ return playlist_db.getPlaylists()
def is_hex(s):
@@ -133,10 +133,11 @@ async def playlist_get(request, tag):
return None, 404
return {
- 'shuffle': playlist.__dict__.get('shuffle'),
- 'persist': playlist.__dict__.get('persist'),
+ 'shuffle': playlist.shuffle,
+ 'persist': playlist.persist,
'paths': [(p[len(fsroot):] if p.startswith(fsroot) else p).decode()
for p in playlist.getPaths()],
+ 'name': playlist.name
}
@@ -156,7 +157,8 @@ async def playlist_put(request, tag):
playlist_db.createPlaylistForTag(tag.encode(),
(fsroot + path.encode() for path in playlist.get('paths', [])),
playlist.get('persist', 'track').encode(),
- playlist.get('shuffle', 'no').encode())
+ playlist.get('shuffle', 'no').encode(),
+ playlist.get('name', ''))
return '', 204