Make scrobbling configurable, clean up logic (#17)

This commit is contained in:
jeffvli
2021-10-09 21:42:12 -07:00
committed by Jeff
parent c44a305341
commit ace388b3b4
6 changed files with 89 additions and 40 deletions

View File

@@ -44,6 +44,7 @@ const playQueueState: PlayQueue = {
playerUpdated: 0,
autoIncremented: false,
volume: 0.5,
scrobble: false,
isLoading: false,
repeat: 'all',
shuffle: false,

View File

@@ -23,7 +23,7 @@ import {
setFadeData,
setPlayerSrc,
} from '../../redux/playQueueSlice';
import { setCurrentSeek, setScrobbled } from '../../redux/playerSlice';
import { setCurrentSeek } from '../../redux/playerSlice';
import cacheSong from '../shared/cacheSong';
import { getSongCachePath, isCached } from '../../shared/utils';
import { scrobble } from '../../api/api';
@@ -35,7 +35,9 @@ const gaplessListenHandler = (
currentPlayer: number,
dispatch: any,
pollingInterval: number,
scrobbled: boolean
shouldScrobble: boolean,
scrobbled: boolean,
setScrobbled: any
) => {
const currentSeek = currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const duration = currentPlayerRef.current?.audioEl.current?.duration;
@@ -55,8 +57,19 @@ const gaplessListenHandler = (
nextPlayerRef.current.audioEl.current.play();
}
if ((currentSeek >= 240 || currentSeek >= duration - 5) && !scrobbled) {
dispatch(setScrobbled(true));
// Conditions for scrobbling gapless track
// 1. Scrobble enabled in settings
// 2. Not already scrobbled
// 3. Track reached past 4 minutes or past the 90% mark
// 4. Not in the last 2 seconds of the track (gapless player starts second track before first ends)
// Step 4 sets the scrobbled value to false again which would trigger a second scrobble
if (
shouldScrobble &&
!scrobbled &&
(currentSeek >= 240 || currentSeek >= duration * 0.9) &&
currentSeek <= duration - 2
) {
setScrobbled(true);
scrobble({ id: playQueue.currentSongId, submission: true });
}
};
@@ -72,7 +85,9 @@ const listenHandler = (
fadeType: string,
volumeFade: boolean,
debug: boolean,
scrobbled: boolean
shouldScrobble: boolean,
scrobbled: boolean,
setScrobbled: any
) => {
const currentSeek = currentPlayerRef.current?.audioEl.current?.currentTime || 0;
const duration = currentPlayerRef.current?.audioEl.current?.duration;
@@ -203,12 +218,18 @@ const listenHandler = (
dispatch(setCurrentSeek({ seek: currentSeek }));
}
// Conditions for scrobbling fading track
// 1. Scrobble enabled in settings
// 2. Not already scrobbled
// 3. Track reached past 4 minutes or past the fadeAtTime - 15 seconds
// 4. The track is not fading
if (
(currentSeek >= 240 || currentSeek >= duration - fadeAtTime + 1) &&
shouldScrobble &&
!scrobbled &&
(currentSeek >= 240 || currentSeek >= fadeAtTime - 15) &&
currentSeek <= fadeAtTime
) {
dispatch(setScrobbled(true));
setScrobbled(true);
scrobble({ id: playQueue.currentSongId, submission: true });
}
};
@@ -227,6 +248,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
const [fadeType, setFadeType] = useState(playQueue.fadeType);
const [volumeFade, setVolumeFade] = useState(playQueue.volumeFade);
const [pollingInterval, setPollingInterval] = useState(playQueue.pollingInterval);
const [scrobbled, setScrobbled] = useState(false);
const getSrc1 = useCallback(() => {
const cachedSongPath = `${cachePath}/${
@@ -347,18 +369,11 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
fadeType,
volumeFade,
debug,
player.scrobbled
playQueue.scrobble,
scrobbled,
setScrobbled
);
}, [
currentEntryList,
debug,
dispatch,
fadeDuration,
fadeType,
playQueue,
player.scrobbled,
volumeFade,
]);
}, [currentEntryList, debug, dispatch, fadeDuration, fadeType, playQueue, scrobbled, volumeFade]);
const handleListenPlayer2 = useCallback(() => {
listenHandler(
@@ -372,18 +387,11 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
fadeType,
volumeFade,
debug,
player.scrobbled
playQueue.scrobble,
scrobbled,
setScrobbled
);
}, [
currentEntryList,
debug,
dispatch,
fadeDuration,
fadeType,
playQueue,
player.scrobbled,
volumeFade,
]);
}, [currentEntryList, debug, dispatch, fadeDuration, fadeType, playQueue, scrobbled, volumeFade]);
const handleOnEndedPlayer1 = () => {
player1Ref.current.audioEl.current.currentTime = 0;
@@ -452,7 +460,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
}
};
const handleGaplessPlayer1 = () => {
const handleGaplessPlayer1 = useCallback(() => {
gaplessListenHandler(
player1Ref,
player2Ref,
@@ -460,11 +468,13 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
1,
dispatch,
pollingInterval,
player.scrobbled
playQueue.scrobble,
scrobbled,
setScrobbled
);
};
}, [dispatch, playQueue, scrobbled, pollingInterval]);
const handleGaplessPlayer2 = () => {
const handleGaplessPlayer2 = useCallback(() => {
gaplessListenHandler(
player2Ref,
player1Ref,
@@ -472,13 +482,27 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
2,
dispatch,
pollingInterval,
player.scrobbled
playQueue.scrobble,
scrobbled,
setScrobbled
);
};
}, [dispatch, playQueue, scrobbled, pollingInterval]);
const handleOnPlay = () => {
dispatch(setScrobbled(false));
scrobble({ id: playQueue.currentSongId, submission: false });
const handleOnPlay = (playerNumber: 1 | 2) => {
setScrobbled(false);
if (playQueue.scrobble) {
if (playerNumber === 1) {
scrobble({
id: playQueue[currentEntryList][playQueue.player1.index].id,
submission: false,
});
} else {
scrobble({
id: playQueue[currentEntryList][playQueue.player2.index].id,
submission: false,
});
}
}
};
return (
@@ -490,7 +514,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
<ReactAudioPlayer
ref={player1Ref}
src={playQueue.player1.src}
onPlay={handleOnPlay}
onPlay={() => handleOnPlay(1)}
listenInterval={pollingInterval}
preload="auto"
onListen={fadeDuration === 0 ? handleGaplessPlayer1 : handleListenPlayer1}
@@ -512,7 +536,7 @@ const Player = ({ currentEntryList, children }: any, ref: any) => {
<ReactAudioPlayer
ref={player2Ref}
src={playQueue.player2.src}
onPlay={handleOnPlay}
onPlay={() => handleOnPlay(2)}
listenInterval={pollingInterval}
preload="auto"
onListen={fadeDuration === 0 ? handleGaplessPlayer2 : handleListenPlayer2}

View File

@@ -3,11 +3,15 @@ import settings from 'electron-settings';
import { ControlLabel } from 'rsuite';
import { ConfigPanel } from '../styled';
import { StyledCheckbox, StyledInputNumber } from '../../shared/styled';
import { useAppDispatch } from '../../../redux/hooks';
import { setPlaybackSetting } from '../../../redux/playQueueSlice';
const PlayerConfig = () => {
const dispatch = useAppDispatch();
const [globalMediaHotkeys, setGlobalMediaHotkeys] = useState(
Boolean(settings.getSync('globalMediaHotkeys'))
);
const [scrobble, setScrobble] = useState(Boolean(settings.getSync('scrobble')));
return (
<ConfigPanel header="Player" bordered>
<p>
@@ -48,6 +52,16 @@ const PlayerConfig = () => {
>
Enable global media hotkeys (requires app restart)
</StyledCheckbox>
<StyledCheckbox
defaultChecked={scrobble}
onChange={() => {
settings.setSync('scrobble', !scrobble);
dispatch(setPlaybackSetting({ setting: 'scrobble', value: !scrobble }));
setScrobble(!scrobble);
}}
>
Enable scrobbling
</StyledCheckbox>
</ConfigPanel>
);
};

View File

@@ -26,6 +26,10 @@ const setDefaultSettings = (force: boolean) => {
settings.setSync('cachePath', path.join(path.dirname(settings.file())));
}
if (force || !settings.hasSync('scrobble')) {
settings.setSync('scrobble', false);
}
if (force || !settings.hasSync('volume')) {
settings.setSync('volume', 0.3);
}

View File

@@ -75,6 +75,7 @@ export interface PlayQueue {
playerUpdated: number;
autoIncremented: boolean;
volume: number;
scrobble: boolean;
isLoading: boolean;
repeat: string;
shuffle: boolean;
@@ -119,6 +120,7 @@ const initialState: PlayQueue = {
playerUpdated: 0,
autoIncremented: false,
volume: Number(parsedSettings.volume),
scrobble: Boolean(parsedSettings.scrobble),
isLoading: Boolean(false),
repeat: String(parsedSettings.repeat),
shuffle: Boolean(parsedSettings.shuffle),
@@ -302,6 +304,9 @@ const playQueueSlice = createSlice({
case 'scrollWithCurrentSong':
state.scrollWithCurrentSong = action.payload.value;
break;
case 'scrobble':
state.scrobble = action.payload.value;
break;
default:
break;
}

View File

@@ -15,6 +15,7 @@ export const mockSettings = {
pollingInterval: 20,
fadeDuration: 9,
fadeType: 'equalPower',
scrobble: false,
gridCardSize: 200,
playlistViewType: 'grid',
albumViewType: 'grid',