mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
refactor(utils): group utils/ files into topic folders (Phase L, part 1) (#689)
111 of 122 top-level src/utils/ files move into 16 topic folders (audio, cache, cover, share, server, playback, playlist, deviceSync, waveform, mix, format, export, changelog, ui, perf, componentHelpers). True singletons with no cluster stay at the utils/ root. Pure file-move: a path-aware codemod rewrote 539 relative-import specifiers across 275 files; no logic touched. The hot-path coverage gate list (.github/frontend-hot-path-files.txt) is updated to the new paths for the 11 gated utils files — a mechanical consequence of the move, not a CI change. tsc is green.
This commit is contained in:
committed by
GitHub
parent
2409a1fec8
commit
7a7a9f5e6b
@@ -5,10 +5,10 @@ import type { NavigateFunction } from 'react-router-dom';
|
||||
import { getSimilarSongs } from '../../api/subsonicArtists';
|
||||
import { getMusicFolders } from '../../api/subsonicLibrary';
|
||||
import { search as subsonicSearch } from '../../api/subsonicSearch';
|
||||
import { shuffleArray } from '../../utils/shuffleArray';
|
||||
import { songToTrack } from '../../utils/songToTrack';
|
||||
import { showToast } from '../../utils/toast';
|
||||
import { switchActiveServer } from '../../utils/switchActiveServer';
|
||||
import { shuffleArray } from '../../utils/playback/shuffleArray';
|
||||
import { songToTrack } from '../../utils/playback/songToTrack';
|
||||
import { showToast } from '../../utils/ui/toast';
|
||||
import { switchActiveServer } from '../../utils/server/switchActiveServer';
|
||||
import i18n from '../../i18n';
|
||||
import { usePlayerStore } from '../../store/playerStore';
|
||||
import { useAuthStore } from '../../store/authStore';
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import type { SubsonicSong } from '../api/subsonicTypes';
|
||||
import { useSelectionStore } from '../store/selectionStore';
|
||||
import { useDragDrop } from '../contexts/DragDropContext';
|
||||
import { songToTrack } from '../utils/songToTrack';
|
||||
import { songToTrack } from '../utils/playback/songToTrack';
|
||||
|
||||
interface UseAlbumTrackListSelectionArgs {
|
||||
songs: SubsonicSong[];
|
||||
|
||||
@@ -5,7 +5,7 @@ import { invoke } from '@tauri-apps/api/core';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { version as currentVersion } from '../../package.json';
|
||||
import { IS_LINUX, IS_MACOS } from '../utils/platform';
|
||||
import { SKIP_KEY, isNewer, pickAsset, type ReleaseData, type DlState } from '../utils/appUpdaterHelpers';
|
||||
import { SKIP_KEY, isNewer, pickAsset, type ReleaseData, type DlState } from '../utils/componentHelpers/appUpdaterHelpers';
|
||||
|
||||
/** All update-modal state, the GitHub release probe and the download/relaunch
|
||||
* handlers. The component owns only the early-return guard and the JSX. */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { SubsonicArtist } from '../api/subsonicTypes';
|
||||
import { usePlayerStore } from '../store/playerStore';
|
||||
import { ALL_SENTINEL, type ArtistListFlatRow } from '../utils/artistsHelpers';
|
||||
import { ALL_SENTINEL, type ArtistListFlatRow } from '../utils/componentHelpers/artistsHelpers';
|
||||
|
||||
interface UseArtistsFilteringArgs {
|
||||
artists: SubsonicArtist[];
|
||||
|
||||
@@ -4,8 +4,8 @@ import { listen } from '@tauri-apps/api/event';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { IS_MACOS } from '../utils/platform';
|
||||
import { sortAudioDeviceIds } from '../utils/audioDeviceLabels';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { sortAudioDeviceIds } from '../utils/audio/audioDeviceLabels';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
|
||||
interface UseAudioDevicesProbeResult {
|
||||
audioDevices: string[];
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { useEqStore } from '../store/eqStore';
|
||||
import { parseFixedBandEqString, type AutoEqVariant, type AutoEqResult } from '../utils/autoEqParse';
|
||||
import { parseFixedBandEqString, type AutoEqVariant, type AutoEqResult } from '../utils/audio/autoEqParse';
|
||||
|
||||
/** AutoEQ search/apply state for the Equalizer. Loads the entries index lazily
|
||||
* when the section opens, filters client-side, and applies fetched profiles via
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { pingWithCredentials, scheduleInstantMixProbeForServer } from '../api/subsonic';
|
||||
import { serverListDisplayLabel } from '../utils/serverDisplayName';
|
||||
import { usePerfProbeFlags } from '../utils/perfFlags';
|
||||
import { serverListDisplayLabel } from '../utils/server/serverDisplayName';
|
||||
import { usePerfProbeFlags } from '../utils/perf/perfFlags';
|
||||
|
||||
export type ConnectionStatus = 'connected' | 'disconnected' | 'checking';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { setRating } from '../api/subsonicStarRating';
|
||||
import type { SubsonicAlbum, SubsonicArtist } from '../api/subsonicTypes';
|
||||
import type { Track } from '../store/playerStoreTypes';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
|
||||
type RatingKind = 'song' | 'album' | 'artist';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { search as searchSubsonic } from '../api/subsonicSearch';
|
||||
import type {
|
||||
SubsonicAlbum, SubsonicArtist, SubsonicPlaylist,
|
||||
} from '../api/subsonicTypes';
|
||||
import type { SourceTab } from '../utils/deviceSyncHelpers';
|
||||
import type { SourceTab } from '../utils/deviceSync/deviceSyncHelpers';
|
||||
|
||||
export interface DeviceSyncBrowserResult {
|
||||
playlists: SubsonicPlaylist[];
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { useDeviceSyncStore, type DeviceSyncSource } from '../store/deviceSyncStore';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
|
||||
export interface DeviceSyncDeviceScanResult {
|
||||
scanDevice: () => Promise<void>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import type { RemovableDrive } from '../utils/deviceSyncHelpers';
|
||||
import type { RemovableDrive } from '../utils/deviceSync/deviceSyncHelpers';
|
||||
|
||||
export interface DeviceSyncDrivesResult {
|
||||
drives: RemovableDrive[];
|
||||
|
||||
@@ -4,9 +4,9 @@ import { listen } from '@tauri-apps/api/event';
|
||||
import type { TFunction } from 'i18next';
|
||||
import { useDeviceSyncJobStore } from '../store/deviceSyncJobStore';
|
||||
import { useDeviceSyncStore } from '../store/deviceSyncStore';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { trackToSyncInfo } from '../utils/deviceSyncHelpers';
|
||||
import { fetchTracksForSource } from '../utils/fetchTracksForSource';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
import { trackToSyncInfo } from '../utils/deviceSync/deviceSyncHelpers';
|
||||
import { fetchTracksForSource } from '../utils/playback/fetchTracksForSource';
|
||||
|
||||
export function useDeviceSyncJobEvents(
|
||||
t: TFunction,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { fetchTracksForSource } from '../utils/fetchTracksForSource';
|
||||
import { trackToSyncInfo, type SyncStatus } from '../utils/deviceSyncHelpers';
|
||||
import { fetchTracksForSource } from '../utils/playback/fetchTracksForSource';
|
||||
import { trackToSyncInfo, type SyncStatus } from '../utils/deviceSync/deviceSyncHelpers';
|
||||
import type { DeviceSyncSource } from '../store/deviceSyncStore';
|
||||
|
||||
export interface DeviceSyncSourceStatusesResult {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { usePlayerStore } from '../store/playerStore';
|
||||
import {
|
||||
entryToTrack, folderBrowserHasKeyModifiers, isFolderBrowserArrowKey,
|
||||
type Column, type NavPos,
|
||||
} from '../utils/folderBrowserHelpers';
|
||||
} from '../utils/componentHelpers/folderBrowserHelpers';
|
||||
|
||||
interface Args {
|
||||
columns: Column[];
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useLocation } from 'react-router-dom';
|
||||
import { getMusicDirectory, getMusicIndexes } from '../api/subsonicLibrary';
|
||||
import type { SubsonicDirectoryEntry } from '../api/subsonicTypes';
|
||||
import type { Track } from '../store/playerStoreTypes';
|
||||
import type { Column, NavPos } from '../utils/folderBrowserHelpers';
|
||||
import type { Column, NavPos } from '../utils/componentHelpers/folderBrowserHelpers';
|
||||
|
||||
let persistedPlayingPathIds: string[] = [];
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import type { Column, NavPos } from '../utils/folderBrowserHelpers';
|
||||
import type { Column, NavPos } from '../utils/componentHelpers/folderBrowserHelpers';
|
||||
|
||||
interface Args {
|
||||
columns: Column[];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { extractCoverColors } from '../utils/dynamicColors';
|
||||
import { extractCoverColors } from '../utils/ui/dynamicColors';
|
||||
|
||||
// Module-level cache: artKey → accent color string.
|
||||
// Survives track changes so same-album songs reuse the extracted color instantly.
|
||||
|
||||
@@ -10,7 +10,7 @@ import { fetchLyricsPlus, hasWordSync } from '../api/lyricsplus';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import { useOfflineStore } from '../store/offlineStore';
|
||||
import { useHotCacheStore } from '../store/hotCacheStore';
|
||||
import { getCachedLyrics, putCachedLyrics, lyricsCacheKey } from '../utils/lyricsPersistentCache';
|
||||
import { getCachedLyrics, putCachedLyrics, lyricsCacheKey } from '../utils/cache/lyricsPersistentCache';
|
||||
export type LyricsSource = 'server' | 'lrclib' | 'netease' | 'embedded' | 'lyricsplus';
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useAuthStore } from '../store/authStore';
|
||||
import { IS_LINUX } from '../utils/platform';
|
||||
import {
|
||||
EXPANDED_SIZE, EXPANDED_MIN, readStoredExpandedHeight,
|
||||
} from '../utils/miniPlayerHelpers';
|
||||
} from '../utils/componentHelpers/miniPlayerHelpers';
|
||||
|
||||
/** Three window-bound setup effects bundled together:
|
||||
* - Linux WebKitGTK smooth-scroll per-window (re-applies after auth hydrates
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
lastfmGetArtistStats, lastfmGetTrackInfo, lastfmIsConfigured,
|
||||
type LastfmArtistStats, type LastfmTrackInfo,
|
||||
} from '../api/lastfm';
|
||||
import { makeCache } from '../utils/nowPlayingCache';
|
||||
import { makeCache } from '../utils/cache/nowPlayingCache';
|
||||
|
||||
// Module-level TTL caches (shared across mounts)
|
||||
const songMetaCache = makeCache<SubsonicSong | null>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getSong } from '../api/subsonicLibrary';
|
||||
import { songToTrack } from '../utils/songToTrack';
|
||||
import { songToTrack } from '../utils/playback/songToTrack';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useOrbitStore } from '../store/orbitStore';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getSong } from '../api/subsonicLibrary';
|
||||
import { songToTrack } from '../utils/songToTrack';
|
||||
import { songToTrack } from '../utils/playback/songToTrack';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useOrbitStore } from '../store/orbitStore';
|
||||
import { usePlayerStore } from '../store/playerStore';
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
type OrbitState,
|
||||
type OrbitQueueItem,
|
||||
} from '../api/orbit';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
import i18n from '../i18n';
|
||||
import { pushOrbitEvent } from '../utils/orbitDiag';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
evaluateOrbitSuggestGate,
|
||||
OrbitSuggestBlockedError,
|
||||
} from '../utils/orbit';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
|
||||
/**
|
||||
* Shared behaviour for song rows that in "normal mode" swallow a full list
|
||||
|
||||
@@ -3,7 +3,7 @@ import type React from 'react';
|
||||
import { getPlaylist } from '../api/subsonicPlaylists';
|
||||
import type { SubsonicPlaylist } from '../api/subsonicTypes';
|
||||
import { usePlaylistStore } from '../store/playlistStore';
|
||||
import type { PendingSmartPlaylist } from '../utils/playlistsSmart';
|
||||
import type { PendingSmartPlaylist } from '../utils/playlist/playlistsSmart';
|
||||
|
||||
/**
|
||||
* Poll Navidrome every 10 s for each pending smart playlist until its
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCallback } from 'react';
|
||||
import type { Track } from '../store/playerStoreTypes';
|
||||
import { enqueuePlaylistAll, playPlaylistAll, shufflePlaylistAll } from '../utils/playlistBulkPlayActions';
|
||||
import { enqueuePlaylistAll, playPlaylistAll, shufflePlaylistAll } from '../utils/playlist/playlistBulkPlayActions';
|
||||
|
||||
export interface PlaylistBulkPlayCallbacksDeps {
|
||||
songsLength: number;
|
||||
|
||||
@@ -2,8 +2,8 @@ import { useMemo } from 'react';
|
||||
import type { SubsonicSong } from '../api/subsonicTypes';
|
||||
import type { Track } from '../store/playerStoreTypes';
|
||||
import { usePlayerStore } from '../store/playerStore';
|
||||
import { songToTrack } from '../utils/songToTrack';
|
||||
import { getDisplayedSongs, type PlaylistSortDir, type PlaylistSortKey } from '../utils/playlistDisplayedSongs';
|
||||
import { songToTrack } from '../utils/playback/songToTrack';
|
||||
import { getDisplayedSongs, type PlaylistSortDir, type PlaylistSortKey } from '../utils/playlist/playlistDisplayedSongs';
|
||||
|
||||
export interface PlaylistDerivedOptions {
|
||||
filterText: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import type { SubsonicSong } from '../api/subsonicTypes';
|
||||
import { useDragDrop } from '../contexts/DragDropContext';
|
||||
import { runPlaylistReorderDrop } from '../utils/runPlaylistReorderDrop';
|
||||
import { runPlaylistReorderDrop } from '../utils/playlist/runPlaylistReorderDrop';
|
||||
|
||||
export interface PlaylistDnDReorderDeps {
|
||||
tracklistRef: React.RefObject<HTMLDivElement | null>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type React from 'react';
|
||||
import type { TFunction } from 'i18next';
|
||||
import type { SubsonicPlaylist, SubsonicSong } from '../api/subsonicTypes';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
|
||||
export interface PlaylistSongMutationsDeps {
|
||||
songs: SubsonicSong[];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { InternetRadioStation } from '../api/subsonicTypes';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { usePerfProbeFlags } from '../utils/perfFlags';
|
||||
import { usePerfProbeFlags } from '../utils/perf/perfFlags';
|
||||
import {
|
||||
guessAzuraCastApiUrl,
|
||||
normaliseAzuraCastHomepageUrl,
|
||||
|
||||
@@ -6,12 +6,12 @@ import {
|
||||
getSystemItemsForReorder,
|
||||
isSidebarNavItemUserHideable,
|
||||
type SidebarNavDropTarget,
|
||||
} from '../utils/sidebarNavReorder';
|
||||
} from '../utils/componentHelpers/sidebarNavReorder';
|
||||
import {
|
||||
SIDEBAR_NAV_LONG_PRESS_MOVE_CANCEL_PX,
|
||||
SIDEBAR_NAV_LONG_PRESS_MS,
|
||||
isPointerOutsideAsideSidebar,
|
||||
} from '../utils/sidebarHelpers';
|
||||
} from '../utils/componentHelpers/sidebarHelpers';
|
||||
|
||||
interface NavDndState {
|
||||
section: 'library' | 'system';
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
NEW_RELEASES_UNREAD_SAMPLE_SIZE,
|
||||
NEW_RELEASES_UNREAD_STORAGE_PREFIX,
|
||||
mergeSeenNewReleaseIdsCap,
|
||||
} from '../utils/sidebarHelpers';
|
||||
} from '../utils/componentHelpers/sidebarHelpers';
|
||||
|
||||
interface Args {
|
||||
serverId: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { setPerfProbeTelemetryActive } from '../utils/perfTelemetry';
|
||||
import { setPerfProbeTelemetryActive } from '../utils/perf/perfTelemetry';
|
||||
|
||||
interface PerfCpu {
|
||||
app: number;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
|
||||
import { filterSongsToActiveLibrary } from '../api/subsonicLibrary';
|
||||
import { getPlaylist } from '../api/subsonicPlaylists';
|
||||
import type { SubsonicPlaylist } from '../api/subsonicTypes';
|
||||
import { isSmartPlaylistName } from '../utils/playlistsSmart';
|
||||
import { isSmartPlaylistName } from '../utils/playlist/playlistsSmart';
|
||||
|
||||
/**
|
||||
* Build the 2×2 cover collage for each smart playlist. Pulls each smart
|
||||
|
||||
@@ -8,12 +8,12 @@ import {
|
||||
type NdLibrary,
|
||||
type NdUser,
|
||||
} from '../api/navidromeAdmin';
|
||||
import { showToast } from '../utils/toast';
|
||||
import { showToast } from '../utils/ui/toast';
|
||||
import {
|
||||
copyTextToClipboard,
|
||||
encodeServerMagicString,
|
||||
} from '../utils/serverMagicString';
|
||||
import { shortHostFromServerUrl } from '../utils/serverDisplayName';
|
||||
} from '../utils/server/serverMagicString';
|
||||
import { shortHostFromServerUrl } from '../utils/server/serverDisplayName';
|
||||
import type { UserFormState } from '../components/settings/UserForm';
|
||||
|
||||
interface UseUserMgmtActionsArgs {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import type { SeekbarStyle } from '../store/authStoreTypes';
|
||||
import type { AnimState } from '../utils/waveformSeekHelpers';
|
||||
import type { AnimState } from '../utils/waveform/waveformSeekHelpers';
|
||||
import {
|
||||
ANIMATED_STYLES, BAR_COUNT, FLAT_WAVE_NORM, WAVE_MORPH_MS,
|
||||
binsToHeights, easeOutCubic, heightsNearlyEqual,
|
||||
makeFlatWaveHeights, makeHeights,
|
||||
} from '../utils/waveformSeekHelpers';
|
||||
import { drawSeekbar } from '../utils/waveformSeekRenderers';
|
||||
} from '../utils/waveform/waveformSeekHelpers';
|
||||
import { drawSeekbar } from '../utils/waveform/waveformSeekRenderers';
|
||||
|
||||
interface Args {
|
||||
trackId: string | undefined;
|
||||
|
||||
@@ -4,8 +4,8 @@ import { getPlaybackProgressSnapshot } from '../store/playbackProgress';
|
||||
import {
|
||||
ANIMATED_STYLES, AnimState, INTERPOLATION_PAINT_MIN_MS,
|
||||
isBarQuantizedSeekStyle, quantizeProgressByBars,
|
||||
} from '../utils/waveformSeekHelpers';
|
||||
import { drawSeekbar } from '../utils/waveformSeekRenderers';
|
||||
} from '../utils/waveform/waveformSeekHelpers';
|
||||
import { drawSeekbar } from '../utils/waveform/waveformSeekRenderers';
|
||||
|
||||
interface Args {
|
||||
duration: number;
|
||||
|
||||
Reference in New Issue
Block a user