Files
Psychotoxical-psysonic/src/features/playback/store/pausedRestorePrepare.ts
T
Psychotoxical f41005682d refactor(playback): move thin-state queue resolver out of utils/library into the feature
The queue-resolver family (queueTrackResolver, queueRestore, queueItemRef,
queueTrackView) runtime-imports usePlayerStore / playerStoreTypes — it is the
playback engine's thin-state queue subsystem, not shared library infra. It sat
in utils/library only because it queries the local index. Co-locate into
features/playback/store so those edges become intra-feature; its remaining deps
(advancedSearchLocal, libraryReady, serverLookup, serverIndexKey, authStore) are
plain core/infra (feature -> infra, no inversion).

Removes 4 of the 6 store/utils -> feature runtime inversions that blocked the
utils/library -> lib move. 8 files moved, 46 consumers rewritten. tsc 0, lint 0,
targeted suites green.
2026-06-30 16:50:29 +02:00

76 lines
2.8 KiB
TypeScript

import type { QueueItemRef, Track } from '@/features/playback/store/playerStoreTypes';
import { getQueueTracksView } from '@/features/playback/store/queueTrackView';
import { scheduleHotCachePrefetchForTrack } from '@/hotCachePrefetch';
import { getPlaybackCacheServerKey } from '@/features/playback/utils/playback/playbackServer';
import { useAuthStore } from '@/store/authStore';
import { bumpPlayGeneration, getPlayGeneration } from '@/features/playback/store/engineState';
import { engineLoadTrackAtPosition } from '@/features/playback/store/engineLoadTrackAtPosition';
import { emitPlaybackProgress } from '@/features/playback/store/playbackProgress';
import { promoteCompletedStreamToHotCache } from '@/features/playback/store/promoteStreamCache';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import { setSeekFallbackVisualTarget } from '@/features/playback/store/seekFallbackState';
/** Push restored position into the store + progress channel so the seekbar paints immediately. */
export function applyRestoredPlaybackVisual(track: Track, atSeconds: number): void {
const dur = track.duration > 0 ? track.duration : 0;
const seconds = Math.max(0, atSeconds);
const progress = dur > 0 ? Math.min(1, seconds / dur) : 0;
usePlayerStore.setState({ currentTime: seconds, progress, buffered: 0 });
emitPlaybackProgress({
currentTime: seconds,
progress,
buffered: 0,
buffering: false,
});
if (seconds > 0.05) {
setSeekFallbackVisualTarget({
trackId: track.id,
seconds,
setAtMs: Date.now(),
});
}
}
/**
* After `getPlayQueue` restores a paused session: show the saved seek position,
* prefetch bytes for the current track, and load the engine paused at that spot
* so the next Play is a warm `audio_resume`.
*/
export function preparePausedRestoreOnStartup(
track: Track,
queueItems: QueueItemRef[],
queueIndex: number,
atSeconds: number,
): void {
const player = usePlayerStore.getState();
if (player.isPlaying || player.currentRadio) return;
applyRestoredPlaybackVisual(track, atSeconds);
scheduleHotCachePrefetchForTrack(track, getPlaybackCacheServerKey());
const generation = bumpPlayGeneration();
void (async () => {
const auth = useAuthStore.getState();
const promoteSid = getPlaybackCacheServerKey();
if (auth.hotCacheEnabled && promoteSid) {
await promoteCompletedStreamToHotCache(
track,
promoteSid,
auth.hotCacheDownloadDir || null,
);
}
if (getPlayGeneration() !== generation) return;
if (usePlayerStore.getState().isPlaying) return;
const queue = getQueueTracksView(queueItems, [track]);
engineLoadTrackAtPosition({
generation,
track,
queue,
queueIndex,
atSeconds,
wantPlaying: false,
});
})();
}