Add mpv path reload and clear functionality

This commit is contained in:
jeffvli 2024-02-12 21:21:17 -08:00
parent 8f4ff9286a
commit fb08502e51
4 changed files with 94 additions and 18 deletions

View file

@ -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",

View file

@ -81,10 +81,11 @@ const DEFAULT_MPV_PARAMETERS = (extraParameters?: string[]) => {
};
const createMpv = async (data: {
binaryPath?: string;
extraParameters?: string[];
properties?: Record<string, any>;
}): Promise<MpvAPI> => {
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<string, any>) =>
ipcMain.handle(
'player-restart',
async (_event, data: { extraParameters?: string[]; properties?: Record<string, any> }) => {
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<number | undefined> => {
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', () => {

View file

@ -5,7 +5,11 @@ const initialize = (data: { extraParameters?: string[]; properties?: Record<stri
return ipcRenderer.invoke('player-initialize', data);
};
const restart = (data: { extraParameters?: string[]; properties?: Record<string, any> }) => {
const restart = (data: {
binaryPath?: string;
extraParameters?: string[];
properties?: Record<string, any>;
}) => {
return ipcRenderer.invoke('player-restart', data);
};

View file

@ -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<string, any> = {
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: (
<FileInput
placeholder={mpvPath}
width={225}
onChange={handleSetMpvPath}
/>
<Group spacing="sm">
<Button
tooltip={{
label: t('common.reload', { postProcess: 'titleCase' }),
openDelay: 0,
}}
variant="subtle"
onClick={handleReloadMpv}
>
<RiRestartLine />
</Button>
<FileInput
placeholder={mpvPath}
width={200}
onChange={handleSetMpvPath}
/>
{mpvPath && (
<Button
tooltip={{
label: t('common.clear', { postProcess: 'titleCase' }),
openDelay: 0,
}}
variant="default"
onClick={() => handleSetMpvPath(null)}
>
<RiCloseLine />
</Button>
)}
</Group>
),
description: t('setting.mpvExecutablePath', {
context: 'description',