mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
fix preserve pitch on player start, add to player config (#1349)
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import { UseSuspenseQueryOptions } from '@tanstack/react-query';
|
import { UseSuspenseQueryOptions } from '@tanstack/react-query';
|
||||||
import { ref } from 'process';
|
|
||||||
|
|
||||||
import { api } from '/@/renderer/api';
|
import { api } from '/@/renderer/api';
|
||||||
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
import { useItemListPaginatedLoader } from '/@/renderer/components/item-list/helpers/item-list-paginated-loader';
|
||||||
@@ -77,7 +76,6 @@ export const AlbumArtistListPaginatedGrid = ({
|
|||||||
itemsPerRow={itemsPerRow}
|
itemsPerRow={itemsPerRow}
|
||||||
itemType={LibraryItem.ALBUM_ARTIST}
|
itemType={LibraryItem.ALBUM_ARTIST}
|
||||||
onScrollEnd={handleOnScrollEnd}
|
onScrollEnd={handleOnScrollEnd}
|
||||||
ref={ref}
|
|
||||||
rows={rows}
|
rows={rows}
|
||||||
/>
|
/>
|
||||||
</ItemListWithPagination>
|
</ItemListWithPagination>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { RefObject } from 'react';
|
import type { RefObject } from 'react';
|
||||||
|
|
||||||
import { useEffect, useImperativeHandle, useRef, useState } from 'react';
|
import { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
||||||
import ReactPlayer from 'react-player';
|
import ReactPlayer from 'react-player';
|
||||||
|
|
||||||
import { AudioPlayer, PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
|
import { AudioPlayer, PlayerOnProgressProps } from '/@/renderer/features/player/audio-player/types';
|
||||||
@@ -153,15 +153,37 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const player1 = player1Ref.current?.getInternalPlayer();
|
const player1 = player1Ref.current?.getInternalPlayer();
|
||||||
if (player1) {
|
if (player1 && player1 instanceof HTMLAudioElement) {
|
||||||
player1.preservesPitch = preservesPitch;
|
player1.preservesPitch = preservesPitch;
|
||||||
}
|
}
|
||||||
const player2 = player2Ref.current?.getInternalPlayer();
|
const player2 = player2Ref.current?.getInternalPlayer();
|
||||||
if (player2) {
|
if (player2 && player2 instanceof HTMLAudioElement) {
|
||||||
player2.preservesPitch = preservesPitch;
|
player2.preservesPitch = preservesPitch;
|
||||||
}
|
}
|
||||||
}, [preservesPitch]);
|
}, [preservesPitch]);
|
||||||
|
|
||||||
|
const handleOnReadyPlayer1 = useCallback(
|
||||||
|
(player: ReactPlayer) => {
|
||||||
|
const internal = player.getInternalPlayer();
|
||||||
|
if (internal && internal instanceof HTMLAudioElement) {
|
||||||
|
internal.preservesPitch = preservesPitch;
|
||||||
|
}
|
||||||
|
onStartedPlayer1(player);
|
||||||
|
},
|
||||||
|
[onStartedPlayer1, preservesPitch],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOnReadyPlayer2 = useCallback(
|
||||||
|
(player: ReactPlayer) => {
|
||||||
|
const internal = player.getInternalPlayer();
|
||||||
|
if (internal && internal instanceof HTMLAudioElement) {
|
||||||
|
internal.preservesPitch = preservesPitch;
|
||||||
|
}
|
||||||
|
onStartedPlayer2(player);
|
||||||
|
},
|
||||||
|
[onStartedPlayer2, preservesPitch],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="web-player-engine" style={{ display: 'none' }}>
|
<div id="web-player-engine" style={{ display: 'none' }}>
|
||||||
<ReactPlayer
|
<ReactPlayer
|
||||||
@@ -175,7 +197,7 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
|
|||||||
onEnded={src1 ? () => onEndedPlayer1() : undefined}
|
onEnded={src1 ? () => onEndedPlayer1() : undefined}
|
||||||
onError={handleOnError(player1Ref, () => onEndedPlayer1())}
|
onError={handleOnError(player1Ref, () => onEndedPlayer1())}
|
||||||
onProgress={onProgressPlayer1}
|
onProgress={onProgressPlayer1}
|
||||||
onReady={onStartedPlayer1}
|
onReady={handleOnReadyPlayer1}
|
||||||
playbackRate={speed || 1}
|
playbackRate={speed || 1}
|
||||||
playing={playerNum === 1 && playerStatus === PlayerStatus.PLAYING}
|
playing={playerNum === 1 && playerStatus === PlayerStatus.PLAYING}
|
||||||
progressInterval={isTransitioning ? 10 : 250}
|
progressInterval={isTransitioning ? 10 : 250}
|
||||||
@@ -195,7 +217,7 @@ export const WebPlayerEngine = (props: WebPlayerEngineProps) => {
|
|||||||
onEnded={src2 ? () => onEndedPlayer2() : undefined}
|
onEnded={src2 ? () => onEndedPlayer2() : undefined}
|
||||||
onError={handleOnError(player2Ref, () => onEndedPlayer2())}
|
onError={handleOnError(player2Ref, () => onEndedPlayer2())}
|
||||||
onProgress={onProgressPlayer2}
|
onProgress={onProgressPlayer2}
|
||||||
onReady={onStartedPlayer2}
|
onReady={handleOnReadyPlayer2}
|
||||||
playbackRate={speed || 1}
|
playbackRate={speed || 1}
|
||||||
playing={playerNum === 2 && playerStatus === PlayerStatus.PLAYING}
|
playing={playerNum === 2 && playerStatus === PlayerStatus.PLAYING}
|
||||||
progressInterval={isTransitioning ? 10 : 250}
|
progressInterval={isTransitioning ? 10 : 250}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { ListConfigTable } from '/@/renderer/features/shared/components/list-config-menu';
|
import { ListConfigTable } from '/@/renderer/features/shared/components/list-config-menu';
|
||||||
@@ -11,12 +11,17 @@ import {
|
|||||||
usePlayerSpeed,
|
usePlayerSpeed,
|
||||||
usePlayerStatus,
|
usePlayerStatus,
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
import {
|
||||||
|
usePlaybackSettings,
|
||||||
|
useSettingsStore,
|
||||||
|
useSettingsStoreActions,
|
||||||
|
} from '/@/renderer/store/settings.store';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
||||||
import { Popover } from '/@/shared/components/popover/popover';
|
import { Popover } from '/@/shared/components/popover/popover';
|
||||||
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
|
import { SegmentedControl } from '/@/shared/components/segmented-control/segmented-control';
|
||||||
import { Select } from '/@/shared/components/select/select';
|
import { Select } from '/@/shared/components/select/select';
|
||||||
import { Slider } from '/@/shared/components/slider/slider';
|
import { Slider } from '/@/shared/components/slider/slider';
|
||||||
|
import { Switch } from '/@/shared/components/switch/switch';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import {
|
import {
|
||||||
CrossfadeStyle,
|
CrossfadeStyle,
|
||||||
@@ -42,9 +47,20 @@ export const PlayerConfig = () => {
|
|||||||
const { crossfadeDuration, crossfadeStyle, transitionType } = usePlayerProperties();
|
const { crossfadeDuration, crossfadeStyle, transitionType } = usePlayerProperties();
|
||||||
const { setCrossfadeDuration, setCrossfadeStyle, setQueueType, setSpeed, setTransitionType } =
|
const { setCrossfadeDuration, setCrossfadeStyle, setQueueType, setSpeed, setTransitionType } =
|
||||||
usePlayerActions();
|
usePlayerActions();
|
||||||
|
const preservePitch = useSettingsStore((state) => state.playback.preservePitch);
|
||||||
|
|
||||||
const playbackSettings = usePlaybackSettings();
|
const playbackSettings = usePlaybackSettings();
|
||||||
const { setSettings } = useSettingsStoreActions();
|
const { setSettings } = useSettingsStoreActions();
|
||||||
|
|
||||||
|
const setPreservePitch = useCallback(
|
||||||
|
(value: boolean) => {
|
||||||
|
setSettings({
|
||||||
|
playback: { ...playbackSettings, preservePitch: value },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[playbackSettings, setSettings],
|
||||||
|
);
|
||||||
|
|
||||||
const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]);
|
const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -288,26 +304,38 @@ export const PlayerConfig = () => {
|
|||||||
id: 'playbackSpeed',
|
id: 'playbackSpeed',
|
||||||
label: t('player.playbackSpeed', { postProcess: 'titleCase' }),
|
label: t('player.playbackSpeed', { postProcess: 'titleCase' }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
component: (
|
||||||
|
<Switch
|
||||||
|
defaultChecked={preservePitch}
|
||||||
|
onChange={(e) => setPreservePitch(e.currentTarget.checked)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
id: 'preservePitch',
|
||||||
|
label: t('setting.preservePitch', { postProcess: 'titleCase' }),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return allOptions;
|
return allOptions;
|
||||||
}, [
|
}, [
|
||||||
playbackSettings,
|
t,
|
||||||
audioDevices,
|
|
||||||
status,
|
|
||||||
setSettings,
|
|
||||||
currentSong,
|
|
||||||
speed,
|
|
||||||
setSpeed,
|
|
||||||
queueType,
|
queueType,
|
||||||
setQueueType,
|
playbackSettings,
|
||||||
|
status,
|
||||||
|
audioDevices,
|
||||||
transitionType,
|
transitionType,
|
||||||
setTransitionType,
|
crossfadeStyle,
|
||||||
crossfadeDuration,
|
crossfadeDuration,
|
||||||
setCrossfadeDuration,
|
setCrossfadeDuration,
|
||||||
crossfadeStyle,
|
speed,
|
||||||
|
setSpeed,
|
||||||
|
preservePitch,
|
||||||
|
currentSong?.bpm,
|
||||||
|
setQueueType,
|
||||||
|
setSettings,
|
||||||
|
setTransitionType,
|
||||||
setCrossfadeStyle,
|
setCrossfadeStyle,
|
||||||
t,
|
setPreservePitch,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user