mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 02:13:33 +00:00
provide transcoding support
This commit is contained in:
parent
da95a644c8
commit
528bef01f0
24 changed files with 347 additions and 69 deletions
|
|
@ -65,6 +65,7 @@ import { ItemDetailsModal } from '/@/renderer/features/item-details/components/i
|
|||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||
import { controller } from '/@/renderer/api/controller';
|
||||
import { api } from '/@/renderer/api';
|
||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
type ContextMenuContextProps = {
|
||||
closeContextMenu: () => void;
|
||||
|
|
@ -92,7 +93,6 @@ const JELLYFIN_IGNORED_MENU_ITEMS: ContextMenuItemType[] = ['setRating', 'shareI
|
|||
// const NAVIDROME_IGNORED_MENU_ITEMS: ContextMenuItemType[] = [];
|
||||
// const SUBSONIC_IGNORED_MENU_ITEMS: ContextMenuItemType[] = [];
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
const utils = isElectron() ? window.electron.utils : null;
|
||||
|
||||
export interface ContextMenuProviderProps {
|
||||
|
|
@ -610,7 +610,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
const playerData = moveToBottomOfQueue(uniqueIds);
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
}, [ctx.dataNodes, moveToBottomOfQueue, playbackType]);
|
||||
|
||||
|
|
@ -621,7 +621,7 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
const playerData = moveToTopOfQueue(uniqueIds);
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
}, [ctx.dataNodes, moveToTopOfQueue, playbackType]);
|
||||
|
||||
|
|
@ -651,9 +651,9 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
if (isCurrentSongRemoved) {
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
} else {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -687,7 +687,9 @@ export const ContextMenuProvider = ({ children }: ContextMenuProviderProps) => {
|
|||
},
|
||||
query: { albumArtistIds: item.albumArtistIds, songId: item.id },
|
||||
});
|
||||
handlePlayQueueAdd?.({ byData: [ctx.data[0], ...songs], playType: Play.NOW });
|
||||
if (songs) {
|
||||
handlePlayQueueAdd?.({ byData: [ctx.data[0], ...songs], playType: Play.NOW });
|
||||
}
|
||||
}, [ctx, handlePlayQueueAdd]);
|
||||
|
||||
const handleDownload = useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { usePlaybackType } from '/@/renderer/store/settings.store';
|
|||
import { usePlayerStore, useSetCurrentTime } from '../../../store/player.store';
|
||||
import { TableConfigDropdown } from '/@/renderer/components/virtual-table';
|
||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
|
|||
const playerData = moveToBottomOfQueue(uniqueIds);
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
|
|||
const playerData = moveToTopOfQueue(uniqueIds);
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -72,9 +73,9 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
|
|||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
if (isCurrentSongRemoved) {
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
} else {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +88,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
|
|||
const playerData = clearQueue();
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
mpvPlayer!.pause();
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +102,7 @@ export const PlayQueueListControls = ({ type, tableRef }: PlayQueueListOptionsPr
|
|||
const playerData = shuffleQueue();
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-gr
|
|||
import { useAppFocus } from '/@/renderer/hooks';
|
||||
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref<any>) => {
|
|||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.volume(volume);
|
||||
mpvPlayer!.setQueue(playerData, false);
|
||||
setQueue(playerData, false);
|
||||
} else {
|
||||
const player =
|
||||
playerData.current.player === 1
|
||||
|
|
@ -117,7 +118,7 @@ export const PlayQueue = forwardRef(({ type }: QueueProps, ref: Ref<any>) => {
|
|||
const playerData = reorderQueue(selectedUniqueIds as string[], e.overNode?.data?.uniqueId);
|
||||
|
||||
if (playbackType === PlaybackType.LOCAL) {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
|
||||
if (type === 'sideDrawerQueue') {
|
||||
|
|
|
|||
|
|
@ -137,7 +137,9 @@ export const CenterControls = ({ playersRef }: CenterControlsProps) => {
|
|||
if (!isElectron() || playbackType === PlaybackType.WEB) {
|
||||
// Update twice a second for slightly better performance
|
||||
interval = setInterval(() => {
|
||||
setCurrentTime(currentPlayerRef.getCurrentTime());
|
||||
if (currentPlayerRef) {
|
||||
setCurrentTime(currentPlayerRef.getCurrentTime());
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import debounce from 'lodash/debounce';
|
|||
import { toast } from '/@/renderer/components';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||
import { setAutoNext, setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
const mpvPlayerListener = isElectron() ? window.electron.mpvPlayerListener : null;
|
||||
|
|
@ -131,30 +132,30 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
if (shuffleStatus === PlayerShuffle.NONE) {
|
||||
const playerData = setShuffle(PlayerShuffle.TRACK);
|
||||
remote?.updateShuffle(true);
|
||||
return mpvPlayer?.setQueueNext(playerData);
|
||||
return setQueueNext(playerData);
|
||||
}
|
||||
|
||||
const playerData = setShuffle(PlayerShuffle.NONE);
|
||||
remote?.updateShuffle(false);
|
||||
return mpvPlayer?.setQueueNext(playerData);
|
||||
return setQueueNext(playerData);
|
||||
}, [setShuffle, shuffleStatus]);
|
||||
|
||||
const handleToggleRepeat = useCallback(() => {
|
||||
if (repeatStatus === PlayerRepeat.NONE) {
|
||||
const playerData = setRepeat(PlayerRepeat.ALL);
|
||||
remote?.updateRepeat(PlayerRepeat.ALL);
|
||||
return mpvPlayer?.setQueueNext(playerData);
|
||||
return setQueueNext(playerData);
|
||||
}
|
||||
|
||||
if (repeatStatus === PlayerRepeat.ALL) {
|
||||
const playerData = setRepeat(PlayerRepeat.ONE);
|
||||
remote?.updateRepeat(PlayerRepeat.ONE);
|
||||
return mpvPlayer?.setQueueNext(playerData);
|
||||
return setQueueNext(playerData);
|
||||
}
|
||||
|
||||
const playerData = setRepeat(PlayerRepeat.NONE);
|
||||
remote?.updateRepeat(PlayerRepeat.NONE);
|
||||
return mpvPlayer?.setQueueNext(playerData);
|
||||
return setQueueNext(playerData);
|
||||
}, [repeatStatus, setRepeat]);
|
||||
|
||||
const checkIsLastTrack = useCallback(() => {
|
||||
|
|
@ -172,7 +173,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
local: () => {
|
||||
const playerData = autoNext();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.autoNext(playerData);
|
||||
setAutoNext(playerData);
|
||||
play();
|
||||
},
|
||||
web: () => {
|
||||
|
|
@ -186,12 +187,12 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
if (isLastTrack) {
|
||||
const playerData = setCurrentIndex(0);
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData, true);
|
||||
setQueue(playerData, true);
|
||||
pause();
|
||||
} else {
|
||||
const playerData = autoNext();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.autoNext(playerData);
|
||||
setAutoNext(playerData);
|
||||
play();
|
||||
}
|
||||
},
|
||||
|
|
@ -211,7 +212,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
local: () => {
|
||||
const playerData = autoNext();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.autoNext(playerData);
|
||||
setAutoNext(playerData);
|
||||
play();
|
||||
},
|
||||
web: () => {
|
||||
|
|
@ -257,7 +258,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
local: () => {
|
||||
const playerData = next();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
},
|
||||
web: () => {
|
||||
const playerData = next();
|
||||
|
|
@ -270,12 +271,12 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
if (isLastTrack) {
|
||||
const playerData = setCurrentIndex(0);
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData, true);
|
||||
setQueue(playerData, true);
|
||||
pause();
|
||||
} else {
|
||||
const playerData = next();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
}
|
||||
},
|
||||
web: () => {
|
||||
|
|
@ -297,7 +298,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
if (!isLastTrack) {
|
||||
const playerData = next();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
}
|
||||
},
|
||||
web: () => {
|
||||
|
|
@ -358,11 +359,11 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
if (!isFirstTrack) {
|
||||
const playerData = previous();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
} else {
|
||||
const playerData = setCurrentIndex(queue.length - 1);
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
}
|
||||
},
|
||||
web: () => {
|
||||
|
|
@ -383,12 +384,12 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
if (isFirstTrack) {
|
||||
const playerData = setCurrentIndex(0);
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData, true);
|
||||
setQueue(playerData, true);
|
||||
pause();
|
||||
} else {
|
||||
const playerData = previous();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
}
|
||||
},
|
||||
web: () => {
|
||||
|
|
@ -407,7 +408,7 @@ export const useCenterControls = (args: { playersRef: any }) => {
|
|||
local: () => {
|
||||
const playerData = previous();
|
||||
updateSong(playerData.current.song);
|
||||
mpvPlayer!.setQueue(playerData);
|
||||
setQueue(playerData);
|
||||
},
|
||||
web: () => {
|
||||
const playerData = previous();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { queryKeys } from '/@/renderer/api/query-keys';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { PlayersRef } from '/@/renderer/features/player/ref/players-ref';
|
||||
import { updateSong } from '/@/renderer/features/player/update-remote-song';
|
||||
import { setQueue, setQueueNext } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
const getRootQueryKey = (itemType: LibraryItem, serverId: string) => {
|
||||
let queryKey;
|
||||
|
|
@ -180,9 +181,9 @@ export const useHandlePlayQueueAdd = () => {
|
|||
|
||||
if (playType === Play.NOW || !hadSong) {
|
||||
mpvPlayer!.pause();
|
||||
mpvPlayer!.setQueue(playerData, false);
|
||||
setQueue(playerData, false);
|
||||
} else {
|
||||
mpvPlayer!.setQueueNext(playerData);
|
||||
setQueueNext(playerData);
|
||||
}
|
||||
} else {
|
||||
const player =
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@ import { useCurrentStatus, usePlayerStore } from '/@/renderer/store';
|
|||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { PlaybackType, PlayerStatus, PlaybackStyle, CrossfadeStyle } from '/@/renderer/types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const mpvPlayer = isElectron() ? window.electron.mpvPlayer : null;
|
||||
import { setQueue } from '/@/renderer/utils/set-transcoded-queue-data';
|
||||
|
||||
const getAudioDevice = async () => {
|
||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||
|
|
@ -62,7 +61,7 @@ export const AudioSettings = ({ hasFancyAudio }: { hasFancyAudio: boolean }) =>
|
|||
setSettings({ playback: { ...settings, type: e as PlaybackType } });
|
||||
if (isElectron() && e === PlaybackType.LOCAL) {
|
||||
const queueData = usePlayerStore.getState().actions.getPlayerData();
|
||||
mpvPlayer!.setQueue(queueData);
|
||||
setQueue(queueData);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import isElectron from 'is-electron';
|
|||
import { LyricSettings } from '/@/renderer/features/settings/components/playback/lyric-settings';
|
||||
import { useSettingsStore } from '/@/renderer/store';
|
||||
import { PlaybackType } from '/@/renderer/types';
|
||||
import { TranscodeSettings } from '/@/renderer/features/settings/components/playback/transcode-settings';
|
||||
|
||||
const MpvSettings = lazy(() =>
|
||||
import('/@/renderer/features/settings/components/playback/mpv-settings').then((module) => {
|
||||
|
|
@ -28,6 +29,7 @@ export const PlaybackTab = () => {
|
|||
<Stack spacing="md">
|
||||
<AudioSettings hasFancyAudio={hasFancyAudio} />
|
||||
<Suspense fallback={<></>}>{hasFancyAudio && <MpvSettings />}</Suspense>
|
||||
<TranscodeSettings />
|
||||
<ScrobbleSettings />
|
||||
<LyricSettings />
|
||||
</Stack>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,89 @@
|
|||
import { NumberInput, Switch, TextInput } from '/@/renderer/components';
|
||||
import { usePlaybackSettings, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||
import { SettingOption, SettingsSection } from '../settings-section';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export const TranscodeSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
const { transcode } = usePlaybackSettings();
|
||||
const { setTranscodingConfig } = useSettingsStoreActions();
|
||||
const note = t('setting.transcodeNote', { postProcess: 'sentenceCase' });
|
||||
|
||||
const transcodeOptions: SettingOption[] = [
|
||||
{
|
||||
control: (
|
||||
<Switch
|
||||
aria-label="Toggle transcode"
|
||||
defaultChecked={transcode.enabled}
|
||||
onChange={(e) => {
|
||||
setTranscodingConfig({
|
||||
...transcode,
|
||||
enabled: e.currentTarget.checked,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description: t('setting.transcode', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
note,
|
||||
title: t('setting.transcode', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<NumberInput
|
||||
aria-label="Transcode bitrate"
|
||||
defaultValue={transcode.bitrate}
|
||||
min={0}
|
||||
placeholder="mp3, opus"
|
||||
w={100}
|
||||
onBlur={(e) => {
|
||||
setTranscodingConfig({
|
||||
...transcode,
|
||||
bitrate: e.currentTarget.value
|
||||
? Number(e.currentTarget.value)
|
||||
: undefined,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description: t('setting.transcodeBitrate', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
isHidden: !transcode.enabled,
|
||||
note,
|
||||
title: t('setting.transcodeBitrate', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
{
|
||||
control: (
|
||||
<TextInput
|
||||
aria-label="transcoding format"
|
||||
defaultValue={transcode.format}
|
||||
width={100}
|
||||
onBlur={(e) => {
|
||||
setTranscodingConfig({
|
||||
...transcode,
|
||||
format: e.currentTarget.value || undefined,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
),
|
||||
description: t('setting.transcodeFormat', {
|
||||
context: 'description',
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
isHidden: !transcode.enabled,
|
||||
note,
|
||||
title: t('setting.transcodeFormat', { postProcess: 'sentenceCase' }),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<SettingsSection
|
||||
divider
|
||||
options={transcodeOptions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue