From 499b77879d9565ca850461562df985faf5eac073 Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Mon, 1 Jun 2026 01:49:15 -0600 Subject: [PATCH] qconnect: strict source parse for admission (unknown -> blocked) Admission must do the opposite of from_source_str: add from_source_str_strict returning TrackOriginTag::ExternalUnknown so an untagged local/Plex row can never be cast. cc --- crates/qbz-models/src/lib.rs | 2 +- crates/qbz-models/src/source.rs | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/crates/qbz-models/src/lib.rs b/crates/qbz-models/src/lib.rs index 9e4f79801..cbc2c542b 100644 --- a/crates/qbz-models/src/lib.rs +++ b/crates/qbz-models/src/lib.rs @@ -41,7 +41,7 @@ pub mod types; pub use error::{QbzError, QbzResult}; pub use events::CoreEvent; pub use playback::{PlaybackState, PlaybackStatus, QueueState, QueueTrack, RepeatMode}; -pub use source::{ArtworkRef, PlaybackSource}; +pub use source::{ArtworkRef, PlaybackSource, TrackOriginTag}; pub use traits::{FrontendAdapter, LoggingAdapter, NoOpAdapter}; pub use types::{ Album, diff --git a/crates/qbz-models/src/source.rs b/crates/qbz-models/src/source.rs index 42e101977..bfbadef2d 100644 --- a/crates/qbz-models/src/source.rs +++ b/crates/qbz-models/src/source.rs @@ -70,6 +70,36 @@ impl PlaybackSource { } } +/// Admission-only origin tag. Unlike PlaybackSource, this has ExternalUnknown +/// so the Qobuz Connect gate can default unknown/absent to *blocked* not *Qobuz*. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum TrackOriginTag { + Qobuz, + OfflineCache, + Local, + Plex, + ExternalUnknown, +} + +impl PlaybackSource { + /// Strict parse for the admission path: unknown/absent → ExternalUnknown (blocked). + pub fn from_source_str_strict(s: Option<&str>) -> TrackOriginTag { + match s { + Some("qobuz") => TrackOriginTag::Qobuz, + Some("qobuz_download") => TrackOriginTag::OfflineCache, + Some("local") => TrackOriginTag::Local, + Some("plex") => TrackOriginTag::Plex, + _ => TrackOriginTag::ExternalUnknown, + } + } +} + +impl TrackOriginTag { + pub fn is_castable_to_qconnect(self) -> bool { + matches!(self, Self::Qobuz | Self::OfflineCache) + } +} + /// A reference to a piece of cover art, resolvable regardless of origin. /// /// The artwork loaders historically handled only remote HTTP URLs, which is @@ -163,6 +193,19 @@ mod tests { } } + #[test] + fn strict_parse_blocks_unknown_and_absent() { + use TrackOriginTag::*; + assert_eq!(PlaybackSource::from_source_str_strict(Some("qobuz")), Qobuz); + assert_eq!(PlaybackSource::from_source_str_strict(Some("local")), Local); + assert_eq!(PlaybackSource::from_source_str_strict(Some("plex")), Plex); + assert_eq!(PlaybackSource::from_source_str_strict(Some("qobuz_download")), OfflineCache); + assert_eq!(PlaybackSource::from_source_str_strict(None), ExternalUnknown); + assert_eq!(PlaybackSource::from_source_str_strict(Some("???")), ExternalUnknown); + // Lenient parser still defaults to Qobuz (playback compatibility). + assert_eq!(PlaybackSource::from_source_str(None), PlaybackSource::Qobuz); + } + #[test] fn only_qobuz_is_castable() { assert!(PlaybackSource::Qobuz.is_qobuz_streamable());