From a69a4e7b0c7afe14deb02b1a4e44cf2bbf928a9f Mon Sep 17 00:00:00 2001 From: Violet Caulfield <42452695+anultravioletaurora@users.noreply.github.com> Date: Wed, 11 Mar 2026 06:05:09 -0500 Subject: [PATCH] fix issue where playnext tracks occurred in multiple playlists --- jest.config.js | 2 +- src/hooks/player/callbacks.ts | 8 +++++++- src/hooks/player/functions/queue.ts | 24 ++++++++---------------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/jest.config.js b/jest.config.js index 532428c8..9c788be6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,7 +22,7 @@ module.exports = { './jest/setup/nitro-image.ts', './jest/setup/nitro-ota.ts', './jest/setup/nitro-player.ts', - './tamagui.config.ts', + './src/config/tamagui.config.ts', './jest/setup/native-modules.ts', ], extensionsToTreatAsEsm: ['.ts', '.tsx'], diff --git a/src/hooks/player/callbacks.ts b/src/hooks/player/callbacks.ts index 34dbdbab..4b6527ed 100644 --- a/src/hooks/player/callbacks.ts +++ b/src/hooks/player/callbacks.ts @@ -183,14 +183,20 @@ export const useRemoveFromQueue = () => { if (!playlistId) return const playlist = PlayerQueue.getPlaylist(playlistId)! + const trackIdToRemove = playlist.tracks[index].id - PlayerQueue.removeTrackFromPlaylist(playlistId, playlist.tracks[index].id) + PlayerQueue.removeTrackFromPlaylist(playlistId, trackIdToRemove) const prevQueue = usePlayerQueueStore.getState().queue const newQueue = prevQueue.filter((_, i) => i !== index) usePlayerQueueStore.getState().setQueue(newQueue) + // Also remove from unShuffledQueue to prevent orphaned tracks + const prevUnshuffledQueue = usePlayerQueueStore.getState().unShuffledQueue + const newUnshuffledQueue = prevUnshuffledQueue.filter((t) => t.id !== trackIdToRemove) + usePlayerQueueStore.getState().setUnshuffledQueue(newUnshuffledQueue) + // If queue is now empty, reset player state to hide miniplayer if (newQueue.length === 0) { usePlayerQueueStore.getState().setCurrentIndex(undefined) diff --git a/src/hooks/player/functions/queue.ts b/src/hooks/player/functions/queue.ts index bc162da3..0350589b 100644 --- a/src/hooks/player/functions/queue.ts +++ b/src/hooks/player/functions/queue.ts @@ -9,7 +9,6 @@ import { isNull } from 'lodash' import { useNetworkStore } from '../../../stores/network' import { DownloadManager, PlayerQueue, TrackItem, TrackPlayer } from 'react-native-nitro-player' import uuid from 'react-native-uuid' -import resolveTrackUrls from '../../../utils/fetching/track-media-info' type LoadQueueResult = { finalStartIndex: number @@ -76,27 +75,17 @@ export async function loadQueue({ * @param item The track to play next */ export const playNextInQueue = async ({ tracks }: AddToQueueMutation) => { - // Add the resolved tracks to the CURRENT playlist (not an orphan one). The - // native updatePlaylist callback will do a soft rebuild that dedups them from - // the remaining queue, so they only appear in the playNext stack. - const currentPlaylistId = PlayerQueue.getCurrentPlaylistId() - if (!currentPlaylistId) return - const tracksToPlayNext = tracks.map((item) => mapDtoToTrack(item)) - // Resolve URLs before adding to the native queue. If we add unresolved tracks - // (empty URL) and then call playNext, ExoPlayer/AVPlayer immediately errors on - // the empty URI and skips the track. We must have the real URL in the playlist - // before playNext references it by ID. - const resolvedTracks = await resolveTrackUrls(tracksToPlayNext, 'stream') + const playlistId = PlayerQueue.createPlaylist(uuid.v4(), undefined, undefined) - PlayerQueue.addTracksToPlaylist(currentPlaylistId, resolvedTracks) + PlayerQueue.addTracksToPlaylist(playlistId, tracksToPlayNext) // Insert in reverse so the album plays in forward order. playNextInternal prepends // each call (inserts at index 0 or 1), so calling last-track-first means track[0] // ends up at the front of the stack after all insertions. - for (let i = resolvedTracks.length - 1; i >= 0; i--) { - await TrackPlayer.playNext(resolvedTracks[i].id) + for (let i = tracksToPlayNext.length - 1; i >= 0; i--) { + await TrackPlayer.playNext(tracksToPlayNext[i].id) } // Get the active queue, put it in Zustand @@ -105,7 +94,10 @@ export const playNextInQueue = async ({ tracks }: AddToQueueMutation) => { usePlayerQueueStore .getState() - .setUnshuffledQueue([...usePlayerQueueStore.getState().unShuffledQueue, ...resolvedTracks]) + .setUnshuffledQueue([ + ...usePlayerQueueStore.getState().unShuffledQueue, + ...tracksToPlayNext, + ]) } export const playLaterInQueue = async ({ tracks }: AddToQueueMutation) => {