import isElectron from 'is-electron'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { SettingOption, SettingsSection, } from '/@/renderer/features/settings/components/settings-section'; import { usePlayerControls, usePlayerStore, useQueueControls } from '/@/renderer/store'; import { SettingsState, usePlaybackSettings, useSettingsStore, useSettingsStoreActions, } from '/@/renderer/store/settings.store'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Group } from '/@/shared/components/group/group'; import { NumberInput } from '/@/shared/components/number-input/number-input'; import { Select } from '/@/shared/components/select/select'; import { Stack } from '/@/shared/components/stack/stack'; import { Switch } from '/@/shared/components/switch/switch'; import { TextInput } from '/@/shared/components/text-input/text-input'; import { Text } from '/@/shared/components/text/text'; import { Textarea } from '/@/shared/components/textarea/textarea'; import { PlaybackType } from '/@/shared/types/types'; const localSettings = isElectron() ? window.api.localSettings : null; const mpvPlayer = isElectron() ? window.api.mpvPlayer : null; export const getMpvSetting = ( key: keyof SettingsState['playback']['mpvProperties'], value: any, ) => { switch (key) { case 'audioExclusiveMode': return { 'audio-exclusive': value || 'no' }; case 'audioSampleRateHz': return { 'audio-samplerate': value }; case 'gaplessAudio': return { 'gapless-audio': value || 'weak' }; case 'replayGainClip': return { 'replaygain-clip': value || 'no' }; case 'replayGainFallbackDB': return { 'replaygain-fallback': value }; case 'replayGainMode': return { replaygain: value || 'no' }; case 'replayGainPreampDB': return { 'replaygain-preamp': value || 0 }; default: return { 'audio-format': value }; } }; export const getMpvProperties = (settings: SettingsState['playback']['mpvProperties']) => { const properties: Record = { 'audio-exclusive': settings.audioExclusiveMode || 'no', 'audio-samplerate': settings.audioSampleRateHz === 0 ? undefined : settings.audioSampleRateHz, 'gapless-audio': settings.gaplessAudio || 'weak', replaygain: settings.replayGainMode || 'no', 'replaygain-clip': settings.replayGainClip || 'no', 'replaygain-fallback': settings.replayGainFallbackDB, 'replaygain-preamp': settings.replayGainPreampDB || 0, }; Object.keys(properties).forEach((key) => properties[key] === undefined ? delete properties[key] : {}, ); return properties; }; export const MpvSettings = () => { const { t } = useTranslation(); const settings = usePlaybackSettings(); const { setSettings } = useSettingsStoreActions(); const { pause } = usePlayerControls(); const { clearQueue } = useQueueControls(); const [mpvPath, setMpvPath] = useState( (localSettings?.get('mpv_path') as string | undefined) || '', ); const handleSetMpvPath = async (clear?: boolean) => { if (clear) { localSettings?.set('mpv_path', undefined); setMpvPath(''); return; } const result = await localSettings?.openFileSelector(); if (result === null) { localSettings?.set('mpv_path', undefined); setMpvPath(''); return; } localSettings?.set('mpv_path', result); setMpvPath(result); }; useEffect(() => { const getMpvPath = async () => { if (!localSettings) return setMpvPath(''); const mpvPath = (await localSettings.get('mpv_path')) as string; return setMpvPath(mpvPath); }; getMpvPath(); }, []); const handleSetMpvProperty = ( setting: keyof SettingsState['playback']['mpvProperties'], value: any, ) => { setSettings({ playback: { ...settings, mpvProperties: { ...settings.mpvProperties, [setting]: value, }, }, }); const mpvSetting = getMpvSetting(setting, value); mpvPlayer?.setProperties(mpvSetting); }; const handleReloadMpv = () => { pause(); clearQueue(); const extraParameters = useSettingsStore.getState().playback.mpvExtraParameters; const properties: Record = { speed: usePlayerStore.getState().speed, ...getMpvProperties(useSettingsStore.getState().playback.mpvProperties), }; mpvPlayer?.restart({ binaryPath: mpvPath || undefined, extraParameters, properties, }); }; const handleSetExtraParameters = (data: string[]) => { setSettings({ playback: { ...settings, mpvExtraParameters: data, }, }); }; const options: SettingOption[] = [ { control: ( { setMpvPath(e.currentTarget.value); // Transform backslashes to forward slashes const transformedValue = e.currentTarget.value.replace(/\\/g, '/'); localSettings?.set('mpv_path', transformedValue); }} onClick={() => handleSetMpvPath()} rightSection={ mpvPath && ( handleSetMpvPath(true)} variant="transparent" /> ) } value={mpvPath} width={200} /> ), description: t('setting.mpvExecutablePath', { context: 'description', postProcess: 'sentenceCase', }), isHidden: settings.type !== PlaybackType.LOCAL, note: 'Restart required', title: t('setting.mpvExecutablePath', { postProcess: 'sentenceCase' }), }, { control: (