Add scrobbling feature to player

This commit is contained in:
jeffvli
2021-10-07 20:23:42 -07:00
committed by Jeff
parent 48413898f1
commit c4bf305948
4 changed files with 90 additions and 16 deletions

View File

@@ -59,6 +59,7 @@ const playQueueState: PlayQueue = {
const playerState: Player = {
status: 'PAUSED',
currentSeek: 0,
scrobbled: false,
};
const miscState: General = {

View File

@@ -721,3 +721,11 @@ export const search3 = async (query: string) => {
})),
};
};
export const scrobble = async (options: { id: string; time?: number; submission?: boolean }) => {
const { data } = await api.get(`/scrobble`, {
params: options,
});
return data;
};

View File

@@ -23,9 +23,10 @@ import {
setFadeData,
setPlayerSrc,
} from '../../redux/playQueueSlice';
import { setCurrentSeek } from '../../redux/playerSlice';
import { setCurrentSeek, setScrobbled } from '../../redux/playerSlice';
import cacheSong from '../shared/cacheSong';
import { getSongCachePath, isCached } from '../../shared/utils';
import { scrobble } from '../../api/api';
const gaplessListenHandler = (
currentPlayerRef: any,
@@ -33,16 +34,16 @@ const gaplessListenHandler = (
playQueue: any,
currentPlayer: number,
dispatch: any,
pollingInterval: number
pollingInterval: number,
scrobbled: boolean
) => {
const seek = currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const currentSeek = currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const duration = currentPlayerRef.current?.audioEl.current?.duration;
if (playQueue.currentPlayer === currentPlayer) {
dispatch(
setCurrentSeek({
seek,
seek: currentSeek,
})
);
}
@@ -50,9 +51,14 @@ const gaplessListenHandler = (
// Add a bit of leeway for the second track to start since the
// seek value doesn't always reach the duration
const durationPadding = pollingInterval <= 10 ? 0.12 : pollingInterval <= 20 ? 0.13 : 0.15;
if (seek + durationPadding >= duration) {
if (currentSeek + durationPadding >= duration) {
nextPlayerRef.current.audioEl.current.play();
}
if ((currentSeek >= 240 || currentSeek >= duration - 5) && !scrobbled) {
dispatch(setScrobbled(true));
scrobble({ id: playQueue.currentSongId, submission: true });
}
};
const listenHandler = (
@@ -65,7 +71,8 @@ const listenHandler = (
fadeDuration: number,
fadeType: string,
volumeFade: boolean,
debug: boolean
debug: boolean,
scrobbled: boolean
) => {
const currentSeek = currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const duration = currentPlayerRef.current?.audioEl.current?.duration;
@@ -195,6 +202,15 @@ const listenHandler = (
if (playQueue.currentPlayer === player) {
dispatch(setCurrentSeek({ seek: currentSeek }));
}
if (
(currentSeek >= 240 || currentSeek >= duration - fadeAtTime + 1) &&
!scrobbled &&
currentSeek <= fadeAtTime
) {
dispatch(setScrobbled(true));
scrobble({ id: playQueue.currentSongId, submission: true });
}
};
const Player = ({ currentEntryList, children }: any, ref: any) => {
@@ -319,7 +335,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
playQueue.volumeFade,
]);
const handleListenPlayer1 = () => {
const handleListenPlayer1 = useCallback(() => {
listenHandler(
player1Ref,
player2Ref,
@@ -330,11 +346,21 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
fadeDuration,
fadeType,
volumeFade,
debug
debug,
player.scrobbled
);
};
}, [
currentEntryList,
debug,
dispatch,
fadeDuration,
fadeType,
playQueue,
player.scrobbled,
volumeFade,
]);
const handleListenPlayer2 = () => {
const handleListenPlayer2 = useCallback(() => {
listenHandler(
player2Ref,
player1Ref,
@@ -345,9 +371,19 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
fadeDuration,
fadeType,
volumeFade,
debug
debug,
player.scrobbled
);
};
}, [
currentEntryList,
debug,
dispatch,
fadeDuration,
fadeType,
playQueue,
player.scrobbled,
volumeFade,
]);
const handleOnEndedPlayer1 = () => {
player1Ref.current.audioEl.current.currentTime = 0;
@@ -417,11 +453,32 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
};
const handleGaplessPlayer1 = () => {
gaplessListenHandler(player1Ref, player2Ref, playQueue, 1, dispatch, pollingInterval);
gaplessListenHandler(
player1Ref,
player2Ref,
playQueue,
1,
dispatch,
pollingInterval,
player.scrobbled
);
};
const handleGaplessPlayer2 = () => {
gaplessListenHandler(player2Ref, player1Ref, playQueue, 2, dispatch, pollingInterval);
gaplessListenHandler(
player2Ref,
player1Ref,
playQueue,
2,
dispatch,
pollingInterval,
player.scrobbled
);
};
const handleOnPlay = () => {
dispatch(setScrobbled(false));
scrobble({ id: playQueue.currentSongId, submission: false });
};
return (
@@ -433,6 +490,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
<ReactAudioPlayer
ref={player1Ref}
src={playQueue.player1.src}
onPlay={handleOnPlay}
listenInterval={pollingInterval}
preload="auto"
onListen={fadeDuration === 0 ? handleGaplessPlayer1 : handleListenPlayer1}
@@ -454,6 +512,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
<ReactAudioPlayer
ref={player2Ref}
src={playQueue.player2.src}
onPlay={handleOnPlay}
listenInterval={pollingInterval}
preload="auto"
onListen={fadeDuration === 0 ? handleGaplessPlayer2 : handleListenPlayer2}

View File

@@ -3,11 +3,13 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
export interface Player {
status: string;
currentSeek: number;
scrobbled: boolean;
}
const initialState: Player = {
status: 'PAUSED',
currentSeek: 0,
scrobbled: false,
};
const playerSlice = createSlice({
@@ -25,8 +27,12 @@ const playerSlice = createSlice({
setCurrentSeek: (state, action: PayloadAction<{ seek: number }>) => {
state.currentSeek = action.payload.seek;
},
setScrobbled: (state, action: PayloadAction<boolean>) => {
state.scrobbled = action.payload;
},
},
});
export const { setStatus, setCurrentSeek, resetPlayer } = playerSlice.actions;
export const { setStatus, setCurrentSeek, resetPlayer, setScrobbled } = playerSlice.actions;
export default playerSlice.reducer;