refactor(lib): move songToTrack + pure server-scope helpers to lib/media; split trackServerScope

songToTrack (the canonical Subsonic-song -> Track mapper) and the pure
server-scope helpers (activeServerProfileId, stampTrackServerId/s,
isMultiServerQueue, profileIdFromQueueRef) operate only on the lib/media model +
authStore + server-key utils -- no playback-store read. Move them to lib/media so
the ~58 app-wide consumers (cover, context menus, sharing, lucky-mix, library
browse, pages, hooks) depend on lib, not on the playback feature.

trackServerScope is split: the store-reading queue helpers (queueItemRefAt,
filterQueueRefs*, activeServerQueueTrackIds) stay in
features/playback/utils/playback/trackServerScope and build on the pure lib half.

With Track/QueueItemRef (prior commit), songToTrack and shuffleArray now in lib,
the media-domain model is fully out of features/playback. The remaining
playerStoreTypes imports are PlayerState only (the store shape). tsc 0, lint 0,
full suite 2353/2353, build OK.
This commit is contained in:
Psychotoxical
2026-06-30 17:24:29 +02:00
parent 9058abd340
commit 572dce4703
65 changed files with 123 additions and 102 deletions
@@ -11,7 +11,7 @@ vi.mock('@/utils/server/serverLookup', () => ({
resolveServerIdForIndexKey: (id: string) => id,
}));
vi.mock('@/features/playback/utils/playback/songToTrack', () => ({
vi.mock('@/lib/media/songToTrack', () => ({
songToTrack: (s: { id: string }) => ({
id: s.id,
title: s.id,
@@ -1,5 +1,5 @@
import { getPlayQueueForServer, type PlayQueueResult } from '@/lib/api/subsonicPlayQueue';
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
import { songToTrack } from '@/lib/media/songToTrack';
import { bindQueueServerId } from '@/features/playback/utils/playback/playbackServer';
import { resolveServerIdForIndexKey } from '@/utils/server/serverLookup';
import { toQueueItemRefs } from '@/features/playback/store/queueItemRef';
+1 -1
View File
@@ -1,7 +1,7 @@
import { getSimilarSongs2, getTopSongs } from '@/lib/api/subsonicArtists';
import { invoke } from '@tauri-apps/api/core';
import { buildInfiniteQueueCandidates } from '@/features/playback/utils/playback/buildInfiniteQueueCandidates';
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
import { songToTrack } from '@/lib/media/songToTrack';
import { ensureQueueServerPinned } from '@/features/playback/utils/playback/playbackServer';
import { useAuthStore } from '@/store/authStore';
import { setIsAudioPaused } from '@/features/playback/store/engineState';
@@ -39,7 +39,7 @@ vi.mock('@/features/playback/store/queueTrackView', () => ({
vi.mock('@/features/playback/utils/playback/buildInfiniteQueueCandidates', () => ({
buildInfiniteQueueCandidates: vi.fn(() => Promise.resolve([])),
}));
vi.mock('@/features/playback/utils/playback/songToTrack', () => ({ songToTrack: (s: unknown) => s }));
vi.mock('@/lib/media/songToTrack', () => ({ songToTrack: (s: unknown) => s }));
vi.mock('@/features/playback/utils/playback/playbackServer', () => ({ ensureQueueServerPinned: () => null }));
vi.mock('@/features/playback/store/queueTrackResolver', () => ({ seedQueueResolver: vi.fn() }));
vi.mock('@/features/playback/store/queueItemRef', () => ({ toQueueItemRefs: () => [] }));
@@ -26,7 +26,7 @@ import {
playbackProfileIdForTrack,
shouldBindQueueServerForPlay,
} from '@/features/playback/utils/playback/playbackServer';
import { stampTrackServerId, stampTrackServerIds } from '@/features/playback/utils/playback/trackServerScope';
import { stampTrackServerId, stampTrackServerIds } from '@/lib/media/trackServerScope';
import {
findLocalPlaybackUrl,
hasLocalPersistentPlaybackBytes,
+1 -1
View File
@@ -1,5 +1,5 @@
import type { QueueItemRef, Track } from '@/lib/media/trackTypes';
import { stampTrackServerId } from '@/features/playback/utils/playback/trackServerScope';
import { stampTrackServerId } from '@/lib/media/trackServerScope';
import { canonicalQueueServerKey } from '@/utils/server/serverIndexKey';
/**
@@ -2,7 +2,7 @@ import { libraryGetTracksBatch, type TrackRefDto } from '@/lib/api/library';
import { getSongForServer } from '@/lib/api/subsonicLibrary';
import { usePlayerStore } from '@/features/playback/store/playerStore';
import type { QueueItemRef, Track } from '@/lib/media/trackTypes';
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
import { songToTrack } from '@/lib/media/songToTrack';
import { resolveServerIdForIndexKey } from '@/utils/server/serverLookup';
import { canonicalQueueServerKey } from '@/utils/server/serverIndexKey';
import { trackToSong } from '@/lib/library/advancedSearchLocal';
+1 -1
View File
@@ -9,7 +9,7 @@ import {
import { resolvePlaybackUrl } from '@/features/playback/utils/playback/resolvePlaybackUrl';
import { resolveReplayGainDb } from '@/features/playback/utils/audio/resolveReplayGainDb';
import { audioPlayHiResBlendArgs } from '@/utils/audio/hiResCrossfadeResample';
import { songToTrack } from '@/features/playback/utils/playback/songToTrack';
import { songToTrack } from '@/lib/media/songToTrack';
import { useAuthStore } from '@/store/authStore';
import {
bumpPlayGeneration,