feat: add Qobuz playlist caching with versioning and infinite scroll UI

- Add qobuz_debug to .gitignore
- Bump PMOMusic version to 0.3.26
- Add .cargo/ copy in Dockerfile for registry config
- Implement infinite scroll in ServerDrawer.vue with IntersectionObserver and sentinel element
- Add source/source_version fields to playlists for cache invalidation
- Update pmocache and pmoplaylist DB schemas with versioning (SCHEMA_VERSION)
- Add Qobuz API metadata fetching and pagination for playlist tracks
- Implement album/playlist cache invalidation based on released_at/updated_at timestamps
- Refactor adapt_playlist_items_to_qobuz → adapt_items_to_qobuz with cleaner logic
- Add debug mode to save Qobuz API responses when QOBUZ_DEBUG_DIR is set
This commit is contained in:
2026-03-24 17:10:38 +01:00
parent 402c3399e4
commit 0137a4675f
17 changed files with 688 additions and 160 deletions

View File

@@ -215,6 +215,8 @@ impl PlaylistManager {
&role,
cover_pk.as_deref(),
artist.as_deref(),
None,
None,
&core.config,
&core.tracks,
)
@@ -522,7 +524,7 @@ impl PlaylistManager {
// Pas en mémoire, essayer de charger depuis la DB
if let Some(persistence) = &self.inner.persistence {
if let Some((title, role, config, cover_pk, artist, tracks)) =
if let Some((title, role, config, cover_pk, artist, source, source_version, tracks)) =
persistence.load_playlist(&id).await?
{
// Reconstruire la playlist
@@ -537,10 +539,16 @@ impl PlaylistManager {
cover_pk,
));
// Restaurer l'artiste si présent
// Restaurer les métadonnées optionnelles
if let Some(artist_name) = artist {
playlist.set_artist(Some(artist_name)).await;
}
if source.is_some() {
playlist.set_source(source).await;
}
if source_version.is_some() {
playlist.set_source_version(source_version).await;
}
// Restaurer les tracks
{
@@ -583,7 +591,7 @@ impl PlaylistManager {
// Pas en m<>moire, essayer de ressusciter depuis la DB
if let Some(persistence) = &self.inner.persistence {
if let Some((title, role, config, cover_pk, artist, tracks)) =
if let Some((title, role, config, cover_pk, artist, source, source_version, tracks)) =
persistence.load_playlist(id).await?
{
// Reconstruire la playlist
@@ -598,10 +606,16 @@ impl PlaylistManager {
cover_pk,
));
// Restaurer l'artiste si présent
// Restaurer les métadonnées optionnelles
if let Some(artist_name) = artist {
playlist.set_artist(Some(artist_name)).await;
}
if source.is_some() {
playlist.set_source(source).await;
}
if source_version.is_some() {
playlist.set_source_version(source_version).await;
}
// Restaurer les tracks
{
@@ -995,6 +1009,8 @@ impl PlaylistManager {
let role = playlist.role().await;
let cover_pk = playlist.cover_pk().await;
let artist = playlist.artist().await;
let source = playlist.source().await;
let source_version = playlist.source_version().await;
let core = playlist.core.read().await;
let _ = persistence
.save_playlist(
@@ -1003,6 +1019,8 @@ impl PlaylistManager {
&role,
cover_pk.as_deref(),
artist.as_deref(),
source.as_deref(),
source_version.as_deref(),
&core.config,
&core.tracks,
)