fix(qconnect): treat remote queue tracks as qobuz playback

cx
This commit is contained in:
vicrodh committed 2026-03-12 19:48:17 -06:00
1 parent d3c2d4c6ca
commit a2c4017607
5 files changed
+88 -10

No files matched your search

+9 -6
View File
@@ -11,6 +11,10 @@
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { getUserItem, setUserItem } from '$lib/utils/userStorage'; import { getUserItem, setUserItem } from '$lib/utils/userStorage';
import {
isPlaybackSourceLocal,
resolvePlaybackSource
} from '$lib/services/playbackSource';
/** /**
* Get the preferred streaming quality from localStorage * Get the preferred streaming quality from localStorage
@@ -278,12 +282,11 @@ export async function playTrack(
console.log('Auto-skipping to next track:', next.title); console.log('Auto-skipping to next track:', next.title);
// Small delay to let the toast be visible // Small delay to let the toast be visible
setTimeout(() => { setTimeout(() => {
const nextSource = (next.source === 'plex' || next.source === 'local' || next.source === 'qobuz') const nextSource = resolvePlaybackSource(next);
? next.source const nextIsLocal = isPlaybackSourceLocal(nextSource, next.is_local ?? false);
: (next.is_local ? 'local' : 'qobuz');
const nextSamplingRate = next.sample_rate == null const nextSamplingRate = next.sample_rate == null
? undefined ? undefined
: (next.is_local || nextSource === 'plex') : nextIsLocal
? next.sample_rate / 1000 ? next.sample_rate / 1000
: next.sample_rate; : next.sample_rate;
playTrack({ playTrack({
@@ -299,9 +302,9 @@ export async function playTrack(
bitDepth: next.bit_depth || undefined, bitDepth: next.bit_depth || undefined,
samplingRate: nextSamplingRate, samplingRate: nextSamplingRate,
source: nextSource, source: nextSource,
isLocal: next.is_local isLocal: nextIsLocal
}, { }, {
isLocal: next.is_local ?? false, isLocal: nextIsLocal,
source: nextSource, source: nextSource,
showLoadingToast: true, showLoadingToast: true,
showSuccessToast: true showSuccessToast: true
+38
View File
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest';
import {
isPlaybackSourceLocal,
resolvePlaybackSource
} from './playbackSource';
describe('playbackSource', () => {
it('treats qobuz_connect_remote as remote Qobuz playback', () => {
const source = resolvePlaybackSource({
source: 'qobuz_connect_remote',
is_local: false
});
expect(source).toBe('qobuz');
expect(isPlaybackSourceLocal(source, false)).toBe(false);
});
it('keeps downloaded Qobuz tracks on the local playback path', () => {
const source = resolvePlaybackSource({
source: 'qobuz_download',
is_local: false
});
expect(source).toBe('local');
expect(isPlaybackSourceLocal(source, false)).toBe(true);
});
it('falls back to local playback when the backend marks a track as local', () => {
const source = resolvePlaybackSource({
source: undefined,
is_local: true
});
expect(source).toBe('local');
expect(isPlaybackSourceLocal(source, false)).toBe(true);
});
});
+29
View File
@@ -0,0 +1,29 @@
export type PlaybackSource = 'qobuz' | 'local' | 'plex';
type SourceCandidate = {
source?: string | null;
is_local?: boolean | null;
isLocal?: boolean | null;
};
export function resolvePlaybackSource(candidate: SourceCandidate): PlaybackSource {
const source = (candidate.source ?? '').toLowerCase();
if (source === 'plex') return 'plex';
if (source === 'local' || source === 'qobuz_download') return 'local';
if (source === 'qobuz' || source === 'qobuz_connect_remote') return 'qobuz';
if (candidate.is_local === true || candidate.isLocal === true) {
return 'local';
}
return 'qobuz';
}
export function isPlaybackSourceLocal(source: PlaybackSource, knownLocalTrack = false): boolean {
if (source === 'local' || source === 'plex') {
return true;
}
return knownLocalTrack;
}
+6 -2
View File
@@ -279,6 +279,10 @@
updateLastfmNowPlaying, updateLastfmNowPlaying,
cleanup as cleanupPlayback cleanup as cleanupPlayback
} from '$lib/services/playbackService'; } from '$lib/services/playbackService';
import {
isPlaybackSourceLocal,
resolvePlaybackSource
} from '$lib/services/playbackSource';
import { import {
queueTrackNext, queueTrackNext,
@@ -2168,8 +2172,8 @@
// Helper to play a track from the queue (with offline skip support) // Helper to play a track from the queue (with offline skip support)
async function playQueueTrack(track: BackendQueueTrack, skippedIds = new Set<number>(), gaplessTransition = false) { async function playQueueTrack(track: BackendQueueTrack, skippedIds = new Set<number>(), gaplessTransition = false) {
const source = track.source ?? (track.is_local ? 'local' : 'qobuz'); const source = resolvePlaybackSource(track);
const isLocal = source !== 'qobuz' || isLocalTrack(track.id); const isLocal = isPlaybackSourceLocal(source, isLocalTrack(track.id));
// In offline mode, check if track is available // In offline mode, check if track is available
if (offlineStatus.isOffline && !isLocal) { if (offlineStatus.isOffline && !isLocal) {
+6 -2
View File
@@ -55,6 +55,10 @@
handleKeydown as keybindingHandler handleKeydown as keybindingHandler
} from '$lib/stores/keybindingsStore'; } from '$lib/stores/keybindingsStore';
import { playTrack } from '$lib/services/playbackService'; import { playTrack } from '$lib/services/playbackService';
import {
isPlaybackSourceLocal,
resolvePlaybackSource
} from '$lib/services/playbackSource';
let playerState = $state<PlayerState>(getPlayerState()); let playerState = $state<PlayerState>(getPlayerState());
let queueState = $state<QueueState>(getQueueState()); let queueState = $state<QueueState>(getQueueState());
@@ -312,8 +316,8 @@
} }
async function playQueueTrack(track: BackendQueueTrack): Promise<void> { async function playQueueTrack(track: BackendQueueTrack): Promise<void> {
const source = track.source ?? (track.is_local ? 'local' : 'qobuz'); const source = resolvePlaybackSource(track);
const isLocal = source !== 'qobuz'; const isLocal = isPlaybackSourceLocal(source, track.is_local ?? false);
const quality = isLocal const quality = isLocal
? 'Local' ? 'Local'
: track.bit_depth && track.sample_rate : track.bit_depth && track.sample_rate