From bded788431ece86c01b6c7b5ad8070bd870365a6 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Wed, 25 Mar 2026 12:59:27 +0100 Subject: [PATCH] feat: optimize lazy PK resolution and fix OpenHome IdList delimiter - In track_metadata.rs: cache real_pk at construction time to avoid repeated DB queries per metadata field access. - In openhome_client.rs: change IdList delimiter from comma to space per OpenHome spec. --- pmoaudiocache/src/track_metadata.rs | 32 +++++++++++-------- .../src/upnp_clients/openhome_client.rs | 3 +- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/pmoaudiocache/src/track_metadata.rs b/pmoaudiocache/src/track_metadata.rs index 2831922a..582748fb 100644 --- a/pmoaudiocache/src/track_metadata.rs +++ b/pmoaudiocache/src/track_metadata.rs @@ -20,6 +20,9 @@ fn map_db_err(err: rusqlite::Error) -> MetadataError { pub struct AudioCacheTrackMetadata { cache: Arc, pk: String, + /// Real pk si le lazy pk a été téléchargé, None sinon. + /// Résolu une seule fois à la construction pour éviter N appels DB par champ. + real_pk: Option, } impl AudioCacheTrackMetadata { @@ -28,24 +31,25 @@ impl AudioCacheTrackMetadata { /// Le type implémente ensuite toutes les méthodes du trait `pmometadata::TrackMetadata` /// en stockant les données dans la base SQLite de `pmocache`. pub fn new(cache: Arc, pk: impl Into) -> Self { - Self { - cache, - pk: pk.into(), - } + let pk_str: String = pk.into(); + // Résolution lazy→real une seule fois à la construction (une seule query DB). + let real_pk = if pmocache::is_lazy_pk(&pk_str) { + cache.db.get_pk_by_lazy_pk(&pk_str).ok().flatten() + } else { + None + }; + Self { cache, pk: pk_str, real_pk } } fn read_raw(&self, key: &str) -> Result, MetadataError> { - // Si le pk est un lazy pk déjà téléchargé (pk != lazy_pk dans l'asset), - // lire d'abord sous le real_pk (métadonnées écrites par FlacCacheSink), - // puis fallback sous le lazy_pk (cover_pk, qobuz_track_id semés à l'enregistrement). - if pmocache::is_lazy_pk(&self.pk) { - if let Ok(Some(real_pk)) = self.cache.db.get_pk_by_lazy_pk(&self.pk) { - if let Ok(Some(v)) = self.cache.db.get_a_metadata(&real_pk, key) { - return Ok(Some(v)); - } - // Fallback vers lazy_pk pour les clés semées avant téléchargement (cover_pk, etc.) - return self.cache.db.get_a_metadata(&self.pk, key).map_err(map_db_err); + // Si le lazy pk a été téléchargé, lire d'abord sous le real_pk + // (métadonnées écrites par FlacCacheSink), puis fallback sous le lazy_pk + // pour les clés semées avant téléchargement (cover_pk, etc.). + if let Some(real_pk) = &self.real_pk { + if let Ok(Some(v)) = self.cache.db.get_a_metadata(real_pk, key) { + return Ok(Some(v)); } + return self.cache.db.get_a_metadata(&self.pk, key).map_err(map_db_err); } self.cache .db diff --git a/pmocontrol/src/upnp_clients/openhome_client.rs b/pmocontrol/src/upnp_clients/openhome_client.rs index fc9bd3f4..dd8080d3 100644 --- a/pmocontrol/src/upnp_clients/openhome_client.rs +++ b/pmocontrol/src/upnp_clients/openhome_client.rs @@ -185,11 +185,12 @@ impl OhPlaylistClient { return Ok(Vec::new()); } + // OpenHome spec: IdList is space-delimited (not comma-delimited) let id_list_csv = id_list .iter() .map(|id| id.to_string()) .collect::>() - .join(","); + .join(" "); let args = [("IdList", id_list_csv.as_str())]; let call_result =