mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 02:13:33 +00:00
Add remote control (#164)
* draft add remotes * add favorite, rating * add basic auth
This commit is contained in:
parent
0a13d047bb
commit
c9dbf9b5be
66 changed files with 2585 additions and 298 deletions
|
|
@ -74,7 +74,7 @@ export const ApplicationSettings = () => {
|
|||
zoomFactor: newVal,
|
||||
},
|
||||
});
|
||||
localSettings.setZoomFactor(newVal);
|
||||
localSettings!.setZoomFactor(newVal);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { ApplicationSettings } from '/@/renderer/features/settings/components/ge
|
|||
import { ControlSettings } from '/@/renderer/features/settings/components/general/control-settings';
|
||||
import { SidebarSettings } from '/@/renderer/features/settings/components/general/sidebar-settings';
|
||||
import { ThemeSettings } from '/@/renderer/features/settings/components/general/theme-settings';
|
||||
import { RemoteSettings } from '/@/renderer/features/settings/components/general/remote-settings';
|
||||
|
||||
export const GeneralTab = () => {
|
||||
return (
|
||||
|
|
@ -14,6 +15,8 @@ export const GeneralTab = () => {
|
|||
<ControlSettings />
|
||||
<Divider />
|
||||
<SidebarSettings />
|
||||
<Divider />
|
||||
<RemoteSettings />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,156 @@
|
|||
import isElectron from 'is-electron';
|
||||
import { SettingsSection } from '/@/renderer/features/settings/components/settings-section';
|
||||
import { useRemoteSettings, useSettingsStoreActions } from '/@/renderer/store';
|
||||
import { NumberInput, Switch, Text, TextInput, toast } from '/@/renderer/components';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
const remote = isElectron() ? window.electron.remote : null;
|
||||
|
||||
export const RemoteSettings = () => {
|
||||
const settings = useRemoteSettings();
|
||||
const { setSettings } = useSettingsStoreActions();
|
||||
|
||||
const url = `http://localhost:${settings.port}`;
|
||||
|
||||
const debouncedEnableRemote = debounce(async (enabled: boolean) => {
|
||||
const errorMsg = await remote!.setRemoteEnabled(enabled);
|
||||
|
||||
if (errorMsg === null) {
|
||||
setSettings({
|
||||
remote: {
|
||||
...settings,
|
||||
enabled,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
toast.error({
|
||||
message: errorMsg,
|
||||
title: enabled ? 'Error enabling remote' : 'Error disabling remote',
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
|
||||
const debouncedChangeRemotePort = debounce(async (port: number) => {
|
||||
const errorMsg = await remote!.setRemotePort(port);
|
||||
if (errorMsg === null) {
|
||||
setSettings({
|
||||
remote: {
|
||||
...settings,
|
||||
port,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
toast.error({
|
||||
message: errorMsg,
|
||||
title: 'Error setting port',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const isHidden = !isElectron();
|
||||
|
||||
const controlOptions = [
|
||||
{
|
||||
control: (
|
||||
<Switch
|
||||
aria-label="Enable remote control server"
|
||||
defaultChecked={settings.enabled}
|
||||
onChange={async (e) => {
|
||||
const enabled = e.currentTarget.checked;
|
||||
await debouncedEnableRemote(enabled);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description: (
|
||||
<div>
|
||||
Start an HTTP server to remotely control Feishin. This will listen on{' '}
|
||||
<a
|
||||
href={url}
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
>
|
||||
{url}
|
||||
</a>
|
||||
</div>
|
||||
),
|
||||
isHidden,
|
||||
title: 'Enable remote control',
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
aria-label="Set remote port"
|
||||
max={65535}
|
||||
value={settings.port}
|
||||
onBlur={async (e) => {
|
||||
if (!e) return;
|
||||
const port = Number(e.currentTarget.value);
|
||||
await debouncedChangeRemotePort(port);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description:
|
||||
'Remote server port. Changes here only take effect when you enable the remote',
|
||||
isHidden,
|
||||
title: 'Remove server port',
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<TextInput
|
||||
aria-label="Set remote username"
|
||||
defaultValue={settings.username}
|
||||
onBlur={(e) => {
|
||||
const username = e.currentTarget.value;
|
||||
if (username === settings.username) return;
|
||||
remote!.updateUsername(username);
|
||||
setSettings({
|
||||
remote: {
|
||||
...settings,
|
||||
username,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description:
|
||||
'Username that must be provided to access remote. If both username and password are empty, disable authentication',
|
||||
isHidden,
|
||||
title: 'Remote username',
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<TextInput
|
||||
aria-label="Set remote password"
|
||||
defaultValue={settings.password}
|
||||
onBlur={(e) => {
|
||||
const password = e.currentTarget.value;
|
||||
if (password === settings.password) return;
|
||||
remote!.updatePassword(password);
|
||||
setSettings({
|
||||
remote: {
|
||||
...settings,
|
||||
password,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description: 'Password to access remote',
|
||||
isHidden,
|
||||
title: 'Remote password',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsSection options={controlOptions} />
|
||||
<Text size="lg">
|
||||
<b>
|
||||
NOTE: these credentials are by default transferred insecurely. Do not use a
|
||||
password you care about. Changing username/password will disconnect clients and
|
||||
require them to reauthenticate
|
||||
</b>
|
||||
</Text>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
@ -23,12 +23,12 @@ export const WindowHotkeySettings = () => {
|
|||
globalMediaHotkeys: e.currentTarget.checked,
|
||||
},
|
||||
});
|
||||
localSettings.set('global_media_hotkeys', e.currentTarget.checked);
|
||||
localSettings!.set('global_media_hotkeys', e.currentTarget.checked);
|
||||
|
||||
if (e.currentTarget.checked) {
|
||||
localSettings.enableMediaKeys();
|
||||
localSettings!.enableMediaKeys();
|
||||
} else {
|
||||
localSettings.disableMediaKeys();
|
||||
localSettings!.disableMediaKeys();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export const AudioSettings = () => {
|
|||
setSettings({ playback: { ...settings, type: e as PlaybackType } });
|
||||
if (isElectron() && e === PlaybackType.LOCAL) {
|
||||
const queueData = usePlayerStore.getState().actions.getPlayerData();
|
||||
mpvPlayer.setQueue(queueData);
|
||||
mpvPlayer!.setQueue(queueData);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const getMpvSetting = (
|
|||
case 'replayGainPreampDB':
|
||||
return { 'replaygain-preamp': value || 0 };
|
||||
default:
|
||||
return key;
|
||||
return { 'audio-format': value };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -66,12 +66,12 @@ export const MpvSettings = () => {
|
|||
const [mpvPath, setMpvPath] = useState('');
|
||||
|
||||
const handleSetMpvPath = (e: File) => {
|
||||
localSettings.set('mpv_path', e.path);
|
||||
localSettings?.set('mpv_path', e.path);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const getMpvPath = async () => {
|
||||
if (!isElectron()) return setMpvPath('');
|
||||
if (!localSettings) return setMpvPath('');
|
||||
const mpvPath = (await localSettings.get('mpv_path')) as string;
|
||||
return setMpvPath(mpvPath);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export const WindowSettings = () => {
|
|||
message:
|
||||
'Restart to apply changes... close the notification to restart Feishin',
|
||||
onClose: () => {
|
||||
window.electron.ipc.send('app-restart');
|
||||
window.electron.ipc!.send('app-restart');
|
||||
},
|
||||
title: 'Restart required',
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue