Add discord rich presence (#72)
This commit is contained in:
parent
2664a80851
commit
244c00c4c6
12 changed files with 391 additions and 7 deletions
62
package-lock.json
generated
62
package-lock.json
generated
|
@ -27,6 +27,7 @@
|
||||||
"@tanstack/react-query-devtools": "^4.32.1",
|
"@tanstack/react-query-devtools": "^4.32.1",
|
||||||
"@tanstack/react-query-persist-client": "^4.32.1",
|
"@tanstack/react-query-persist-client": "^4.32.1",
|
||||||
"@ts-rest/core": "^3.23.0",
|
"@ts-rest/core": "^3.23.0",
|
||||||
|
"@xhayper/discord-rpc": "^1.0.24",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"cmdk": "^0.2.0",
|
"cmdk": "^0.2.0",
|
||||||
|
@ -5613,6 +5614,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@xhayper/discord-rpc": {
|
||||||
|
"version": "1.0.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xhayper/discord-rpc/-/discord-rpc-1.0.24.tgz",
|
||||||
|
"integrity": "sha512-gzC8OaOSz7cGALSHyyq6nANQvBfyfntbSq+Qh+cNanoKX8ybOj+jWKmDP6PbLVDWoBftTU3JYsWXrLml2df2Hw==",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.5.1",
|
||||||
|
"ws": "^8.14.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.18.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@xhayper/discord-rpc/node_modules/ws": {
|
||||||
|
"version": "8.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
|
||||||
|
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@xmldom/xmldom": {
|
"node_modules/@xmldom/xmldom": {
|
||||||
"version": "0.8.10",
|
"version": "0.8.10",
|
||||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||||
|
@ -6292,9 +6325,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.4.0",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
|
||||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
"integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
|
@ -25433,6 +25466,23 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"@xhayper/discord-rpc": {
|
||||||
|
"version": "1.0.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/@xhayper/discord-rpc/-/discord-rpc-1.0.24.tgz",
|
||||||
|
"integrity": "sha512-gzC8OaOSz7cGALSHyyq6nANQvBfyfntbSq+Qh+cNanoKX8ybOj+jWKmDP6PbLVDWoBftTU3JYsWXrLml2df2Hw==",
|
||||||
|
"requires": {
|
||||||
|
"axios": "^1.5.1",
|
||||||
|
"ws": "^8.14.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ws": {
|
||||||
|
"version": "8.14.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
|
||||||
|
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==",
|
||||||
|
"requires": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@xmldom/xmldom": {
|
"@xmldom/xmldom": {
|
||||||
"version": "0.8.10",
|
"version": "0.8.10",
|
||||||
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
|
||||||
|
@ -25951,9 +26001,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.4.0",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
|
||||||
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
|
"integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.0",
|
"follow-redirects": "^1.15.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
|
|
|
@ -273,6 +273,7 @@
|
||||||
"@tanstack/react-query-devtools": "^4.32.1",
|
"@tanstack/react-query-devtools": "^4.32.1",
|
||||||
"@tanstack/react-query-persist-client": "^4.32.1",
|
"@tanstack/react-query-persist-client": "^4.32.1",
|
||||||
"@ts-rest/core": "^3.23.0",
|
"@ts-rest/core": "^3.23.0",
|
||||||
|
"@xhayper/discord-rpc": "^1.0.24",
|
||||||
"axios": "^1.4.0",
|
"axios": "^1.4.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"cmdk": "^0.2.0",
|
"cmdk": "^0.2.0",
|
||||||
|
|
63
src/main/features/core/discord-rpc/index.ts
Normal file
63
src/main/features/core/discord-rpc/index.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { Client, SetActivity } from '@xhayper/discord-rpc';
|
||||||
|
import { ipcMain } from 'electron';
|
||||||
|
|
||||||
|
const FEISHIN_DISCORD_APPLICATION_ID = '1165957668758900787';
|
||||||
|
|
||||||
|
let client: Client | null = null;
|
||||||
|
|
||||||
|
const createClient = (clientId?: string) => {
|
||||||
|
client = new Client({
|
||||||
|
clientId: clientId || FEISHIN_DISCORD_APPLICATION_ID,
|
||||||
|
});
|
||||||
|
|
||||||
|
client.login();
|
||||||
|
|
||||||
|
return client;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setActivity = (activity: SetActivity) => {
|
||||||
|
if (client) {
|
||||||
|
client.user?.setActivity({
|
||||||
|
...activity,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearActivity = () => {
|
||||||
|
if (client) {
|
||||||
|
client.user?.clearActivity();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const quit = () => {
|
||||||
|
if (client) {
|
||||||
|
client?.destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ipcMain.handle('discord-rpc-initialize', (_event, clientId?: string) => {
|
||||||
|
createClient(clientId);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('discord-rpc-set-activity', (_event, activity: SetActivity) => {
|
||||||
|
if (client) {
|
||||||
|
setActivity(activity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('discord-rpc-clear-activity', () => {
|
||||||
|
if (client) {
|
||||||
|
clearActivity();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('discord-rpc-quit', () => {
|
||||||
|
quit();
|
||||||
|
});
|
||||||
|
|
||||||
|
export const discordRpc = {
|
||||||
|
clearActivity,
|
||||||
|
createClient,
|
||||||
|
quit,
|
||||||
|
setActivity,
|
||||||
|
};
|
|
@ -2,3 +2,4 @@ import './lyrics';
|
||||||
import './player';
|
import './player';
|
||||||
import './remote';
|
import './remote';
|
||||||
import './settings';
|
import './settings';
|
||||||
|
import './discord-rpc';
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { contextBridge } from 'electron';
|
import { contextBridge } from 'electron';
|
||||||
import { browser } from './preload/browser';
|
import { browser } from './preload/browser';
|
||||||
|
import { discordRpc } from './preload/discord-rpc';
|
||||||
import { ipc } from './preload/ipc';
|
import { ipc } from './preload/ipc';
|
||||||
import { localSettings } from './preload/local-settings';
|
import { localSettings } from './preload/local-settings';
|
||||||
import { lyrics } from './preload/lyrics';
|
import { lyrics } from './preload/lyrics';
|
||||||
|
@ -10,6 +11,7 @@ import { utils } from './preload/utils';
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('electron', {
|
contextBridge.exposeInMainWorld('electron', {
|
||||||
browser,
|
browser,
|
||||||
|
discordRpc,
|
||||||
ipc,
|
ipc,
|
||||||
localSettings,
|
localSettings,
|
||||||
lyrics,
|
lyrics,
|
||||||
|
|
28
src/main/preload/discord-rpc.ts
Normal file
28
src/main/preload/discord-rpc.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { SetActivity } from '@xhayper/discord-rpc';
|
||||||
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
|
const initialize = (clientId: string) => {
|
||||||
|
const client = ipcRenderer.invoke('discord-rpc-initialize', clientId);
|
||||||
|
return client;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearActivity = () => {
|
||||||
|
ipcRenderer.invoke('discord-rpc-clear-activity');
|
||||||
|
};
|
||||||
|
|
||||||
|
const setActivity = (activity: SetActivity) => {
|
||||||
|
ipcRenderer.invoke('discord-rpc-set-activity', activity);
|
||||||
|
};
|
||||||
|
|
||||||
|
const quit = () => {
|
||||||
|
ipcRenderer.invoke('discord-rpc-quit');
|
||||||
|
};
|
||||||
|
|
||||||
|
export const discordRpc = {
|
||||||
|
clearActivity,
|
||||||
|
initialize,
|
||||||
|
quit,
|
||||||
|
setActivity,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DiscordRpc = typeof discordRpc;
|
|
@ -25,6 +25,7 @@ import { getMpvProperties } from '/@/renderer/features/settings/components/playb
|
||||||
import { PlayerState, usePlayerStore, useQueueControls } from '/@/renderer/store';
|
import { PlayerState, usePlayerStore, useQueueControls } from '/@/renderer/store';
|
||||||
import { FontType, PlaybackType, PlayerStatus } from '/@/renderer/types';
|
import { FontType, PlaybackType, PlayerStatus } from '/@/renderer/types';
|
||||||
import '@ag-grid-community/styles/ag-grid.css';
|
import '@ag-grid-community/styles/ag-grid.css';
|
||||||
|
import { useDiscordRpc } from '/@/renderer/features/discord-rpc/use-discord-rpc';
|
||||||
|
|
||||||
ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]);
|
ModuleRegistry.registerModules([ClientSideRowModelModule, InfiniteRowModelModule]);
|
||||||
|
|
||||||
|
@ -37,7 +38,6 @@ const remote = isElectron() ? window.electron.remote : null;
|
||||||
|
|
||||||
export const App = () => {
|
export const App = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const contentFont = useSettingsStore((state) => state.general.fontContent);
|
|
||||||
const accent = useSettingsStore((store) => store.general.accent);
|
const accent = useSettingsStore((store) => store.general.accent);
|
||||||
const { builtIn, custom, system, type } = useSettingsStore((state) => state.font);
|
const { builtIn, custom, system, type } = useSettingsStore((state) => state.font);
|
||||||
const { type: playbackType } = usePlaybackSettings();
|
const { type: playbackType } = usePlaybackSettings();
|
||||||
|
@ -46,6 +46,7 @@ export const App = () => {
|
||||||
const { clearQueue, restoreQueue } = useQueueControls();
|
const { clearQueue, restoreQueue } = useQueueControls();
|
||||||
const remoteSettings = useRemoteSettings();
|
const remoteSettings = useRemoteSettings();
|
||||||
const textStyleRef = useRef<HTMLStyleElement>();
|
const textStyleRef = useRef<HTMLStyleElement>();
|
||||||
|
useDiscordRpc();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (type === FontType.SYSTEM && system) {
|
if (type === FontType.SYSTEM && system) {
|
||||||
|
|
122
src/renderer/features/discord-rpc/use-discord-rpc.ts
Normal file
122
src/renderer/features/discord-rpc/use-discord-rpc.ts
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
/* eslint-disable consistent-return */
|
||||||
|
import isElectron from 'is-electron';
|
||||||
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
import {
|
||||||
|
useCurrentSong,
|
||||||
|
useCurrentStatus,
|
||||||
|
useDiscordSetttings,
|
||||||
|
usePlayerStore,
|
||||||
|
} from '/@/renderer/store';
|
||||||
|
import { SetActivity } from '@xhayper/discord-rpc';
|
||||||
|
import { PlayerStatus, ServerType } from '/@/renderer/types';
|
||||||
|
|
||||||
|
const discordRpc = isElectron() ? window.electron.discordRpc : null;
|
||||||
|
|
||||||
|
export const useDiscordRpc = () => {
|
||||||
|
const intervalRef = useRef(0);
|
||||||
|
const discordSettings = useDiscordSetttings();
|
||||||
|
const currentSong = useCurrentSong();
|
||||||
|
const currentStatus = useCurrentStatus();
|
||||||
|
|
||||||
|
const setActivity = useCallback(async () => {
|
||||||
|
if (!discordSettings.enableIdle && currentStatus === PlayerStatus.PAUSED) {
|
||||||
|
discordRpc?.clearActivity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentTime = usePlayerStore.getState().current.time;
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const start = currentTime ? Math.round(now - currentTime * 1000) : null;
|
||||||
|
const end =
|
||||||
|
currentSong?.duration && start ? Math.round(start + currentSong.duration) : null;
|
||||||
|
|
||||||
|
const artists = currentSong?.artists.map((artist) => artist.name).join(', ');
|
||||||
|
|
||||||
|
const activity: SetActivity = {
|
||||||
|
details: currentSong?.name.padEnd(2, ' ') || 'Idle',
|
||||||
|
instance: false,
|
||||||
|
largeImageKey: undefined,
|
||||||
|
largeImageText: currentSong?.album || 'Unknown album',
|
||||||
|
smallImageKey: undefined,
|
||||||
|
smallImageText: currentStatus,
|
||||||
|
state: artists && `By ${artists}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (currentStatus === PlayerStatus.PLAYING) {
|
||||||
|
if (start && end) {
|
||||||
|
activity.startTimestamp = start;
|
||||||
|
activity.endTimestamp = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
activity.smallImageKey = 'playing';
|
||||||
|
} else {
|
||||||
|
activity.smallImageKey = 'paused';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
currentSong?.serverType === ServerType.JELLYFIN &&
|
||||||
|
discordSettings.showServerImage &&
|
||||||
|
currentSong?.imageUrl
|
||||||
|
) {
|
||||||
|
activity.largeImageKey = currentSong?.imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to default icon if not set
|
||||||
|
if (!activity.largeImageKey) {
|
||||||
|
activity.largeImageKey = 'icon';
|
||||||
|
}
|
||||||
|
|
||||||
|
discordRpc?.setActivity(activity);
|
||||||
|
}, [currentSong, currentStatus, discordSettings.enableIdle, discordSettings.showServerImage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initializeDiscordRpc = async () => {
|
||||||
|
discordRpc?.initialize(discordSettings.clientId);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (discordSettings.enabled) {
|
||||||
|
initializeDiscordRpc();
|
||||||
|
} else {
|
||||||
|
discordRpc?.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
discordRpc?.quit();
|
||||||
|
};
|
||||||
|
}, [discordSettings.clientId, discordSettings.enabled]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (discordSettings.enabled) {
|
||||||
|
let intervalSeconds = discordSettings.updateInterval;
|
||||||
|
if (intervalSeconds < 15) {
|
||||||
|
intervalSeconds = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
intervalRef.current = window.setInterval(setActivity, intervalSeconds * 1000);
|
||||||
|
return () => clearInterval(intervalRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [discordSettings.enabled, discordSettings.updateInterval, setActivity]);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// console.log(
|
||||||
|
// 'currentStatus, discordSettings.enableIdle',
|
||||||
|
// currentStatus,
|
||||||
|
// discordSettings.enableIdle,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// if (discordSettings.enableIdle === false && currentStatus === PlayerStatus.PAUSED) {
|
||||||
|
// console.log('removing activity');
|
||||||
|
// clearActivity();
|
||||||
|
// clearInterval(intervalRef.current);
|
||||||
|
// }
|
||||||
|
// }, [
|
||||||
|
// clearActivity,
|
||||||
|
// currentStatus,
|
||||||
|
// discordSettings.enableIdle,
|
||||||
|
// discordSettings.enabled,
|
||||||
|
// setActivity,
|
||||||
|
// ]);
|
||||||
|
};
|
|
@ -0,0 +1,95 @@
|
||||||
|
import isElectron from 'is-electron';
|
||||||
|
import { NumberInput, Switch, TextInput } from '/@/renderer/components';
|
||||||
|
import {
|
||||||
|
SettingOption,
|
||||||
|
SettingsSection,
|
||||||
|
} from '/@/renderer/features/settings/components/settings-section';
|
||||||
|
import { useDiscordSetttings, useSettingsStoreActions } from '/@/renderer/store';
|
||||||
|
|
||||||
|
export const DiscordSettings = () => {
|
||||||
|
const settings = useDiscordSetttings();
|
||||||
|
const { setSettings } = useSettingsStoreActions();
|
||||||
|
|
||||||
|
const discordOptions: SettingOption[] = [
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
checked={settings.enabled}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSettings({
|
||||||
|
discord: {
|
||||||
|
...settings,
|
||||||
|
enabled: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description:
|
||||||
|
'Enable playback status in Discord rich presence. Image keys include: "icon", "playing", and "paused"',
|
||||||
|
isHidden: !isElectron(),
|
||||||
|
title: 'Discord rich presence',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<TextInput
|
||||||
|
defaultValue={settings.clientId}
|
||||||
|
onBlur={(e) => {
|
||||||
|
setSettings({
|
||||||
|
discord: {
|
||||||
|
...settings,
|
||||||
|
clientId: e.currentTarget.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: 'The Discord application ID (defaults to 1165957668758900787)',
|
||||||
|
isHidden: !isElectron(),
|
||||||
|
title: 'Discord application ID',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<NumberInput
|
||||||
|
value={settings.updateInterval}
|
||||||
|
onChange={(e) => {
|
||||||
|
let value = e ? Number(e) : 0;
|
||||||
|
if (value < 15) {
|
||||||
|
value = 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSettings({
|
||||||
|
discord: {
|
||||||
|
...settings,
|
||||||
|
updateInterval: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: 'The time in seconds between each update (minimum 15 seconds)',
|
||||||
|
isHidden: !isElectron(),
|
||||||
|
title: 'Rich presence update interval (seconds)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: (
|
||||||
|
<Switch
|
||||||
|
checked={settings.enableIdle}
|
||||||
|
onChange={(e) => {
|
||||||
|
setSettings({
|
||||||
|
discord: {
|
||||||
|
...settings,
|
||||||
|
enableIdle: e.currentTarget.checked,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
description: 'When enabled, the rich presence will update while player is idle',
|
||||||
|
isHidden: !isElectron(),
|
||||||
|
title: 'Show rich presence when idle',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return <SettingsSection options={discordOptions} />;
|
||||||
|
};
|
|
@ -1,12 +1,15 @@
|
||||||
import { Divider, Stack } from '@mantine/core';
|
import { Divider, Stack } from '@mantine/core';
|
||||||
import { UpdateSettings } from '/@/renderer/features/settings/components/window/update-settings';
|
import { UpdateSettings } from '/@/renderer/features/settings/components/window/update-settings';
|
||||||
import { WindowSettings } from '/@/renderer/features/settings/components/window/window-settings';
|
import { WindowSettings } from '/@/renderer/features/settings/components/window/window-settings';
|
||||||
|
import { DiscordSettings } from '/@/renderer/features/settings/components/window/discord-settings';
|
||||||
|
|
||||||
export const WindowTab = () => {
|
export const WindowTab = () => {
|
||||||
return (
|
return (
|
||||||
<Stack spacing="md">
|
<Stack spacing="md">
|
||||||
<WindowSettings />
|
<WindowSettings />
|
||||||
<Divider />
|
<Divider />
|
||||||
|
<DiscordSettings />
|
||||||
|
<Divider />
|
||||||
<UpdateSettings />
|
<UpdateSettings />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
2
src/renderer/preload.d.ts
vendored
2
src/renderer/preload.d.ts
vendored
|
@ -8,11 +8,13 @@ import { Lyrics } from '/@/main/preload/lyrics';
|
||||||
import { Utils } from '/@/main/preload/utils';
|
import { Utils } from '/@/main/preload/utils';
|
||||||
import { LocalSettings } from '/@/main/preload/local-settings';
|
import { LocalSettings } from '/@/main/preload/local-settings';
|
||||||
import { Ipc } from '/@/main/preload/ipc';
|
import { Ipc } from '/@/main/preload/ipc';
|
||||||
|
import { DiscordRpc } from '/@/main/preload/discord-rpc';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
electron: {
|
electron: {
|
||||||
browser: any;
|
browser: any;
|
||||||
|
discordRpc: DiscordRpc;
|
||||||
ipc?: Ipc;
|
ipc?: Ipc;
|
||||||
ipcRenderer: {
|
ipcRenderer: {
|
||||||
APP_RESTART(): void;
|
APP_RESTART(): void;
|
||||||
|
|
|
@ -112,6 +112,13 @@ export enum BindingActions {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingsState {
|
export interface SettingsState {
|
||||||
|
discord: {
|
||||||
|
clientId: string;
|
||||||
|
enableIdle: boolean;
|
||||||
|
enabled: boolean;
|
||||||
|
showServerImage: boolean;
|
||||||
|
updateInterval: number;
|
||||||
|
};
|
||||||
font: {
|
font: {
|
||||||
builtIn: string;
|
builtIn: string;
|
||||||
custom: string | null;
|
custom: string | null;
|
||||||
|
@ -216,6 +223,13 @@ const getPlatformDefaultWindowBarStyle = (): Platform => {
|
||||||
const platformDefaultWindowBarStyle: Platform = getPlatformDefaultWindowBarStyle();
|
const platformDefaultWindowBarStyle: Platform = getPlatformDefaultWindowBarStyle();
|
||||||
|
|
||||||
const initialState: SettingsState = {
|
const initialState: SettingsState = {
|
||||||
|
discord: {
|
||||||
|
clientId: '1165957668758900787',
|
||||||
|
enableIdle: false,
|
||||||
|
enabled: false,
|
||||||
|
showServerImage: false,
|
||||||
|
updateInterval: 15,
|
||||||
|
},
|
||||||
font: {
|
font: {
|
||||||
builtIn: 'Inter',
|
builtIn: 'Inter',
|
||||||
custom: null,
|
custom: null,
|
||||||
|
@ -558,3 +572,5 @@ export const useLyricsSettings = () => useSettingsStore((state) => state.lyrics,
|
||||||
export const useRemoteSettings = () => useSettingsStore((state) => state.remote, shallow);
|
export const useRemoteSettings = () => useSettingsStore((state) => state.remote, shallow);
|
||||||
|
|
||||||
export const useFontSettings = () => useSettingsStore((state) => state.font, shallow);
|
export const useFontSettings = () => useSettingsStore((state) => state.font, shallow);
|
||||||
|
|
||||||
|
export const useDiscordSetttings = () => useSettingsStore((state) => state.discord, shallow);
|
||||||
|
|
Reference in a new issue