import isElectron from 'is-electron'; import { generatePath } from 'react-router'; import { z } from 'zod'; import { devtools, persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; import { shallow } from 'zustand/shallow'; import { createWithEqualityFn } from 'zustand/traditional'; import i18n from '/@/i18n/i18n'; import { ALBUM_ARTIST_TABLE_COLUMNS, ALBUM_TABLE_COLUMNS, GENRE_TABLE_COLUMNS, pickGridRows, pickTableColumns, PLAYLIST_SONG_TABLE_COLUMNS, PLAYLIST_TABLE_COLUMNS, SONG_TABLE_COLUMNS, } from '/@/renderer/components/item-list/item-table-list/default-columns'; import { audiomotionanalyzerPresets } from '/@/renderer/features/visualizer/components/audiomotionanalyzer/presets'; import { AppRoute } from '/@/renderer/router/routes'; import { mergeOverridingColumns } from '/@/renderer/store/utils'; import { FontValueSchema } from '/@/renderer/types/fonts'; import { randomString } from '/@/renderer/utils'; import { sanitizeCss } from '/@/renderer/utils/sanitize'; import { AppTheme } from '/@/shared/themes/app-theme-types'; import { LibraryItem, LyricSource } from '/@/shared/types/domain-types'; import { FontType, ItemListKey, ListDisplayType, ListPaginationType, Platform, Play, PlayerType, TableColumn, } from '/@/shared/types/types'; const utils = isElectron() ? window.api.utils : null; type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; }; const HomeItemSchema = z.enum([ 'genres', 'mostPlayed', 'random', 'recentlyAdded', 'recentlyPlayed', 'recentlyReleased', ]); const ArtistItemSchema = z.enum([ 'biography', 'compilations', 'recentAlbums', 'similarArtists', 'topSongs', ]); const ArtistReleaseTypeItemSchema = z.enum([ 'releaseTypeAlbum', 'releaseTypeEp', 'releaseTypeSingle', 'releaseTypeBroadcast', 'releaseTypeOther', 'releaseTypeCompilation', 'appearsOn', 'releaseTypeAudioDrama', 'releaseTypeAudiobook', 'releaseTypeDemo', 'releaseTypeDjMix', 'releaseTypeFieldRecording', 'releaseTypeInterview', 'releaseTypeLive', 'releaseTypeMixtapeStreet', 'releaseTypeRemix', 'releaseTypeSoundtrack', 'releaseTypeSpokenWord', ]); const BindingActionsSchema = z.enum([ 'browserBack', 'browserForward', 'favoriteCurrentAdd', 'favoriteCurrentRemove', 'favoriteCurrentToggle', 'favoritePreviousAdd', 'favoritePreviousRemove', 'favoritePreviousToggle', 'globalSearch', 'localSearch', 'volumeMute', 'navigateHome', 'next', 'pause', 'play', 'playPause', 'previous', 'rate0', 'rate1', 'rate2', 'rate3', 'rate4', 'rate5', 'toggleShuffle', 'skipBackward', 'skipForward', 'stop', 'toggleFullscreenPlayer', 'toggleQueue', 'toggleRepeat', 'volumeDown', 'volumeUp', 'zoomIn', 'zoomOut', ]); const DiscordDisplayTypeSchema = z.enum(['artist', 'feishin', 'song']); const DiscordLinkTypeSchema = z.enum(['last_fm', 'musicbrainz', 'musicbrainz_last_fm', 'none']); const GenreTargetSchema = z.enum(['album', 'track']); const SideQueueTypeSchema = z.enum(['sideDrawerQueue', 'sideQueue']); const SidebarPanelTypeSchema = z.enum(['queue', 'lyrics', 'visualizer']); const SidebarItemTypeSchema = z.object({ disabled: z.boolean(), id: z.string(), label: z.string(), route: z.union([z.nativeEnum(AppRoute), z.string()]), }); const SortableItemSchema = (itemSchema: T) => z.object({ disabled: z.boolean(), id: itemSchema, }); const ItemTableListColumnConfigSchema = z.object({ align: z.enum(['center', 'end', 'start']), autoSize: z.boolean().optional(), id: z.nativeEnum(TableColumn), isEnabled: z.boolean(), pinned: z.union([z.literal('left'), z.literal('right'), z.literal(null)]), width: z.number(), }); export type ItemTableListColumnConfig = z.infer; const ItemGridListRowConfigSchema = z.object({ align: z.enum(['center', 'end', 'start']), id: z.nativeEnum(TableColumn), isEnabled: z.boolean(), }); export type ItemGridListRowConfig = z.infer; const ItemTableListPropsSchema = z.object({ autoFitColumns: z.boolean(), columns: z.array(ItemTableListColumnConfigSchema), enableAlternateRowColors: z.boolean(), enableHorizontalBorders: z.boolean(), enableRowHoverHighlight: z.boolean(), enableVerticalBorders: z.boolean(), size: z.enum(['compact', 'default']), }); const ItemListConfigSchema = z.object({ display: z.nativeEnum(ListDisplayType), grid: z.object({ itemGap: z.enum(['lg', 'md', 'sm', 'xl', 'xs']), itemsPerRow: z.number(), itemsPerRowEnabled: z.boolean(), rows: z.array(ItemGridListRowConfigSchema), size: z.enum(['compact', 'default', 'large']), }), itemsPerPage: z.number(), pagination: z.nativeEnum(ListPaginationType), table: ItemTableListPropsSchema, }); const TranscodingConfigSchema = z.object({ bitrate: z.number().optional(), enabled: z.boolean(), format: z.string().optional(), }); const MpvSettingsSchema = z.object({ audioExclusiveMode: z.enum(['no', 'yes']), audioFormat: z.enum(['float', 's16', 's32']).optional(), audioSampleRateHz: z.number().optional(), gaplessAudio: z.enum(['no', 'weak', 'yes']), replayGainClip: z.boolean(), replayGainFallbackDB: z.number().optional(), replayGainMode: z.enum(['album', 'no', 'track']), replayGainPreampDB: z.number().optional(), }); const CssSettingsSchema = z.object({ content: z.string().transform((val) => sanitizeCss(`