Upgrade all dependencies

(1) react-native-track-player to v2
(2) react-navigation to v6
(3) react-native to v0.66.4
This commit is contained in:
Lei Nelissen
2021-12-31 15:04:37 +01:00
parent 6440c1ac7b
commit 9668ba9c7c
28 changed files with 21769 additions and 5659 deletions

View File

@@ -0,0 +1,43 @@
import TrackPlayer from 'react-native-track-player';
import { useEffect } from 'react';
import EventEmitter from 'events';
const eventName = 'track-added';
const addedTrackEmitter = new EventEmitter();
/**
* Emit the event that a track has been added
*/
export function emitTrackAdded() {
addedTrackEmitter.emit(eventName);
}
/**
* Call the callback whenever a track has been added to the queue
*/
export function onTrackAdded(callback: () => void) {
addedTrackEmitter.addListener(eventName, callback);
}
/**
* A hook to manage the listeners for the added track function
*/
export function useOnTrackAdded(callback: () => void) {
useEffect(() => {
addedTrackEmitter.addListener(eventName, callback);
return () => {
addedTrackEmitter.removeListener(eventName, callback);
};
});
}
/**
* Monkey-patch the track-player to also emit track added events
*/
export function patchTrackPlayer() {
const oldAddFunction = TrackPlayer.add;
TrackPlayer.add = (...args: Parameters<typeof oldAddFunction>) => {
emitTrackAdded();
return oldAddFunction(...args);
};
}

View File

@@ -44,8 +44,8 @@ export function generateTrack(track: AlbumTrack, credentials: Credentials): Trac
const url = encodeURI(`${credentials?.uri}/Audio/${track.Id}/universal?${trackParams}`);
return {
id: track.Id,
url,
backendId: track.Id,
title: track.Name,
artist: track.Artists.join(', '),
album: track.Album,

View File

@@ -7,30 +7,30 @@
* such as processing media buttons or analytics
*/
import TrackPlayer from 'react-native-track-player';
import TrackPlayer, { Event } from 'react-native-track-player';
export default async function() {
TrackPlayer.addEventListener('remote-play', () => {
TrackPlayer.addEventListener(Event.RemotePlay, () => {
TrackPlayer.play();
});
TrackPlayer.addEventListener('remote-pause', () => {
TrackPlayer.addEventListener(Event.RemotePause, () => {
TrackPlayer.pause();
});
TrackPlayer.addEventListener('remote-next', () => {
TrackPlayer.addEventListener(Event.RemoteNext, () => {
TrackPlayer.skipToNext();
});
TrackPlayer.addEventListener('remote-previous', () => {
TrackPlayer.addEventListener(Event.RemotePrevious, () => {
TrackPlayer.skipToPrevious();
});
TrackPlayer.addEventListener('remote-stop', () => {
TrackPlayer.addEventListener(Event.RemoteStop, () => {
TrackPlayer.destroy();
});
TrackPlayer.addEventListener('remote-seek', (event) => {
TrackPlayer.addEventListener(Event.RemoteSeek, (event) => {
TrackPlayer.seekTo(event.position);
});

View File

@@ -1,15 +1,29 @@
import { Track } from 'react-native-track-player';
import { useTypedSelector } from 'store';
import { useCallback, useEffect, useState } from 'react';
import TrackPlayer, { Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
const idEqual = (left: Track | undefined, right: Track | undefined) => {
return left?.id === right?.id;
};
interface CurrentTrackResponse {
track: Track | undefined;
index: number | undefined;
}
/**
* This hook retrieves the current playing track from TrackPlayer
*/
export default function useCurrentTrack(): Track | undefined {
const track = useTypedSelector(state => state.player.currentTrack, idEqual);
export default function useCurrentTrack(): CurrentTrackResponse {
const [track, setTrack] = useState<Track | undefined>();
const [index, setIndex] = useState<number | undefined>();
// Retrieve the current track from the queue using the index
const retrieveCurrentTrack = useCallback(async () => {
const queue = await TrackPlayer.getQueue();
const currentTrackIndex = await TrackPlayer.getCurrentTrack();
setTrack(queue[currentTrackIndex]);
setIndex(currentTrackIndex);
}, [setTrack, setIndex]);
// Then execute the function on component mount and track changes
useEffect(() => { retrieveCurrentTrack(); }, [retrieveCurrentTrack]);
useTrackPlayerEvents([ Event.PlaybackTrackChanged ], retrieveCurrentTrack);
return track;
return { track, index };
}

View File

@@ -2,55 +2,27 @@ import { useTypedSelector } from 'store';
import { useCallback } from 'react';
import TrackPlayer, { Track } from 'react-native-track-player';
import { generateTrack } from './JellyfinApi';
import useQueue from './useQueue';
import player from 'store/player';
import { useDispatch } from 'react-redux';
/**
* Generate a callback function that starts playing a full album given its
* supplied id.
*/
export default function usePlayAlbum() {
const dispatch = useDispatch();
const credentials = useTypedSelector(state => state.settings.jellyfin);
const albums = useTypedSelector(state => state.music.albums.entities);
const tracks = useTypedSelector(state => state.music.tracks.entities);
const queue = useQueue();
return useCallback(async function playAlbum(albumId: string, play = true): Promise<TrackPlayer.Track[] | undefined> {
return useCallback(async function playAlbum(albumId: string, play: boolean = true): Promise<Track[] | undefined> {
const album = albums[albumId];
const trackIds = album?.Tracks;
const backendTrackIds = album?.Tracks;
// GUARD: Check that the album actually has tracks
if (!album || !trackIds?.length) {
// GUARD: Check if the album has songs
if (!backendTrackIds?.length) {
return;
}
// Check if the queue already contains the consecutive track listing
// that is described as part of the album
const queuedAlbum = queue.reduce<TrackPlayer.Track[]>((sum, track) => {
if (track.id.startsWith(trackIds[sum.length])) {
sum.push(track);
} else {
sum = [];
}
return sum;
}, []);
// If the entire album is already in the queue, we can just return those
// tracks, rather than adding it to the queue again.
if (queuedAlbum.length === trackIds.length) {
if (play) {
await TrackPlayer.skip(trackIds[0]);
await TrackPlayer.play();
}
return queuedAlbum;
}
// Convert all trackIds to the relevant format for react-native-track-player
const newTracks = trackIds.map((trackId) => {
// Convert all backendTrackIds to the relevant format for react-native-track-player
const newTracks = backendTrackIds.map((trackId) => {
const track = tracks[trackId];
if (!trackId || !track) {
return;
@@ -60,17 +32,14 @@ export default function usePlayAlbum() {
}).filter((t): t is Track => typeof t !== 'undefined');
// Clear the queue and add all tracks
await TrackPlayer.removeUpcomingTracks();
await TrackPlayer.reset();
await TrackPlayer.add(newTracks);
// Then, we'll dispatch the added track event
dispatch(player.actions.addNewTrackToPlayer());
// Play the queue
if (play) {
await TrackPlayer.skip(trackIds[0]);
await TrackPlayer.play();
}
return newTracks;
}, [credentials, albums, tracks, queue, dispatch]);
}, [credentials, albums, tracks]);
}

View File

@@ -3,20 +3,17 @@ import TrackPlayer from 'react-native-track-player';
import { useTypedSelector } from 'store';
import { generateTrack } from './JellyfinApi';
import useQueue from './useQueue';
import { useDispatch } from 'react-redux';
import player from 'store/player';
/**
* A hook that generates a callback that can setup and start playing a
* particular trackId in the player.
*/
export default function usePlayTrack() {
const dispatch = useDispatch();
const credentials = useTypedSelector(state => state.settings.jellyfin);
const tracks = useTypedSelector(state => state.music.tracks.entities);
const queue = useQueue();
return useCallback(async function playTrack(trackId: string, play = true, addToEnd = true) {
return useCallback(async function playTrack(trackId: string, play: boolean = true, addToEnd: boolean = true) {
// Get the relevant track
const track = tracks[trackId];
@@ -25,22 +22,21 @@ export default function usePlayTrack() {
return;
}
// GUARD: Check if the track is already in the queue
const trackInstances = queue.filter((t) => t.id.startsWith(trackId));
// Generate the new track for the queue
const newTrack = {
...(trackInstances.length ? trackInstances[0] : generateTrack(track, credentials)),
id: `${trackId}_${trackInstances.length}`
};
const newTrack = generateTrack(track, credentials);
// Then, we'll need to check where to add the track
if (addToEnd) {
await TrackPlayer.add([ newTrack ]);
// Then we'll skip to it and play it
if (play) {
await TrackPlayer.skip(await (await TrackPlayer.getQueue()).length);
await TrackPlayer.play();
}
} else {
// Try and locate the current track
const currentTrackId = await TrackPlayer.getCurrentTrack();
const currentTrackIndex = queue.findIndex(track => track.id === currentTrackId);
const currentTrackIndex = await TrackPlayer.getCurrentTrack();
// Since the argument is the id to insert the track BEFORE, we need
// to get the current track + 1
@@ -51,17 +47,13 @@ export default function usePlayTrack() {
// Depending on whether this track exists, we either add it there,
// or at the end of the queue.
await TrackPlayer.add([ newTrack ], targetTrack);
}
// Then, we'll dispatch the added track event
dispatch(player.actions.addNewTrackToPlayer());
// Then we'll skip to it and play it
if (play) {
await TrackPlayer.skip(newTrack.id);
await TrackPlayer.play();
if (play) {
await TrackPlayer.skip(currentTrackIndex + 1);
await TrackPlayer.play();
}
}
return newTrack;
}, [credentials, tracks, queue, dispatch]);
}, [credentials, tracks, queue]);
}

View File

@@ -1,18 +1,22 @@
import { useEffect, useState } from 'react';
import TrackPlayer, { usePlaybackState, Track } from 'react-native-track-player';
import { useTypedSelector } from 'store';
import { useCallback, useEffect, useState } from 'react';
import TrackPlayer, { Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import { useOnTrackAdded } from './AddedTrackEvents';
/**
* This hook retrieves the current playing track from TrackPlayer
*/
export default function useQueue(): Track[] {
const state = usePlaybackState();
const [queue, setQueue] = useState<Track[]>([]);
const addedTrackCount = useTypedSelector(state => state.player.addedTrackCount);
useEffect(() => {
TrackPlayer.getQueue().then(setQueue);
}, [state, addedTrackCount]);
// Define function that fetches the current queue
const updateQueue = useCallback(() => TrackPlayer.getQueue().then(setQueue), [setQueue]);
// Then define the triggers for updating it
useEffect(() => { updateQueue(); }, [updateQueue]);
useTrackPlayerEvents([
Event.PlaybackState,
], updateQueue);
useOnTrackAdded(updateQueue);
return queue;
}