diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 241bff963..07733377a 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -794,6 +794,8 @@ "showVisualizerInSidebar": "show visualizer in player sidebar", "preservePitch_description": "preserves pitch when modifying playback speed", "preservePitch": "preserve pitch", + "audioFadeOnStatusChange": "audio fade on status change", + "audioFadeOnStatusChange_description": "enables fade out and fade in when play/pause status changes", "preventSleepOnPlayback_description": "prevent the display from sleeping while music is playing", "preventSleepOnPlayback": "prevent sleep on playback", "remotePassword_description": "sets the password for the remote control server. These credentials are by default transferred insecurely, so you should use a unique password that you do not care about", diff --git a/src/renderer/features/player/audio-player/mpv-player.tsx b/src/renderer/features/player/audio-player/mpv-player.tsx index 4f9edb4a0..9a0d2bc1e 100644 --- a/src/renderer/features/player/audio-player/mpv-player.tsx +++ b/src/renderer/features/player/audio-player/mpv-player.tsx @@ -27,7 +27,7 @@ export function MpvPlayer() { const { speed } = usePlayerProperties(); const isMuted = usePlayerMuted(); const volume = usePlayerVolume(); - const { transcode } = usePlaybackSettings(); + const { audioFadeOnStatusChange, transcode } = usePlaybackSettings(); const [localPlayerStatus, setLocalPlayerStatus] = useState(status); const [isTransitioning, setIsTransitioning] = useState(false); @@ -106,10 +106,20 @@ export function MpvPlayer() { }, onPlayerStatus: async (properties) => { const status = properties.status; - if (status === PlayerStatus.PAUSED) { - fadeAndSetStatus(volume, 0, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PAUSED); - } else if (status === PlayerStatus.PLAYING) { - fadeAndSetStatus(0, volume, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PLAYING); + if (audioFadeOnStatusChange) { + if (status === PlayerStatus.PAUSED) { + fadeAndSetStatus(volume, 0, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PAUSED); + } else if (status === PlayerStatus.PLAYING) { + fadeAndSetStatus(0, volume, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PLAYING); + } + } else { + if (status === PlayerStatus.PAUSED) { + playerRef.current?.setVolume(0); + setLocalPlayerStatus(PlayerStatus.PAUSED); + } else if (status === PlayerStatus.PLAYING) { + playerRef.current?.setVolume(volume); + setLocalPlayerStatus(PlayerStatus.PLAYING); + } } }, onPlayerVolume: (properties) => { @@ -117,7 +127,7 @@ export function MpvPlayer() { playerRef.current?.setVolume(volume); }, }, - [volume, fadeAndSetStatus], + [volume, fadeAndSetStatus, audioFadeOnStatusChange], ); // Cleanup fade interval on unmount diff --git a/src/renderer/features/player/audio-player/web-player.tsx b/src/renderer/features/player/audio-player/web-player.tsx index c2e3c093b..640d495d9 100644 --- a/src/renderer/features/player/audio-player/web-player.tsx +++ b/src/renderer/features/player/audio-player/web-player.tsx @@ -36,7 +36,7 @@ export function WebPlayer() { const { crossfadeDuration, crossfadeStyle, speed, transitionType } = usePlayerProperties(); const isMuted = usePlayerMuted(); const volume = usePlayerVolume(); - const { preservePitch, transcode } = usePlaybackSettings(); + const { audioFadeOnStatusChange, preservePitch, transcode } = usePlaybackSettings(); const [localPlayerStatus, setLocalPlayerStatus] = useState(status); const [isTransitioning, setIsTransitioning] = useState(false); @@ -239,10 +239,20 @@ export function WebPlayer() { } } - if (status === PlayerStatus.PAUSED) { - fadeAndSetStatus(volume, 0, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PAUSED); - } else if (status === PlayerStatus.PLAYING) { - fadeAndSetStatus(0, volume, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PLAYING); + if (audioFadeOnStatusChange) { + if (status === PlayerStatus.PAUSED) { + fadeAndSetStatus(volume, 0, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PAUSED); + } else if (status === PlayerStatus.PLAYING) { + fadeAndSetStatus(0, volume, PLAY_PAUSE_FADE_DURATION, PlayerStatus.PLAYING); + } + } else { + if (status === PlayerStatus.PAUSED) { + playerRef.current?.setVolume(0); + setLocalPlayerStatus(PlayerStatus.PAUSED); + } else if (status === PlayerStatus.PLAYING) { + playerRef.current?.setVolume(volume); + setLocalPlayerStatus(PlayerStatus.PLAYING); + } } }, onPlayerVolume: (properties) => { @@ -250,7 +260,7 @@ export function WebPlayer() { playerRef.current?.setVolume(volume); }, }, - [volume, num, isTransitioning, transitionType], + [volume, num, isTransitioning, transitionType, audioFadeOnStatusChange], ); // Cleanup fade interval on unmount diff --git a/src/renderer/features/settings/components/playback/audio-settings.tsx b/src/renderer/features/settings/components/playback/audio-settings.tsx index 498ac54ce..46f9f353f 100644 --- a/src/renderer/features/settings/components/playback/audio-settings.tsx +++ b/src/renderer/features/settings/components/playback/audio-settings.tsx @@ -135,6 +135,28 @@ export const AudioSettings = () => { postProcess: 'sentenceCase', }), }, + { + control: ( + { + setSettings({ + playback: { + ...settings, + audioFadeOnStatusChange: e.currentTarget.checked, + }, + }); + }} + /> + ), + description: t('setting.audioFadeOnStatusChange', { + context: 'description', + postProcess: 'sentenceCase', + }), + title: t('setting.audioFadeOnStatusChange', { + postProcess: 'sentenceCase', + }), + }, ]; return ( diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts index 9b84580a6..b77fb2737 100644 --- a/src/renderer/store/settings.store.ts +++ b/src/renderer/store/settings.store.ts @@ -304,6 +304,7 @@ const ScrobbleSettingsSchema = z.object({ const PlaybackSettingsSchema = z.object({ audioDeviceId: z.string().nullable().optional(), + audioFadeOnStatusChange: z.boolean(), mediaSession: z.boolean(), mpvExtraParameters: z.array(z.string()), mpvProperties: MpvSettingsSchema, @@ -1137,6 +1138,7 @@ const initialState: SettingsState = { }, playback: { audioDeviceId: undefined, + audioFadeOnStatusChange: true, mediaSession: false, mpvExtraParameters: [], mpvProperties: {