Audio Player: Fix queue order, memory leaks and reduce calculations (#1543)
This commit is contained in:
parent
1a6f0bb28f
commit
50865c78f5
@ -125,7 +125,6 @@ const Audio: FC<OwnProps> = ({
|
|||||||
makeTrackId(message),
|
makeTrackId(message),
|
||||||
getMediaDuration(message)!,
|
getMediaDuration(message)!,
|
||||||
isVoice ? 'voice' : 'audio',
|
isVoice ? 'voice' : 'audio',
|
||||||
origin,
|
|
||||||
mediaData,
|
mediaData,
|
||||||
bufferingHandlers,
|
bufferingHandlers,
|
||||||
undefined,
|
undefined,
|
||||||
@ -172,9 +171,10 @@ const Audio: FC<OwnProps> = ({
|
|||||||
onPlay(message.id, message.chatId);
|
onPlay(message.id, message.chatId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDispatch().setAudioPlayerOrigin({ origin });
|
||||||
setIsActivated(!isActivated);
|
setIsActivated(!isActivated);
|
||||||
playPause();
|
playPause();
|
||||||
}, [isPlaying, isUploading, message.id, message.chatId, onCancelUpload, onPlay, playPause, isActivated]);
|
}, [isUploading, isPlaying, isActivated, playPause, onCancelUpload, onPlay, message.id, message.chatId, origin]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onReadMedia && isMediaUnread && (isPlaying || isDownloading)) {
|
if (onReadMedia && isMediaUnread && (isPlaying || isDownloading)) {
|
||||||
|
|||||||
@ -77,7 +77,7 @@ const AudioResults: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
}, [focusMessage]);
|
}, [focusMessage]);
|
||||||
|
|
||||||
const handlePlayAudio = useCallback((messageId: number, chatId: string) => {
|
const handlePlayAudio = useCallback((messageId: number, chatId: string) => {
|
||||||
openAudioPlayer({ chatId, messageId, origin: AudioOrigin.Search });
|
openAudioPlayer({ chatId, messageId });
|
||||||
}, [openAudioPlayer]);
|
}, [openAudioPlayer]);
|
||||||
|
|
||||||
function renderList() {
|
function renderList() {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import React, {
|
|||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { getGlobal, withGlobal } from '../../lib/teact/teactn';
|
import { getGlobal, withGlobal } from '../../lib/teact/teactn';
|
||||||
|
|
||||||
import { AudioOrigin, LangCode } from '../../types';
|
import { LangCode } from '../../types';
|
||||||
import { GlobalActions } from '../../global/types';
|
import { GlobalActions } from '../../global/types';
|
||||||
import { ApiMessage } from '../../api/types';
|
import { ApiMessage } from '../../api/types';
|
||||||
|
|
||||||
@ -56,7 +56,6 @@ type StateProps = {
|
|||||||
hasNotifications: boolean;
|
hasNotifications: boolean;
|
||||||
hasDialogs: boolean;
|
hasDialogs: boolean;
|
||||||
audioMessage?: ApiMessage;
|
audioMessage?: ApiMessage;
|
||||||
audioOrigin?: AudioOrigin;
|
|
||||||
safeLinkModalUrl?: string;
|
safeLinkModalUrl?: string;
|
||||||
isHistoryCalendarOpen: boolean;
|
isHistoryCalendarOpen: boolean;
|
||||||
shouldSkipHistoryAnimations?: boolean;
|
shouldSkipHistoryAnimations?: boolean;
|
||||||
@ -89,7 +88,6 @@ const Main: FC<StateProps & DispatchProps> = ({
|
|||||||
hasNotifications,
|
hasNotifications,
|
||||||
hasDialogs,
|
hasDialogs,
|
||||||
audioMessage,
|
audioMessage,
|
||||||
audioOrigin,
|
|
||||||
safeLinkModalUrl,
|
safeLinkModalUrl,
|
||||||
isHistoryCalendarOpen,
|
isHistoryCalendarOpen,
|
||||||
shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations,
|
||||||
@ -265,7 +263,7 @@ const Main: FC<StateProps & DispatchProps> = ({
|
|||||||
<ForwardPicker isOpen={isForwardModalOpen} />
|
<ForwardPicker isOpen={isForwardModalOpen} />
|
||||||
<Notifications isOpen={hasNotifications} />
|
<Notifications isOpen={hasNotifications} />
|
||||||
<Dialogs isOpen={hasDialogs} />
|
<Dialogs isOpen={hasDialogs} />
|
||||||
{audioMessage && <AudioPlayer key={audioMessage.id} message={audioMessage} origin={audioOrigin} noUi />}
|
{audioMessage && <AudioPlayer key={audioMessage.id} message={audioMessage} noUi />}
|
||||||
<SafeLinkModal url={safeLinkModalUrl} />
|
<SafeLinkModal url={safeLinkModalUrl} />
|
||||||
<HistoryCalendar isOpen={isHistoryCalendarOpen} />
|
<HistoryCalendar isOpen={isHistoryCalendarOpen} />
|
||||||
<StickerSetModal
|
<StickerSetModal
|
||||||
@ -302,7 +300,7 @@ function updatePageTitle(nextTitle: string) {
|
|||||||
export default memo(withGlobal(
|
export default memo(withGlobal(
|
||||||
(global): StateProps => {
|
(global): StateProps => {
|
||||||
const { settings: { byKey: { animationLevel, language, wasTimeFormatSetManually } } } = global;
|
const { settings: { byKey: { animationLevel, language, wasTimeFormatSetManually } } } = global;
|
||||||
const { chatId: audioChatId, messageId: audioMessageId, origin } = global.audioPlayer;
|
const { chatId: audioChatId, messageId: audioMessageId } = global.audioPlayer;
|
||||||
const audioMessage = audioChatId && audioMessageId
|
const audioMessage = audioChatId && audioMessageId
|
||||||
? selectChatMessage(global, audioChatId, audioMessageId)
|
? selectChatMessage(global, audioChatId, audioMessageId)
|
||||||
: undefined;
|
: undefined;
|
||||||
@ -316,7 +314,6 @@ export default memo(withGlobal(
|
|||||||
hasNotifications: Boolean(global.notifications.length),
|
hasNotifications: Boolean(global.notifications.length),
|
||||||
hasDialogs: Boolean(global.dialogs.length),
|
hasDialogs: Boolean(global.dialogs.length),
|
||||||
audioMessage,
|
audioMessage,
|
||||||
audioOrigin: origin,
|
|
||||||
safeLinkModalUrl: global.safeLinkModalUrl,
|
safeLinkModalUrl: global.safeLinkModalUrl,
|
||||||
isHistoryCalendarOpen: Boolean(global.historyCalendarSelectedAt),
|
isHistoryCalendarOpen: Boolean(global.historyCalendarSelectedAt),
|
||||||
shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations,
|
shouldSkipHistoryAnimations: global.shouldSkipHistoryAnimations,
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../util/enviro
|
|||||||
|
|
||||||
import * as mediaLoader from '../../util/mediaLoader';
|
import * as mediaLoader from '../../util/mediaLoader';
|
||||||
import {
|
import {
|
||||||
getMediaDuration, getMessageContent, getMessageMediaHash, getSenderTitle,
|
getMediaDuration, getMessageContent, getMessageMediaHash, getSenderTitle, isMessageLocal,
|
||||||
} from '../../modules/helpers';
|
} from '../../modules/helpers';
|
||||||
import { selectChat, selectSender } from '../../modules/selectors';
|
import { selectChat, selectSender } from '../../modules/selectors';
|
||||||
import { pick } from '../../util/iteratees';
|
import { pick } from '../../util/iteratees';
|
||||||
@ -59,7 +59,6 @@ const FAST_PLAYBACK_RATE = 1.8;
|
|||||||
|
|
||||||
const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||||
message,
|
message,
|
||||||
origin = AudioOrigin.Inline,
|
|
||||||
className,
|
className,
|
||||||
noUi,
|
noUi,
|
||||||
sender,
|
sender,
|
||||||
@ -95,7 +94,6 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
makeTrackId(message),
|
makeTrackId(message),
|
||||||
getMediaDuration(message)!,
|
getMediaDuration(message)!,
|
||||||
isVoice ? 'voice' : 'audio',
|
isVoice ? 'voice' : 'audio',
|
||||||
origin,
|
|
||||||
mediaData,
|
mediaData,
|
||||||
undefined,
|
undefined,
|
||||||
mediaMetadata,
|
mediaMetadata,
|
||||||
@ -103,7 +101,7 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
true,
|
true,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
undefined,
|
||||||
true,
|
isMessageLocal(message),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -176,7 +174,7 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
color="translucent"
|
color="translucent"
|
||||||
size="smaller"
|
size="smaller"
|
||||||
className="player-button"
|
className="player-button"
|
||||||
disabled={isFirst}
|
disabled={isFirst()}
|
||||||
onClick={requestPreviousTrack}
|
onClick={requestPreviousTrack}
|
||||||
ariaLabel="Previous track"
|
ariaLabel="Previous track"
|
||||||
>
|
>
|
||||||
@ -200,7 +198,7 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
color="translucent"
|
color="translucent"
|
||||||
size="smaller"
|
size="smaller"
|
||||||
className="player-button"
|
className="player-button"
|
||||||
disabled={isLast}
|
disabled={isLast()}
|
||||||
onClick={requestNextTrack}
|
onClick={requestNextTrack}
|
||||||
ariaLabel="Next track"
|
ariaLabel="Next track"
|
||||||
>
|
>
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React, { useCallback } from '../../../../lib/teact/teact';
|
|||||||
import { getDispatch } from '../../../../lib/teact/teactn';
|
import { getDispatch } from '../../../../lib/teact/teactn';
|
||||||
|
|
||||||
import { isUserId } from '../../../../modules/helpers';
|
import { isUserId } from '../../../../modules/helpers';
|
||||||
import { AudioOrigin, IAlbum, MediaViewerOrigin } from '../../../../types';
|
import { IAlbum, MediaViewerOrigin } from '../../../../types';
|
||||||
import {
|
import {
|
||||||
ApiChat, ApiMessage, ApiUser, MAIN_THREAD_ID,
|
ApiChat, ApiMessage, ApiUser, MAIN_THREAD_ID,
|
||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
@ -81,7 +81,7 @@ export default function useInnerHandlers(
|
|||||||
}, [chatId, threadId, messageId, openMediaViewer, isScheduled]);
|
}, [chatId, threadId, messageId, openMediaViewer, isScheduled]);
|
||||||
|
|
||||||
const handleAudioPlay = useCallback((): void => {
|
const handleAudioPlay = useCallback((): void => {
|
||||||
openAudioPlayer({ chatId, messageId, origin: AudioOrigin.Inline });
|
openAudioPlayer({ chatId, messageId });
|
||||||
}, [chatId, messageId, openAudioPlayer]);
|
}, [chatId, messageId, openAudioPlayer]);
|
||||||
|
|
||||||
const handleAlbumMediaClick = useCallback((albumMessageId: number): void => {
|
const handleAlbumMediaClick = useCallback((albumMessageId: number): void => {
|
||||||
|
|||||||
@ -210,7 +210,7 @@ const Profile: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
}, [profileId, openMediaViewer]);
|
}, [profileId, openMediaViewer]);
|
||||||
|
|
||||||
const handlePlayAudio = useCallback((messageId: number) => {
|
const handlePlayAudio = useCallback((messageId: number) => {
|
||||||
openAudioPlayer({ chatId: profileId, messageId, origin: AudioOrigin.SharedMedia });
|
openAudioPlayer({ chatId: profileId, messageId });
|
||||||
}, [profileId, openAudioPlayer]);
|
}, [profileId, openAudioPlayer]);
|
||||||
|
|
||||||
const handleMemberClick = useCallback((id: string) => {
|
const handleMemberClick = useCallback((id: string) => {
|
||||||
|
|||||||
@ -530,7 +530,7 @@ export type ActionTypes = (
|
|||||||
// media viewer & audio player
|
// media viewer & audio player
|
||||||
'openMediaViewer' | 'closeMediaViewer' |
|
'openMediaViewer' | 'closeMediaViewer' |
|
||||||
'openAudioPlayer' | 'setAudioPlayerVolume' | 'setAudioPlayerPlaybackRate' |
|
'openAudioPlayer' | 'setAudioPlayerVolume' | 'setAudioPlayerPlaybackRate' |
|
||||||
'setAudioPlayerMuted' | 'closeAudioPlayer' |
|
'setAudioPlayerMuted' | 'setAudioPlayerOrigin' | 'closeAudioPlayer' |
|
||||||
// misc
|
// misc
|
||||||
'openPollModal' | 'closePollModal' |
|
'openPollModal' | 'closePollModal' |
|
||||||
'loadWebPagePreview' | 'clearWebPagePreview' | 'loadWallpapers' | 'uploadWallpaper' |
|
'loadWebPagePreview' | 'clearWebPagePreview' | 'loadWallpapers' | 'uploadWallpaper' |
|
||||||
|
|||||||
@ -3,8 +3,6 @@ import {
|
|||||||
} from '../lib/teact/teact';
|
} from '../lib/teact/teact';
|
||||||
import { getDispatch, getGlobal } from '../lib/teact/teactn';
|
import { getDispatch, getGlobal } from '../lib/teact/teactn';
|
||||||
|
|
||||||
import { AudioOrigin } from '../types';
|
|
||||||
|
|
||||||
import { register, Track, TrackId } from '../util/audioPlayer';
|
import { register, Track, TrackId } from '../util/audioPlayer';
|
||||||
import useEffectWithPrevDeps from './useEffectWithPrevDeps';
|
import useEffectWithPrevDeps from './useEffectWithPrevDeps';
|
||||||
import { isSafariPatchInProgress } from '../util/patchSafariProgressiveAudio';
|
import { isSafariPatchInProgress } from '../util/patchSafariProgressiveAudio';
|
||||||
@ -21,7 +19,6 @@ export default (
|
|||||||
trackId: TrackId,
|
trackId: TrackId,
|
||||||
originalDuration: number, // Sometimes incorrect for voice messages
|
originalDuration: number, // Sometimes incorrect for voice messages
|
||||||
trackType: Track['type'],
|
trackType: Track['type'],
|
||||||
origin: AudioOrigin,
|
|
||||||
src?: string,
|
src?: string,
|
||||||
handlers?: Record<string, Handler>,
|
handlers?: Record<string, Handler>,
|
||||||
metadata?: MediaMetadata,
|
metadata?: MediaMetadata,
|
||||||
@ -46,7 +43,7 @@ export default (
|
|||||||
}, [onTrackChange]);
|
}, [onTrackChange]);
|
||||||
|
|
||||||
useOnChange(() => {
|
useOnChange(() => {
|
||||||
controllerRef.current = register(trackId, trackType, origin, (eventName, e) => {
|
controllerRef.current = register(trackId, trackType, (eventName, e) => {
|
||||||
switch (eventName) {
|
switch (eventName) {
|
||||||
case 'onPlay': {
|
case 'onPlay': {
|
||||||
const {
|
const {
|
||||||
@ -120,7 +117,6 @@ export default (
|
|||||||
proxy,
|
proxy,
|
||||||
destroy,
|
destroy,
|
||||||
setVolume,
|
setVolume,
|
||||||
setCurrentOrigin,
|
|
||||||
stop,
|
stop,
|
||||||
isFirst,
|
isFirst,
|
||||||
isLast,
|
isLast,
|
||||||
@ -161,10 +157,9 @@ export default (
|
|||||||
|
|
||||||
const playIfPresent = useCallback(() => {
|
const playIfPresent = useCallback(() => {
|
||||||
if (src) {
|
if (src) {
|
||||||
setCurrentOrigin(origin);
|
|
||||||
play(src);
|
play(src);
|
||||||
}
|
}
|
||||||
}, [src, origin, play, setCurrentOrigin]);
|
}, [src, play]);
|
||||||
|
|
||||||
const playPause = useCallback(() => {
|
const playPause = useCallback(() => {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
@ -194,8 +189,8 @@ export default (
|
|||||||
duration,
|
duration,
|
||||||
requestNextTrack,
|
requestNextTrack,
|
||||||
requestPreviousTrack,
|
requestPreviousTrack,
|
||||||
isFirst: isFirst(),
|
isFirst,
|
||||||
isLast: isLast(),
|
isLast,
|
||||||
setPlaybackRate,
|
setPlaybackRate,
|
||||||
toggleMuted,
|
toggleMuted,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -179,8 +179,8 @@ addReducer('openAudioPlayer', (global, actions, payload) => {
|
|||||||
chatId,
|
chatId,
|
||||||
threadId,
|
threadId,
|
||||||
messageId,
|
messageId,
|
||||||
origin,
|
origin: origin ?? global.audioPlayer.origin,
|
||||||
volume: volume || global.audioPlayer.volume,
|
volume: volume ?? global.audioPlayer.volume,
|
||||||
playbackRate: playbackRate || global.audioPlayer.playbackRate,
|
playbackRate: playbackRate || global.audioPlayer.playbackRate,
|
||||||
isMuted: isMuted || global.audioPlayer.isMuted,
|
isMuted: isMuted || global.audioPlayer.isMuted,
|
||||||
},
|
},
|
||||||
@ -229,6 +229,20 @@ addReducer('setAudioPlayerMuted', (global, actions, payload) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addReducer('setAudioPlayerOrigin', (global, actions, payload) => {
|
||||||
|
const {
|
||||||
|
origin,
|
||||||
|
} = payload!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
audioPlayer: {
|
||||||
|
...global.audioPlayer,
|
||||||
|
origin,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
addReducer('closeAudioPlayer', (global) => {
|
addReducer('closeAudioPlayer', (global) => {
|
||||||
return {
|
return {
|
||||||
...global,
|
...global,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { getDispatch } from '../lib/teact/teactn';
|
import { getDispatch, getGlobal } from '../lib/teact/teactn';
|
||||||
|
|
||||||
import { AudioOrigin } from '../types';
|
import { AudioOrigin, GlobalSearchContent } from '../types';
|
||||||
import { ApiMessage } from '../api/types';
|
import { ApiMessage } from '../api/types';
|
||||||
|
|
||||||
import { IS_SAFARI } from './environment';
|
import { IS_SAFARI } from './environment';
|
||||||
@ -8,6 +8,7 @@ import safePlay from './safePlay';
|
|||||||
import { patchSafariProgressiveAudio, isSafariPatchInProgress } from './patchSafariProgressiveAudio';
|
import { patchSafariProgressiveAudio, isSafariPatchInProgress } from './patchSafariProgressiveAudio';
|
||||||
import { getMessageKey, MessageKey, parseMessageKey } from '../modules/helpers';
|
import { getMessageKey, MessageKey, parseMessageKey } from '../modules/helpers';
|
||||||
import { fastRaf } from './schedulers';
|
import { fastRaf } from './schedulers';
|
||||||
|
import { selectCurrentMessageList } from '../modules/selectors';
|
||||||
|
|
||||||
type Handler = (eventName: string, e: Event) => void;
|
type Handler = (eventName: string, e: Event) => void;
|
||||||
export type TrackId = `${MessageKey}-${number}`;
|
export type TrackId = `${MessageKey}-${number}`;
|
||||||
@ -16,22 +17,20 @@ export interface Track {
|
|||||||
audio: HTMLAudioElement;
|
audio: HTMLAudioElement;
|
||||||
proxy: HTMLAudioElement;
|
proxy: HTMLAudioElement;
|
||||||
type: 'voice' | 'audio';
|
type: 'voice' | 'audio';
|
||||||
origin: AudioOrigin;
|
|
||||||
handlers: Handler[];
|
handlers: Handler[];
|
||||||
onForcePlay?: NoneToVoidFunction;
|
onForcePlay?: NoneToVoidFunction;
|
||||||
onTrackChange?: NoneToVoidFunction;
|
onTrackChange?: NoneToVoidFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tracks = new Map<string, Track>();
|
const tracks = new Map<TrackId, Track>();
|
||||||
let voiceQueue: TrackId[] = [];
|
let voiceQueue: TrackId[] = [];
|
||||||
let musicQueue: TrackId[] = [];
|
let musicQueue: TrackId[] = [];
|
||||||
|
|
||||||
let currentTrackId: string | undefined;
|
let currentTrackId: TrackId | undefined;
|
||||||
|
|
||||||
function createAudio(
|
function createAudio(
|
||||||
trackId: TrackId,
|
trackId: TrackId,
|
||||||
type: Track['type'],
|
type: Track['type'],
|
||||||
origin: AudioOrigin,
|
|
||||||
onForcePlay?: NoneToVoidFunction,
|
onForcePlay?: NoneToVoidFunction,
|
||||||
onTrackChange?: NoneToVoidFunction,
|
onTrackChange?: NoneToVoidFunction,
|
||||||
): Track {
|
): Track {
|
||||||
@ -77,7 +76,6 @@ function createAudio(
|
|||||||
proxy: new Proxy(audio, {
|
proxy: new Proxy(audio, {
|
||||||
get: (target, key: keyof HTMLAudioElement) => target[key],
|
get: (target, key: keyof HTMLAudioElement) => target[key],
|
||||||
}),
|
}),
|
||||||
origin,
|
|
||||||
handlers: [],
|
handlers: [],
|
||||||
onForcePlay,
|
onForcePlay,
|
||||||
onTrackChange,
|
onTrackChange,
|
||||||
@ -92,11 +90,9 @@ function playNext(trackId: TrackId, isReverseOrder?: boolean) {
|
|||||||
if (currentTrack.onTrackChange) currentTrack.onTrackChange();
|
if (currentTrack.onTrackChange) currentTrack.onTrackChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
const track = tracks.get(trackId)!;
|
const origin = getGlobal().audioPlayer.origin || AudioOrigin.Inline;
|
||||||
const queue = getTrackQueue(track);
|
|
||||||
if (!queue) return;
|
|
||||||
|
|
||||||
const nextTrackId = findNextInQueue(queue, trackId, track.origin, isReverseOrder);
|
const nextTrackId = findNextInQueue(trackId, origin, isReverseOrder);
|
||||||
if (!nextTrackId) {
|
if (!nextTrackId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -110,8 +106,6 @@ function playNext(trackId: TrackId, isReverseOrder?: boolean) {
|
|||||||
|
|
||||||
const nextTrack = tracks.get(nextTrackId)!;
|
const nextTrack = tracks.get(nextTrackId)!;
|
||||||
|
|
||||||
if (currentTrack) nextTrack.origin = currentTrack.origin; // Preserve origin
|
|
||||||
|
|
||||||
if (nextTrack.onForcePlay) {
|
if (nextTrack.onForcePlay) {
|
||||||
nextTrack.onForcePlay();
|
nextTrack.onForcePlay();
|
||||||
}
|
}
|
||||||
@ -133,13 +127,12 @@ export function stopCurrentAudio() {
|
|||||||
export function register(
|
export function register(
|
||||||
trackId: TrackId,
|
trackId: TrackId,
|
||||||
trackType: Track['type'],
|
trackType: Track['type'],
|
||||||
origin: AudioOrigin,
|
|
||||||
handler: Handler,
|
handler: Handler,
|
||||||
onForcePlay?: NoneToVoidFunction,
|
onForcePlay?: NoneToVoidFunction,
|
||||||
onTrackChange?: NoneToVoidFunction,
|
onTrackChange?: NoneToVoidFunction,
|
||||||
) {
|
) {
|
||||||
if (!tracks.has(trackId)) {
|
if (!tracks.has(trackId)) {
|
||||||
const track = createAudio(trackId, trackType, origin, onForcePlay, onTrackChange);
|
const track = createAudio(trackId, trackType, onForcePlay, onTrackChange);
|
||||||
tracks.set(trackId, track);
|
tracks.set(trackId, track);
|
||||||
addTrackToQueue(track, trackId);
|
addTrackToQueue(track, trackId);
|
||||||
}
|
}
|
||||||
@ -173,10 +166,7 @@ export function register(
|
|||||||
}
|
}
|
||||||
|
|
||||||
safePlay(audio);
|
safePlay(audio);
|
||||||
},
|
cleanUpQueue(trackType, trackId);
|
||||||
|
|
||||||
setCurrentOrigin(audioOrigin: AudioOrigin) {
|
|
||||||
tracks.get(trackId)!.origin = audioOrigin;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
pause() {
|
pause() {
|
||||||
@ -236,17 +226,11 @@ export function register(
|
|||||||
},
|
},
|
||||||
|
|
||||||
isLast() {
|
isLast() {
|
||||||
const track = tracks.get(trackId)!;
|
return !findNextInQueue(trackId, getGlobal().audioPlayer.origin);
|
||||||
const queue = getTrackQueue(track);
|
|
||||||
if (!queue) return true;
|
|
||||||
return !findNextInQueue(queue, trackId, tracks.get(trackId)!.origin);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
isFirst() {
|
isFirst() {
|
||||||
const track = tracks.get(trackId)!;
|
return !findNextInQueue(trackId, getGlobal().audioPlayer.origin, true);
|
||||||
const queue = getTrackQueue(track);
|
|
||||||
if (!queue) return true;
|
|
||||||
return !findNextInQueue(queue, trackId, tracks.get(trackId)!.origin, true);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
requestPreviousTrack() {
|
requestPreviousTrack() {
|
||||||
@ -278,14 +262,11 @@ export function register(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTrackQueue(track: Track) {
|
function getTrackQueue(track: Track) {
|
||||||
if (track.type === 'audio') {
|
switch (track.type) {
|
||||||
return musicQueue;
|
case 'audio': return musicQueue;
|
||||||
|
case 'voice': return voiceQueue;
|
||||||
|
default: return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track.type === 'voice') {
|
|
||||||
return voiceQueue;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function addTrackToQueue(track: Track, trackId: TrackId) {
|
function addTrackToQueue(track: Track, trackId: TrackId) {
|
||||||
@ -301,26 +282,48 @@ function addTrackToQueue(track: Track, trackId: TrackId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeFromQueue(track: Track, trackId: TrackId) {
|
function removeFromQueue(track: Track, trackId: TrackId) {
|
||||||
|
const trackIdFilter = (el: TrackId) => el !== trackId;
|
||||||
if (track.type === 'audio') {
|
if (track.type === 'audio') {
|
||||||
musicQueue = musicQueue.filter((el) => el !== trackId);
|
musicQueue = musicQueue.filter(trackIdFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track.type === 'voice') {
|
if (track.type === 'voice') {
|
||||||
voiceQueue = voiceQueue.filter((el) => el !== trackId);
|
voiceQueue = voiceQueue.filter(trackIdFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function findNextInQueue(queue: TrackId[], current: TrackId, origin: AudioOrigin, isReverseOrder?: boolean) {
|
function cleanUpQueue(type: Track['type'], trackId: TrackId) {
|
||||||
|
if (getGlobal().globalSearch.currentContent === GlobalSearchContent.Music) return;
|
||||||
|
const { chatId } = parseMessageKey(splitTrackId(trackId).messageKey);
|
||||||
|
const openedChatId = selectCurrentMessageList(getGlobal())?.chatId;
|
||||||
|
const queueFilter = (id: string) => (
|
||||||
|
id.startsWith(`msg${chatId}`) || (openedChatId && id.startsWith(`msg${openedChatId}`))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (type === 'audio') {
|
||||||
|
musicQueue = musicQueue.filter(queueFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'voice') {
|
||||||
|
voiceQueue = voiceQueue.filter(queueFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNextInQueue(currentId: TrackId, origin = AudioOrigin.Inline, isReverseOrder?: boolean) {
|
||||||
|
const track = tracks.get(currentId)!;
|
||||||
|
const queue = getTrackQueue(track);
|
||||||
|
if (!queue) return undefined;
|
||||||
|
|
||||||
if (origin === AudioOrigin.Search) {
|
if (origin === AudioOrigin.Search) {
|
||||||
const index = queue.indexOf(current);
|
const index = queue.indexOf(currentId);
|
||||||
if (index < 0) return undefined;
|
if (index < 0) return undefined;
|
||||||
const direction = isReverseOrder ? -1 : 1;
|
const direction = isReverseOrder ? -1 : 1;
|
||||||
return queue[index + direction];
|
return queue[index + direction];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { chatId } = parseMessageKey(splitTrackId(current).messageKey);
|
const { chatId } = parseMessageKey(splitTrackId(currentId).messageKey);
|
||||||
const chatAudio = queue.filter((id) => id.startsWith(`msg${chatId}`));
|
const chatAudio = queue.filter((id) => id.startsWith(`msg${chatId}`));
|
||||||
const index = chatAudio.indexOf(current);
|
const index = chatAudio.indexOf(currentId);
|
||||||
if (index < 0) return undefined;
|
if (index < 0) return undefined;
|
||||||
let direction = origin === AudioOrigin.Inline ? -1 : 1;
|
let direction = origin === AudioOrigin.Inline ? -1 : 1;
|
||||||
if (isReverseOrder) direction *= -1;
|
if (isReverseOrder) direction *= -1;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user