From fb08502e510e7ba380ac99ef695125a8cee5e0e2 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Mon, 12 Feb 2024 21:21:17 -0800 Subject: [PATCH] Add mpv path reload and clear functionality --- src/i18n/locales/en.json | 5 +- src/main/features/core/player/index.ts | 25 ++++-- src/main/preload/mpv-player.ts | 6 +- .../components/playback/mpv-settings.tsx | 76 +++++++++++++++++-- 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 41a4528d..0b9e23e3 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -84,6 +84,7 @@ "random": "random", "rating": "rating", "refresh": "refresh", + "reload": "reload", "reset": "reset", "resetToDefault": "reset to default", "restartRequired": "restart required", @@ -506,9 +507,9 @@ "minimumScrobbleSeconds": "minimum scrobble (seconds)", "minimumScrobbleSeconds_description": "the minimum duration in seconds of the song that must be played before it is scrobbled", "mpvExecutablePath": "mpv executable path", - "mpvExecutablePath_description": "sets the path to the mpv executable", - "mpvExecutablePath_help": "one per line", + "mpvExecutablePath_description": "sets the path to the mpv executable. if left empty, the default path will be used", "mpvExtraParameters": "mpv parameters", + "mpvExtraParameters_help": "one per line", "passwordStore": "passwords/secret store", "passwordStore_description": "what password/secret store to use. change this if you are having issues storing passwords.", "playbackStyle": "playback style", diff --git a/src/main/features/core/player/index.ts b/src/main/features/core/player/index.ts index 22457b81..f096829f 100644 --- a/src/main/features/core/player/index.ts +++ b/src/main/features/core/player/index.ts @@ -81,10 +81,11 @@ const DEFAULT_MPV_PARAMETERS = (extraParameters?: string[]) => { }; const createMpv = async (data: { + binaryPath?: string; extraParameters?: string[]; properties?: Record; }): Promise => { - const { extraParameters, properties } = data; + const { extraParameters, properties, binaryPath } = data; const params = uniq([...DEFAULT_MPV_PARAMETERS(extraParameters), ...(extraParameters || [])]); @@ -94,7 +95,7 @@ const createMpv = async (data: { { audio_only: true, auto_restart: false, - binary: MPV_BINARY_PATH || undefined, + binary: binaryPath || MPV_BINARY_PATH || undefined, socket: isWindows() ? `\\\\.\\pipe\\mpvserver${extra}` : `/tmp/node-mpv${extra}.sock`, time_update: 1, }, @@ -168,15 +169,20 @@ ipcMain.on('player-set-properties', async (_event, data: Record) => ipcMain.handle( 'player-restart', async (_event, data: { extraParameters?: string[]; properties?: Record }) => { - mpvInstance?.quit(); try { mpvLog({ action: `Attempting to initialize mpv with parameters: ${JSON.stringify(data)}`, }); + + // Clean up previous mpv instance + getMpvInstance()?.stop(); + getMpvInstance()?.quit(); + mpvInstance = null; + mpvInstance = await createMpv(data); mpvLog({ action: 'Restarted mpv', toast: 'success' }); } catch (err: NodeMpvError | any) { - mpvLog({ action: 'Failed to initialize mpv' }, err); + mpvLog({ action: 'Failed to restart mpv' }, err); } }, ); @@ -197,8 +203,8 @@ ipcMain.handle( ipcMain.on('player-quit', async () => { try { - mpvInstance?.stop(); - mpvInstance?.quit(); + getMpvInstance()?.stop(); + getMpvInstance()?.quit(); mpvInstance = null; } catch (err: NodeMpvError | any) { mpvLog({ action: 'Failed to quit mpv' }, err); @@ -382,7 +388,12 @@ ipcMain.on('player-mute', async (_event, mute: boolean) => { }); ipcMain.handle('player-get-time', async (): Promise => { - return getMpvInstance()?.getTimePosition(); + try { + return getMpvInstance()?.getTimePosition(); + } catch (err: NodeMpvError | any) { + mpvLog({ action: `Failed to get current time` }, err); + return 0; + } }); app.on('before-quit', () => { diff --git a/src/main/preload/mpv-player.ts b/src/main/preload/mpv-player.ts index d7d84f8d..e93bacde 100644 --- a/src/main/preload/mpv-player.ts +++ b/src/main/preload/mpv-player.ts @@ -5,7 +5,11 @@ const initialize = (data: { extraParameters?: string[]; properties?: Record }) => { +const restart = (data: { + binaryPath?: string; + extraParameters?: string[]; + properties?: Record; +}) => { return ipcRenderer.invoke('player-restart', data); }; diff --git a/src/renderer/features/settings/components/playback/mpv-settings.tsx b/src/renderer/features/settings/components/playback/mpv-settings.tsx index 15443673..2128ba44 100644 --- a/src/renderer/features/settings/components/playback/mpv-settings.tsx +++ b/src/renderer/features/settings/components/playback/mpv-settings.tsx @@ -1,7 +1,15 @@ import { useEffect, useState } from 'react'; -import { Divider, Stack } from '@mantine/core'; +import { Divider, Group, Stack } from '@mantine/core'; import isElectron from 'is-electron'; -import { FileInput, Textarea, Text, Select, NumberInput, Switch } from '/@/renderer/components'; +import { + FileInput, + Textarea, + Text, + Select, + NumberInput, + Switch, + Button, +} from '/@/renderer/components'; import { SettingsSection, SettingOption, @@ -9,10 +17,13 @@ import { import { SettingsState, usePlaybackSettings, + useSettingsStore, useSettingsStoreActions, } from '/@/renderer/store/settings.store'; import { PlaybackType } from '/@/renderer/types'; import { useTranslation } from 'react-i18next'; +import { RiCloseLine, RiRestartLine } from 'react-icons/ri'; +import { usePlayerControls, usePlayerStore, useQueueControls } from '/@/renderer/store'; const localSettings = isElectron() ? window.electron.localSettings : null; const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null; @@ -64,11 +75,20 @@ export const MpvSettings = () => { const { t } = useTranslation(); const settings = usePlaybackSettings(); const { setSettings } = useSettingsStoreActions(); + const { pause } = usePlayerControls(); + const { clearQueue } = useQueueControls(); const [mpvPath, setMpvPath] = useState(''); - const handleSetMpvPath = (e: File) => { + const handleSetMpvPath = (e: File | null) => { + if (e === null) { + localSettings?.set('mpv_path', undefined); + setMpvPath(''); + return; + } + localSettings?.set('mpv_path', e.path); + setMpvPath(e.path); }; useEffect(() => { @@ -100,6 +120,22 @@ export const MpvSettings = () => { mpvPlayer?.setProperties(mpvSetting); }; + const handleReloadMpv = () => { + pause(); + clearQueue(); + + const extraParameters = useSettingsStore.getState().playback.mpvExtraParameters; + const properties: Record = { + speed: usePlayerStore.getState().current.speed, + ...getMpvProperties(useSettingsStore.getState().playback.mpvProperties), + }; + mpvPlayer?.restart({ + binaryPath: mpvPath || undefined, + extraParameters, + properties, + }); + }; + const handleSetExtraParameters = (data: string[]) => { setSettings({ playback: { @@ -112,11 +148,35 @@ export const MpvSettings = () => { const options: SettingOption[] = [ { control: ( - + + + + {mpvPath && ( + + )} + ), description: t('setting.mpvExecutablePath', { context: 'description',