import Store from 'electron-store'; import { defaultConfig as defaults } from './defaults'; import { DefaultPresetList, type Preset } from '@/plugins/downloader/types'; import type { SyncedLyricsPluginConfig } from '@/plugins/synced-lyrics/types'; export type IStore = InstanceType< typeof import('conf').default> >; const migrations = { '>=3.10.0'(store: IStore) { const lyricGeniusConfig = store.get('plugins.lyrics-genius') as | { enabled?: boolean; romanizedLyrics?: boolean; } | undefined; if (lyricGeniusConfig) { const syncedLyricsConfig = store.get('plugins.synced-lyrics') as | SyncedLyricsPluginConfig | undefined; if ( !syncedLyricsConfig || syncedLyricsConfig?.enabled !== lyricGeniusConfig?.enabled ) { store.set('plugins.synced-lyrics', { ...syncedLyricsConfig, enabled: lyricGeniusConfig.enabled, }); } store.delete('plugins.lyrics-genius'); } }, '>=3.3.0'(store: IStore) { const lastfmConfig = store.get('plugins.lastfm') as { enabled?: boolean; token?: string; session_key?: string; api_root?: string; api_key?: string; secret?: string; }; if (lastfmConfig) { let scrobblerConfig = store.get('plugins.scrobbler') as | { enabled?: boolean; scrobblers?: { lastfm?: { enabled?: boolean; token?: string; sessionKey?: string; apiRoot?: string; apiKey?: string; secret?: string; }; }; } | undefined; if (!scrobblerConfig) { scrobblerConfig = { enabled: lastfmConfig.enabled, }; } if (!scrobblerConfig.scrobblers) { scrobblerConfig.scrobblers = { lastfm: {}, }; } scrobblerConfig.scrobblers.lastfm = { enabled: lastfmConfig.enabled, token: lastfmConfig.token, sessionKey: lastfmConfig.session_key, apiRoot: lastfmConfig.api_root, apiKey: lastfmConfig.api_key, secret: lastfmConfig.secret, }; store.set('plugins.scrobbler', scrobblerConfig); store.delete('plugins.lastfm'); } }, '>=3.0.0'(store: IStore) { const discordConfig = store.get('plugins.discord') as Record< string, unknown >; if (discordConfig) { const oldActivityTimoutEnabled = store.get( 'plugins.discord.activityTimoutEnabled', ) as boolean | undefined; const oldActivityTimoutTime = store.get( 'plugins.discord.activityTimoutTime', ) as number | undefined; if (oldActivityTimoutEnabled !== undefined) { discordConfig.activityTimeoutEnabled = oldActivityTimoutEnabled; store.set('plugins.discord', discordConfig); } if (oldActivityTimoutTime !== undefined) { discordConfig.activityTimeoutTime = oldActivityTimoutTime; store.set('plugins.discord', discordConfig); } } }, '>=2.1.3'(store: IStore) { const listenAlong = store.get('plugins.discord.listenAlong'); if (listenAlong !== undefined) { store.set( 'plugins.discord.playOn\u0059\u006f\u0075\u0054\u0075\u0062\u0065\u004d\u0075\u0073\u0069\u0063', listenAlong, ); store.delete('plugins.discord.listenAlong'); } }, '>=2.1.0'(store: IStore) { const originalPreset = store.get('plugins.downloader.preset') as | string | undefined; if (originalPreset) { if (originalPreset !== 'opus') { store.set('plugins.downloader.selectedPreset', 'Custom'); store.set('plugins.downloader.customPresetSetting', { extension: 'mp3', ffmpegArgs: (store.get('plugins.downloader.ffmpegArgs') as string[]) ?? DefaultPresetList['mp3 (256kbps)'].ffmpegArgs, } satisfies Preset); } else { store.set('plugins.downloader.selectedPreset', 'Source'); store.set('plugins.downloader.customPresetSetting', { extension: null, ffmpegArgs: (store.get('plugins.downloader.ffmpegArgs') as string[]) ?? [], } satisfies Preset); } store.delete('plugins.downloader.preset'); store.delete('plugins.downloader.ffmpegArgs'); } }, '>=1.20.0'(store: IStore) { store.delete('plugins.visualizer'); // default value is now in the plugin if (store.get('plugins.notifications.toastStyle') === undefined) { const pluginOptions = store.get('plugins.notifications') || {}; store.set('plugins.notifications', { ...pluginOptions, }); } if (store.get('options.ForceShowLikeButtons')) { store.delete('options.ForceShowLikeButtons'); store.set('options.likeButtons', 'force'); } }, '>=1.17.0'(store: IStore) { store.delete('plugins.picture-in-picture'); // default value is now in the plugin if (store.get('plugins.video-toggle.mode') === undefined) { store.set('plugins.video-toggle.mode', 'custom'); } }, '>=1.14.0'(store: IStore) { if ( typeof store.get('plugins.precise-volume.globalShortcuts') !== 'object' ) { store.set('plugins.precise-volume.globalShortcuts', {}); } if (store.get('plugins.hide-video-player.enabled')) { store.delete('plugins.hide-video-player'); store.set('plugins.video-toggle.enabled', true); } }, '>=1.13.0'(store: IStore) { if (store.get('plugins.discord.listenAlong') === undefined) { store.set('plugins.discord.listenAlong', true); } }, '>=1.12.0'(store: IStore) { const options = store.get('plugins.shortcuts') as | Record< string, | { action: string; shortcut: unknown; }[] | Record > | undefined; if (options) { let updated = false; for (const optionType of ['global', 'local']) { if ( Object.hasOwn(options, optionType) && Array.isArray(options[optionType]) ) { const optionsArray = options[optionType] as { action: string; shortcut: unknown; }[]; const updatedOptions: Record = {}; for (const optionObject of optionsArray) { if (optionObject.action && optionObject.shortcut) { updatedOptions[optionObject.action] = optionObject.shortcut; } } options[optionType] = updatedOptions; updated = true; } } if (updated) { store.set('plugins.shortcuts', options); } } }, '>=1.11.0'(store: IStore) { if (store.get('options.resumeOnStart') === undefined) { store.set('options.resumeOnStart', true); } }, '>=1.7.0'(store: IStore) { const enabledPlugins = store.get('plugins') as string[]; if (!Array.isArray(enabledPlugins)) { console.warn('Plugins are not in array format, cannot migrate'); return; } // Include custom options // eslint-disable-next-line @typescript-eslint/no-explicit-any const plugins: Record = { adblocker: { enabled: true, cache: true, additionalBlockLists: [], }, downloader: { enabled: false, ffmpegArgs: [], // E.g. ["-b:a", "192k"] for an audio bitrate of 192kb/s downloadFolder: undefined, // Custom download folder (absolute path) }, }; for (const enabledPlugin of enabledPlugins) { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment plugins[enabledPlugin] = { ...plugins[enabledPlugin], enabled: true, }; } store.set('plugins', plugins); }, }; export const store = new Store({ defaults: { ...defaults, // README: 'plugin' uses deepmerge to populate the default values, so it is not necessary to include it here }, clearInvalidConfig: false, migrations, }) as Store & IStore;