mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
c165669db5
Add source badges for offline, cache, and stream playback in the queue tech line, including localized tooltips across shipped locales. Track Rust preload-ready events by stream track id and latch the selected source per track, with dev logs to debug preload/source mismatches during next-track handoff.
64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import { buildStreamUrl } from '../api/subsonic';
|
|
import { useOfflineStore } from '../store/offlineStore';
|
|
import { useHotCacheStore } from '../store/hotCacheStore';
|
|
|
|
/** Same resolution order as {@link resolvePlaybackUrl} — for UI hints only. */
|
|
export type PlaybackSourceKind = 'offline' | 'hot' | 'stream';
|
|
|
|
/**
|
|
* Subsonic `buildStreamUrl()` rotates `t`/`s` on every call; Rust matches by `id` (see `playback_identity`).
|
|
*/
|
|
export function streamUrlTrackId(url: string): string | null {
|
|
if (!url.includes('stream.view')) return null;
|
|
try {
|
|
const fromUrl = new URL(url).searchParams.get('id');
|
|
if (fromUrl) return fromUrl;
|
|
} catch {
|
|
// Fallback for non-standard/relative URLs: parse query manually.
|
|
}
|
|
const q = url.split('?')[1];
|
|
if (!q) return null;
|
|
for (const part of q.split('&')) {
|
|
const [k, v = ''] = part.split('=');
|
|
if (k === 'id') {
|
|
try {
|
|
return decodeURIComponent(v);
|
|
} catch {
|
|
return v;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param enginePreloadedTrackId — song id for which `audio_preload` finished into the engine RAM slot
|
|
* (parsed from `audio:preload-ready` payload URL).
|
|
*/
|
|
export function getPlaybackSourceKind(
|
|
trackId: string,
|
|
serverId: string,
|
|
enginePreloadedTrackId: string | null = null,
|
|
): PlaybackSourceKind {
|
|
if (useOfflineStore.getState().getLocalUrl(trackId, serverId)) return 'offline';
|
|
if (useHotCacheStore.getState().getLocalUrl(trackId, serverId)) return 'hot';
|
|
const resolved = resolvePlaybackUrl(trackId, serverId);
|
|
if (
|
|
!resolved.startsWith('psysonic-local://')
|
|
&& enginePreloadedTrackId
|
|
&& trackId === enginePreloadedTrackId
|
|
) {
|
|
return 'hot';
|
|
}
|
|
return 'stream';
|
|
}
|
|
|
|
/** Offline library → hot playback cache → HTTP stream. */
|
|
export function resolvePlaybackUrl(trackId: string, serverId: string): string {
|
|
const offline = useOfflineStore.getState().getLocalUrl(trackId, serverId);
|
|
if (offline) return offline;
|
|
const hot = useHotCacheStore.getState().getLocalUrl(trackId, serverId);
|
|
if (hot) return hot;
|
|
return buildStreamUrl(trackId);
|
|
}
|