qconnect: allow offline-cache to be cast (one consistent rule)
Three sites disagreed: model blocked OfflineCache, live gate allowed it, TS sync filter blocked qobuz_download. Decision: ALLOW — an offline copy's queue id is the real Qobuz track id. Flip the TS sync filter and fix the stale model doc comment to match the live gate. Also add Rust lock-in tests (offline_cache_is_castable / offline_cache_is_admitted) and restore the missing $app/environment vitest mock the config already aliases, so queuePlaybackService.test.ts can load. cc
This commit is contained in:
5 files changed
+47
-7
No files matched your search
@@ -9,8 +9,8 @@
|
||||
//! This is the frontend-agnostic contract behind the source-aware playback
|
||||
//! context: the now-playing bar, the queue, and the artwork pipeline consume
|
||||
//! `PlaybackSource` + [`ArtworkRef`] and never special-case a source themselves.
|
||||
//! The same contract drives the Qobuz Connect queue gate (only Qobuz-streamable
|
||||
//! tracks may be cast — see [`PlaybackSource::is_qobuz_streamable`]).
|
||||
//! The same contract drives the Qobuz Connect queue gate (only castable tracks
|
||||
//! may be cast — see [`PlaybackSource::is_castable_to_qconnect`]).
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -54,10 +54,9 @@ impl PlaybackSource {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this source streams from Qobuz and may therefore be cast onto
|
||||
/// a Qobuz Connect queue. Offline-cache copies, local files, and Plex are
|
||||
/// **not** castable to a Qobuz Connect receiver — this is the first-class
|
||||
/// gate the queue pipeline consults before syncing to Qobuz Connect.
|
||||
/// Whether this source streams live from the Qobuz catalog. NOTE: NOT the
|
||||
/// cast gate — offline-cache also carries a valid Qobuz id and IS castable.
|
||||
/// Use is_castable_to_qconnect for the Qobuz Connect gate.
|
||||
pub fn is_qobuz_streamable(self) -> bool {
|
||||
matches!(self, Self::Qobuz)
|
||||
}
|
||||
@@ -193,6 +192,12 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offline_cache_is_castable() {
|
||||
assert!(PlaybackSource::OfflineCache.is_castable_to_qconnect());
|
||||
assert!(TrackOriginTag::OfflineCache.is_castable_to_qconnect());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strict_parse_blocks_unknown_and_absent() {
|
||||
use TrackOriginTag::*;
|
||||
|
||||
@@ -82,4 +82,9 @@ mod tests {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offline_cache_is_admitted() {
|
||||
assert!(evaluate_remote_queue_admission(TrackOrigin::QobuzOfflineCache).accepted);
|
||||
}
|
||||
}
|
||||
@@ -66,3 +66,24 @@ describe('assessQconnectQueueSync', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const track = (over: Partial<BackendQueueTrack>): BackendQueueTrack =>
|
||||
({ id: 1, title: 't', artist: 'a', album: 'al', duration_secs: 0, artwork_url: null,
|
||||
hires: false, bit_depth: null, sample_rate: null, is_local: false, album_id: null,
|
||||
artist_id: null, streamable: true, source: 'qobuz', parental_warning: false, ...over }) as BackendQueueTrack;
|
||||
|
||||
describe('assessQconnectQueueSync — offline-cache', () => {
|
||||
it('treats qobuz_download as syncable (offline copy carries a Qobuz id)', () => {
|
||||
const r = assessQconnectQueueSync([track({ id: 5, source: 'qobuz_download' })]);
|
||||
expect(r.syncable).toBe(true);
|
||||
expect(r.trackIds).toEqual([5]);
|
||||
expect(r.blockedTrackIds).toEqual([]);
|
||||
});
|
||||
it('still blocks local and plex', () => {
|
||||
const r = assessQconnectQueueSync([
|
||||
track({ id: 1, source: 'qobuz' }), track({ id: 2, source: 'local' }),
|
||||
]);
|
||||
expect(r.syncable).toBe(false);
|
||||
expect(r.blockedTrackIds).toContain(2);
|
||||
});
|
||||
});
|
||||
@@ -23,7 +23,8 @@ function isQconnectSyncEligibleTrack(track: BackendQueueTrack): boolean {
|
||||
if (track.is_local) return false;
|
||||
|
||||
const source = (track.source ?? '').toLowerCase();
|
||||
if (source === 'local' || source === 'plex' || source === 'qobuz_download') {
|
||||
// Offline-cache (qobuz_download) IS eligible: its id is the real Qobuz id.
|
||||
if (source === 'local' || source === 'plex') {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// Test mock for SvelteKit's `$app/environment`.
|
||||
// The vitest config aliases `$app` to this directory, but the module was never
|
||||
// created, so any test whose import graph reaches `$app/environment` (e.g. via
|
||||
// the i18n module) failed to load. This provides the minimal surface the app uses.
|
||||
export const browser = false;
|
||||
export const dev = false;
|
||||
export const building = false;
|
||||
export const version = 'test';
|
||||
Reference in new issue
Block a user