feat: v1.24.0 — Playlist Management, native sample rate playback

- Full playlist feature: overview grid, detail page with hero collage,
  tracklist DnD, song search, suggestions, context menu submenu
- Audio: disable all app-level resampling — every track plays at its
  native sample rate (target_rate always 0 in audio_play + chain_next)
- Fix: playlist hero bg flicker (memoize buildCoverArtUrl calls)
- Fix: input focus double-border (search-input → .input class)
- Polish: redesigned playlist search panel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Psychotoxical
2026-03-31 23:14:15 +02:00
parent 662cc94ca8
commit c67d606f89
15 changed files with 1541 additions and 12 deletions
+140
View File
@@ -25,6 +25,7 @@ const enTranslation = {
downloadingTracks: 'Caching {{n}} tracks…',
offlineLibrary: 'Offline Library',
genres: 'Genres',
playlists: 'Playlists',
},
home: {
starred: 'Personal Favorites',
@@ -100,6 +101,7 @@ const enTranslation = {
openAlbum: 'Open Album',
goToArtist: 'Go to Artist',
download: 'Download (ZIP)',
addToPlaylist: 'Add to Playlist',
},
albumDetail: {
back: 'Back',
@@ -591,6 +593,32 @@ const enTranslation = {
lyrics: 'Lyrics',
lyricsLoading: 'Loading lyrics…',
lyricsNotFound: 'No lyrics found for this track',
},
playlists: {
title: 'Playlists',
newPlaylist: 'New Playlist',
unnamed: 'Unnamed Playlist',
createName: 'Playlist name…',
create: 'Create',
cancel: 'Cancel',
empty: 'No playlists yet.',
emptyPlaylist: 'This playlist is empty.',
notFound: 'Playlist not found.',
songs: '{{n}} songs',
playAll: 'Play All',
addToQueue: 'Add to Queue',
back: 'Back to Playlists',
deletePlaylist: 'Delete',
confirmDelete: 'Click again to confirm',
removeSong: 'Remove from playlist',
addSongs: 'Add Songs',
searchPlaceholder: 'Search your library…',
noResults: 'No results.',
suggestions: 'Suggested Songs',
noSuggestions: 'No suggestions available.',
titleBadge: 'Playlist',
refreshSuggestions: 'New suggestions',
addSong: 'Add to playlist',
}
};
@@ -618,6 +646,7 @@ const deTranslation = {
downloadingTracks: '{{n}} Tracks werden gecacht…',
offlineLibrary: 'Offline-Bibliothek',
genres: 'Genres',
playlists: 'Playlists',
},
home: {
starred: 'Persönliche Favoriten',
@@ -693,6 +722,7 @@ const deTranslation = {
openAlbum: 'Album öffnen',
goToArtist: 'Zum Künstler',
download: 'Herunterladen (ZIP)',
addToPlaylist: 'Zur Playlist hinzufügen',
},
albumDetail: {
back: 'Zurück',
@@ -1184,6 +1214,32 @@ const deTranslation = {
lyrics: 'Lyrics',
lyricsLoading: 'Lyrics werden geladen…',
lyricsNotFound: 'Keine Lyrics für diesen Titel gefunden',
},
playlists: {
title: 'Playlists',
newPlaylist: 'Neue Playlist',
unnamed: 'Unbenannte Playlist',
createName: 'Playlist-Name…',
create: 'Erstellen',
cancel: 'Abbrechen',
empty: 'Noch keine Playlists.',
emptyPlaylist: 'Diese Playlist ist leer.',
notFound: 'Playlist nicht gefunden.',
songs: '{{n}} Songs',
playAll: 'Alle abspielen',
addToQueue: 'Zur Warteschlange',
back: 'Zurück zu Playlists',
deletePlaylist: 'Löschen',
confirmDelete: 'Nochmals klicken zum Bestätigen',
removeSong: 'Aus Playlist entfernen',
addSongs: 'Songs hinzufügen',
searchPlaceholder: 'Bibliothek durchsuchen…',
noResults: 'Keine Ergebnisse.',
suggestions: 'Vorgeschlagene Songs',
noSuggestions: 'Keine Vorschläge verfügbar.',
titleBadge: 'Playlist',
refreshSuggestions: 'Neue Vorschläge',
addSong: 'Zur Playlist hinzufügen',
}
};
@@ -1211,6 +1267,7 @@ const frTranslation = {
downloadingTracks: '{{n}} pistes en cache…',
offlineLibrary: 'Bibliothèque hors ligne',
genres: 'Genres',
playlists: 'Playlists',
},
home: {
starred: 'Favoris personnels',
@@ -1286,6 +1343,7 @@ const frTranslation = {
openAlbum: 'Ouvrir l\'album',
goToArtist: 'Aller à l\'artiste',
download: 'Télécharger (ZIP)',
addToPlaylist: 'Ajouter à la playlist',
},
albumDetail: {
back: 'Retour',
@@ -1777,6 +1835,32 @@ const frTranslation = {
lyrics: 'Paroles',
lyricsLoading: 'Chargement des paroles…',
lyricsNotFound: 'Aucune parole trouvée pour ce titre',
},
playlists: {
title: 'Playlists',
newPlaylist: 'Nouvelle playlist',
unnamed: 'Playlist sans nom',
createName: 'Nom de la playlist…',
create: 'Créer',
cancel: 'Annuler',
empty: 'Aucune playlist pour l\'instant.',
emptyPlaylist: 'Cette playlist est vide.',
notFound: 'Playlist introuvable.',
songs: '{{n}} titres',
playAll: 'Tout lire',
addToQueue: 'Ajouter à la file',
back: 'Retour aux playlists',
deletePlaylist: 'Supprimer',
confirmDelete: 'Cliquer à nouveau pour confirmer',
removeSong: 'Retirer de la playlist',
addSongs: 'Ajouter des titres',
searchPlaceholder: 'Rechercher dans la bibliothèque…',
noResults: 'Aucun résultat.',
suggestions: 'Titres suggérés',
noSuggestions: 'Aucune suggestion disponible.',
titleBadge: 'Playlist',
refreshSuggestions: 'Nouvelles suggestions',
addSong: 'Ajouter à la playlist',
}
};
@@ -1804,6 +1888,7 @@ const nlTranslation = {
downloadingTracks: '{{n}} nummers worden gecached…',
offlineLibrary: 'Offline bibliotheek',
genres: 'Genres',
playlists: 'Playlists',
},
home: {
starred: 'Persoonlijke favorieten',
@@ -1879,6 +1964,7 @@ const nlTranslation = {
openAlbum: 'Album openen',
goToArtist: 'Naar artiest',
download: 'Downloaden (ZIP)',
addToPlaylist: 'Toevoegen aan playlist',
},
albumDetail: {
back: 'Terug',
@@ -2370,6 +2456,32 @@ const nlTranslation = {
lyrics: 'Songtekst',
lyricsLoading: 'Songtekst laden…',
lyricsNotFound: 'Geen songtekst gevonden voor dit nummer',
},
playlists: {
title: 'Playlists',
newPlaylist: 'Nieuwe playlist',
unnamed: 'Naamloze playlist',
createName: 'Playlistnaam…',
create: 'Aanmaken',
cancel: 'Annuleren',
empty: 'Nog geen playlists.',
emptyPlaylist: 'Deze playlist is leeg.',
notFound: 'Playlist niet gevonden.',
songs: '{{n}} nummers',
playAll: 'Alles afspelen',
addToQueue: 'Aan wachtrij toevoegen',
back: 'Terug naar playlists',
deletePlaylist: 'Verwijderen',
confirmDelete: 'Nogmaals klikken om te bevestigen',
removeSong: 'Uit playlist verwijderen',
addSongs: 'Nummers toevoegen',
searchPlaceholder: 'Doorzoek bibliotheek…',
noResults: 'Geen resultaten.',
suggestions: 'Aanbevolen nummers',
noSuggestions: 'Geen suggesties beschikbaar.',
titleBadge: 'Playlist',
refreshSuggestions: 'Nieuwe suggesties',
addSong: 'Toevoegen aan playlist',
}
};
@@ -2397,6 +2509,7 @@ const zhTranslation = {
downloadingTracks: '正在缓存 {{n}} 首歌曲…',
offlineLibrary: '离线音乐库',
genres: '流派',
playlists: '播放列表',
},
home: {
starred: '个人收藏',
@@ -2472,6 +2585,7 @@ const zhTranslation = {
openAlbum: '打开专辑',
goToArtist: '前往艺术家',
download: '下载 (ZIP)',
addToPlaylist: '添加到播放列表',
},
albumDetail: {
back: '返回',
@@ -2963,6 +3077,32 @@ const zhTranslation = {
lyrics: '歌词',
lyricsLoading: '正在加载歌词…',
lyricsNotFound: '未找到此曲目的歌词',
},
playlists: {
title: '播放列表',
newPlaylist: '新建播放列表',
unnamed: '未命名播放列表',
createName: '播放列表名称…',
create: '创建',
cancel: '取消',
empty: '暂无播放列表。',
emptyPlaylist: '此播放列表为空。',
notFound: '未找到播放列表。',
songs: '{{n}} 首歌曲',
playAll: '全部播放',
addToQueue: '添加到队列',
back: '返回播放列表',
deletePlaylist: '删除',
confirmDelete: '再次点击确认删除',
removeSong: '从播放列表中移除',
addSongs: '添加歌曲',
searchPlaceholder: '搜索音乐库…',
noResults: '无结果。',
suggestions: '推荐歌曲',
noSuggestions: '暂无推荐。',
titleBadge: '播放列表',
refreshSuggestions: '新建议',
addSong: '添加到播放列表',
}
};