diff --git a/src/renderer/features/discord-rpc/use-discord-rpc.ts b/src/renderer/features/discord-rpc/use-discord-rpc.ts
index 5c56e356b..2b78b291d 100644
--- a/src/renderer/features/discord-rpc/use-discord-rpc.ts
+++ b/src/renderer/features/discord-rpc/use-discord-rpc.ts
@@ -1,6 +1,6 @@
import { SetActivity, StatusDisplayType } from '@xhayper/discord-rpc';
import isElectron from 'is-electron';
-import { useCallback, useEffect, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
import { api } from '/@/renderer/api';
import { useItemImageUrl } from '/@/renderer/components/item-image/item-image';
@@ -12,6 +12,7 @@ import {
useLastfmApiKey,
usePlayerSong,
usePlayerStore,
+ useSettingsStore,
useTimestampStoreBase,
} from '/@/renderer/store';
import { sentenceCase } from '/@/renderer/utils';
@@ -410,3 +411,21 @@ export const useDiscordRpc = () => {
setActivity,
]);
};
+
+const DiscordRpcHookInner = () => {
+ useDiscordRpc();
+ return null;
+};
+
+export const DiscordRpcHook = () => {
+ const isElectronEnv = isElectron();
+ const isDiscordRpcEnabled = useSettingsStore((state) => state.discord.enabled);
+ const isPrivateMode = useAppStore((state) => state.privateMode);
+ const discordRpc = isElectronEnv ? window.api.discordRpc : null;
+
+ if (!isElectronEnv || !discordRpc || !isDiscordRpcEnabled || isPrivateMode) {
+ return null;
+ }
+
+ return React.createElement(DiscordRpcHookInner);
+};
diff --git a/src/renderer/features/player/audio-player/hooks/use-main-player-listener.tsx b/src/renderer/features/player/audio-player/hooks/use-main-player-listener.tsx
index f298daf9b..315a43d92 100644
--- a/src/renderer/features/player/audio-player/hooks/use-main-player-listener.tsx
+++ b/src/renderer/features/player/audio-player/hooks/use-main-player-listener.tsx
@@ -150,3 +150,19 @@ export const useMainPlayerListener = () => {
toggleShuffle,
]);
};
+
+const MainPlayerListenerHookInner = () => {
+ useMainPlayerListener();
+ return null;
+};
+
+export const MainPlayerListenerHook = () => {
+ const isElectronEnv = isElectron();
+ const mpvPlayerListener = isElectronEnv ? window.api.mpvPlayerListener : null;
+
+ if (mpvPlayerListener === null) {
+ return null;
+ }
+
+ return ;
+};
diff --git a/src/renderer/features/player/components/audio-players.tsx b/src/renderer/features/player/components/audio-players.tsx
index f94efee5b..0acad2671 100644
--- a/src/renderer/features/player/components/audio-players.tsx
+++ b/src/renderer/features/player/components/audio-players.tsx
@@ -3,24 +3,24 @@ import { useEffect } from 'react';
import { eventEmitter } from '/@/renderer/events/event-emitter';
import { UserFavoriteEventPayload, UserRatingEventPayload } from '/@/renderer/events/events';
-import { useDiscordRpc } from '/@/renderer/features/discord-rpc/use-discord-rpc';
-import { useMainPlayerListener } from '/@/renderer/features/player/audio-player/hooks/use-main-player-listener';
+import { DiscordRpcHook } from '/@/renderer/features/discord-rpc/use-discord-rpc';
+import { MainPlayerListenerHook } from '/@/renderer/features/player/audio-player/hooks/use-main-player-listener';
import { MpvPlayer } from '/@/renderer/features/player/audio-player/mpv-player';
import { WebPlayer } from '/@/renderer/features/player/audio-player/web-player';
-import { useAutoDJ } from '/@/renderer/features/player/hooks/use-auto-dj';
-import { useMediaSession } from '/@/renderer/features/player/hooks/use-media-session';
-import { useMPRIS } from '/@/renderer/features/player/hooks/use-mpris';
-import { usePlaybackHotkeys } from '/@/renderer/features/player/hooks/use-playback-hotkeys';
-import { usePowerSaveBlocker } from '/@/renderer/features/player/hooks/use-power-save-blocker';
-import { useQueueRestoreTimestamp } from '/@/renderer/features/player/hooks/use-queue-restore';
-import { useScrobble } from '/@/renderer/features/player/hooks/use-scrobble';
-import { useUpdateCurrentSong } from '/@/renderer/features/player/hooks/use-update-current-song';
+import { AutoDJHook } from '/@/renderer/features/player/hooks/use-auto-dj';
+import { MediaSessionHook } from '/@/renderer/features/player/hooks/use-media-session';
+import { MPRISHook } from '/@/renderer/features/player/hooks/use-mpris';
+import { PlaybackHotkeysHook } from '/@/renderer/features/player/hooks/use-playback-hotkeys';
+import { PowerSaveBlockerHook } from '/@/renderer/features/player/hooks/use-power-save-blocker';
+import { QueueRestoreTimestampHook } from '/@/renderer/features/player/hooks/use-queue-restore';
+import { ScrobbleHook } from '/@/renderer/features/player/hooks/use-scrobble';
+import { UpdateCurrentSongHook } from '/@/renderer/features/player/hooks/use-update-current-song';
import { useWebAudio } from '/@/renderer/features/player/hooks/use-webaudio';
import { RadioWebPlayer } from '/@/renderer/features/radio/components/radio-web-player';
import {
+ RadioAudioInstanceHook,
+ RadioMetadataHook,
useIsRadioActive,
- useRadioAudioInstance,
- useRadioMetadata,
} from '/@/renderer/features/radio/hooks/use-radio-player';
import {
updateQueueFavorites,
@@ -46,19 +46,54 @@ export const AudioPlayers = () => {
} = usePlaybackSettings();
const { setWebAudio, webAudio: audioContext } = useWebAudio();
- useScrobble();
- usePowerSaveBlocker();
- useDiscordRpc();
- useMPRIS();
- useMainPlayerListener();
- useMediaSession();
- usePlaybackHotkeys();
- useAutoDJ();
- useQueueRestoreTimestamp();
- useUpdateCurrentSong();
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
- useRadioAudioInstance();
- useRadioMetadata();
+const AudioPlayersContent = ({
+ audioContext,
+ audioDeviceId,
+ audioSampleRateHz,
+ playbackType,
+ resetSampleRate,
+ serverId,
+ setWebAudio,
+ webAudio,
+}: {
+ audioContext: ReturnType['webAudio'];
+ audioDeviceId: null | string | undefined;
+ audioSampleRateHz: number | undefined;
+ playbackType: PlayerType;
+ resetSampleRate: ReturnType['resetSampleRate'];
+ serverId: null | string;
+ setWebAudio: ReturnType['setWebAudio'];
+ webAudio: boolean;
+}) => {
+ const isRadioActive = useIsRadioActive();
useEffect(() => {
if (webAudio && 'AudioContext' in window) {
@@ -143,8 +178,6 @@ export const AudioPlayers = () => {
};
}, [serverId]);
- const isRadioActive = useIsRadioActive();
-
if (isRadioActive && playbackType === PlayerType.LOCAL) {
return ;
}
diff --git a/src/renderer/features/player/hooks/use-auto-dj.ts b/src/renderer/features/player/hooks/use-auto-dj.ts
index 892233945..864142d52 100644
--- a/src/renderer/features/player/hooks/use-auto-dj.ts
+++ b/src/renderer/features/player/hooks/use-auto-dj.ts
@@ -1,5 +1,5 @@
import { useQueryClient } from '@tanstack/react-query';
-import { useEffect } from 'react';
+import React, { useEffect } from 'react';
import { queryKeys } from '/@/renderer/api/query-keys';
import { eventEmitter } from '/@/renderer/events/event-emitter';
@@ -13,6 +13,7 @@ import {
useCurrentServerId,
usePlayerStore,
usePlayerStoreBase,
+ useSettingsStore,
} from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
import { logMsg } from '/@/renderer/utils/logger-message';
@@ -232,3 +233,18 @@ export const useAutoDJ = () => {
settings.timing,
]);
};
+
+const AutoDJHookInner = () => {
+ useAutoDJ();
+ return null;
+};
+
+export const AutoDJHook = () => {
+ const isAutoDJEnabled = useSettingsStore((state) => state.autoDJ.enabled);
+
+ if (!isAutoDJEnabled) {
+ return null;
+ }
+
+ return React.createElement(AutoDJHookInner);
+};
diff --git a/src/renderer/features/player/hooks/use-media-session.ts b/src/renderer/features/player/hooks/use-media-session.ts
index 5af751267..e43ac4fdd 100644
--- a/src/renderer/features/player/hooks/use-media-session.ts
+++ b/src/renderer/features/player/hooks/use-media-session.ts
@@ -1,11 +1,12 @@
import isElectron from 'is-electron';
-import { useCallback, useEffect, useMemo } from 'react';
+import React, { useCallback, useEffect, useMemo } from 'react';
import { getItemImageUrl } from '/@/renderer/components/item-image/item-image';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
import { usePlayer } from '/@/renderer/features/player/context/player-context';
import {
usePlaybackSettings,
+ usePlaybackType,
usePlayerStore,
useSettingsStore,
useSkipButtons,
@@ -143,3 +144,25 @@ export const useMediaSession = () => {
[isMediaSessionEnabled, mediaSession],
);
};
+
+const MediaSessionHookInner = () => {
+ useMediaSession();
+ return null;
+};
+
+export const MediaSessionHook = () => {
+ const isElectronEnv = isElectron();
+ const playbackType = usePlaybackType();
+ const isMediaSessionEnabled = useSettingsStore((state) => state.playback.mediaSession);
+
+ // We always want to enable media session when on web
+ // Otherwise, only enable if it is explicitly enabled in the settings AND using the web player
+ const shouldUseMediaSession =
+ !isElectronEnv || (isMediaSessionEnabled && playbackType === PlayerType.WEB);
+
+ if (!shouldUseMediaSession) {
+ return null;
+ }
+
+ return React.createElement(MediaSessionHookInner);
+};
diff --git a/src/renderer/features/player/hooks/use-mpris.ts b/src/renderer/features/player/hooks/use-mpris.ts
index d0c06af82..86d40bbd9 100644
--- a/src/renderer/features/player/hooks/use-mpris.ts
+++ b/src/renderer/features/player/hooks/use-mpris.ts
@@ -1,5 +1,5 @@
import isElectron from 'is-electron';
-import { useEffect } from 'react';
+import React, { useEffect } from 'react';
import { useItemImageUrl } from '/@/renderer/components/item-image/item-image';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
@@ -119,3 +119,20 @@ export const useMPRIS = () => {
[],
);
};
+
+const MPRISHookInner = () => {
+ useMPRIS();
+ return null;
+};
+
+export const MPRISHook = () => {
+ const isElectronEnv = isElectron();
+ const utils = isElectronEnv ? window.api.utils : null;
+ const mpris = isElectronEnv && utils?.isLinux() ? window.api.mpris : null;
+
+ if (mpris === null) {
+ return null;
+ }
+
+ return React.createElement(MPRISHookInner);
+};
diff --git a/src/renderer/features/player/hooks/use-playback-hotkeys.ts b/src/renderer/features/player/hooks/use-playback-hotkeys.ts
index a50b8c8d8..bf9932b2e 100644
--- a/src/renderer/features/player/hooks/use-playback-hotkeys.ts
+++ b/src/renderer/features/player/hooks/use-playback-hotkeys.ts
@@ -38,3 +38,8 @@ export const usePlaybackHotkeys = () => {
useHotkeys(playbackHotkeysItems);
};
+
+export const PlaybackHotkeysHook = () => {
+ usePlaybackHotkeys();
+ return null;
+};
diff --git a/src/renderer/features/player/hooks/use-power-save-blocker.ts b/src/renderer/features/player/hooks/use-power-save-blocker.ts
index 6bbe8ae2d..f797b0136 100644
--- a/src/renderer/features/player/hooks/use-power-save-blocker.ts
+++ b/src/renderer/features/player/hooks/use-power-save-blocker.ts
@@ -1,8 +1,7 @@
import isElectron from 'is-electron';
-import { useCallback, useEffect } from 'react';
+import React, { useCallback, useEffect } from 'react';
-import { usePlayerStatus } from '/@/renderer/store';
-import { useWindowSettings } from '/@/renderer/store';
+import { usePlayerStatus, useSettingsStore, useWindowSettings } from '/@/renderer/store';
import { PlayerStatus } from '/@/shared/types/types';
const ipc = isElectron() ? window.api.ipc : null;
@@ -48,3 +47,19 @@ export const usePowerSaveBlocker = () => {
};
}, [stopPowerSaveBlocker]);
};
+
+const PowerSaveBlockerHookInner = () => {
+ usePowerSaveBlocker();
+ return null;
+};
+
+export const PowerSaveBlockerHook = () => {
+ const isElectronEnv = isElectron();
+ const preventSleepOnPlayback = useSettingsStore((state) => state.window.preventSleepOnPlayback);
+
+ if (!isElectronEnv || !preventSleepOnPlayback) {
+ return null;
+ }
+
+ return React.createElement(PowerSaveBlockerHookInner);
+};
diff --git a/src/renderer/features/player/hooks/use-queue-restore.ts b/src/renderer/features/player/hooks/use-queue-restore.ts
index 361e4904f..146018903 100644
--- a/src/renderer/features/player/hooks/use-queue-restore.ts
+++ b/src/renderer/features/player/hooks/use-queue-restore.ts
@@ -32,6 +32,11 @@ export const useQueueRestoreTimestamp = () => {
);
};
+export const QueueRestoreTimestampHook = () => {
+ useQueueRestoreTimestamp();
+ return null;
+};
+
export const useSaveQueue = () => {
const serverId = useCurrentServerId();
diff --git a/src/renderer/features/player/hooks/use-scrobble.ts b/src/renderer/features/player/hooks/use-scrobble.ts
index 3084412a4..3e0468e57 100644
--- a/src/renderer/features/player/hooks/use-scrobble.ts
+++ b/src/renderer/features/player/hooks/use-scrobble.ts
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useItemImageUrl } from '/@/renderer/components/item-image/item-image';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
@@ -8,6 +8,7 @@ import {
usePlaybackSettings,
usePlayerSong,
usePlayerStore,
+ useSettingsStore,
useTimestampStoreBase,
} from '/@/renderer/store';
import { LogCategory, logFn } from '/@/renderer/utils/logger';
@@ -425,3 +426,19 @@ export const useScrobble = () => {
[handleScrobbleFromSongChange, handleProgressUpdate, handleScrobbleFromSeek],
);
};
+
+const ScrobbleHookInner = () => {
+ useScrobble();
+ return null;
+};
+
+export const ScrobbleHook = () => {
+ const isScrobbleEnabled = useSettingsStore((state) => state.playback.scrobble.enabled);
+ const privateMode = useAppStore((state) => state.privateMode);
+
+ if (!isScrobbleEnabled || privateMode) {
+ return null;
+ }
+
+ return React.createElement(ScrobbleHookInner);
+};
diff --git a/src/renderer/features/player/hooks/use-update-current-song.ts b/src/renderer/features/player/hooks/use-update-current-song.ts
index f403719e3..72ff1801d 100644
--- a/src/renderer/features/player/hooks/use-update-current-song.ts
+++ b/src/renderer/features/player/hooks/use-update-current-song.ts
@@ -80,3 +80,8 @@ export const useUpdateCurrentSong = () => {
[handleSongChange],
);
};
+
+export const UpdateCurrentSongHook = () => {
+ useUpdateCurrentSong();
+ return null;
+};
diff --git a/src/renderer/features/radio/hooks/use-radio-player.ts b/src/renderer/features/radio/hooks/use-radio-player.ts
index 30d417825..22bc3aab4 100644
--- a/src/renderer/features/radio/hooks/use-radio-player.ts
+++ b/src/renderer/features/radio/hooks/use-radio-player.ts
@@ -1,6 +1,6 @@
import IcecastMetadataStats from 'icecast-metadata-stats';
import isElectron from 'is-electron';
-import { useEffect } from 'react';
+import React, { useEffect } from 'react';
import { createWithEqualityFn } from 'zustand/traditional';
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
@@ -287,3 +287,33 @@ export const useRadioMetadata = () => {
};
}, [currentStreamUrl, setMetadata, isUsingMpv]);
};
+
+const RadioAudioInstanceHookInner = () => {
+ useRadioAudioInstance();
+ return null;
+};
+
+export const RadioAudioInstanceHook = () => {
+ const isRadioActive = useIsRadioActive();
+
+ if (!isRadioActive) {
+ return null;
+ }
+
+ return React.createElement(RadioAudioInstanceHookInner);
+};
+
+const RadioMetadataHookInner = () => {
+ useRadioMetadata();
+ return null;
+};
+
+export const RadioMetadataHook = () => {
+ const isRadioActive = useIsRadioActive();
+
+ if (!isRadioActive) {
+ return null;
+ }
+
+ return React.createElement(RadioMetadataHookInner);
+};