fix(qconnect): treat remote queue tracks as qobuz playback
cx
This commit is contained in:
5 files changed
+88
-10
No files matched your search
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user