Listenbrainz scrobbling (#1424)

* Refactor session_keys to its own package

* Adjust play_tracker

- Don't send external NowPlaying/Scrobble for tracks with unknown artist
- Continue to the next agent on error

* Implement ListenBrainz Agent and Auth Router

* Implement frontend for ListenBrainz linking

* Update listenBrainzRequest

- Don't marshal Player to json
- Rename Track to Title

* Return ErrRetryLater on ListenBrainz server errors

* Add tests for listenBrainzAgent

* Add tests for ListenBrainz Client

* Adjust ListenBrainzTokenDialog to handle errors better

* Refactor listenbrainz.formatListen and listenBrainzRequest structs

* Refactor agent auth_routers

* Refactor session_keys to agents package

* Add test for listenBrainzResponse

* Add tests for ListenBrainz auth_router

* Update ListenBrainzTokenDialog and auth_router

* Adjust player scrobble toggle
This commit is contained in:
Steve Richter
2021-10-30 12:17:42 -04:00
committed by GitHub
parent ccc871d1f7
commit a56d5bc850
33 changed files with 1214 additions and 54 deletions
+138
View File
@@ -0,0 +1,138 @@
import React, { createRef, useCallback, useState } from 'react'
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
LinearProgress,
Link,
TextField,
} from '@material-ui/core'
import { useNotify, useTranslate } from 'react-admin'
import { useDispatch, useSelector } from 'react-redux'
import { closeListenBrainzTokenDialog } from '../actions'
import { httpClient } from '../dataProvider'
export const ListenBrainzTokenDialog = ({ setLinked }) => {
const dispatch = useDispatch()
const notify = useNotify()
const translate = useTranslate()
const { open } = useSelector((state) => state.listenBrainzTokenDialog)
const [token, setToken] = useState('')
const [checking, setChecking] = useState(false)
const inputRef = createRef()
const handleChange = (event) => {
setToken(event.target.value)
}
const handleLinkClick = (event) => {
inputRef.current.focus()
}
const handleSave = useCallback(
(event) => {
setChecking(true)
httpClient('/api/listenbrainz/link', {
method: 'PUT',
body: JSON.stringify({ token: token }),
})
.then((response) => {
notify('message.listenBrainzLinkSuccess', 'success', {
user: response.json.user,
})
setLinked(true)
setToken('')
})
.catch((error) => {
notify('message.listenBrainzLinkFailure', 'warning', {
error: error.body?.error || error.message,
})
setLinked(false)
})
.finally(() => {
setChecking(false)
dispatch(closeListenBrainzTokenDialog())
event.stopPropagation()
})
},
[dispatch, notify, setLinked, token]
)
const handleClickClose = (event) => {
if (!checking) {
dispatch(closeListenBrainzTokenDialog())
event.stopPropagation()
}
}
const handleKeyPress = useCallback(
(event) => {
if (event.key === 'Enter' && token !== '') {
handleSave(event)
}
},
[token, handleSave]
)
return (
<>
<Dialog
open={open}
onClose={handleClickClose}
onBackdropClick={handleClickClose}
aria-labelledby="form-dialog-listenbrainz-token"
fullWidth={true}
maxWidth="md"
>
<DialogTitle id="form-dialog-listenbrainz-token">
ListenBrainz
</DialogTitle>
<DialogContent>
<DialogContentText>
{translate('resources.user.message.listenBrainzToken')}{' '}
<Link
href="https://listenbrainz.org/profile/"
onClick={handleLinkClick}
target="_blank"
>
{translate('resources.user.message.clickHereForToken')}
</Link>
</DialogContentText>
<TextField
value={token}
onKeyPress={handleKeyPress}
onChange={handleChange}
disabled={checking}
required
autoFocus
fullWidth={true}
variant={'outlined'}
label={translate('resources.user.fields.token')}
inputRef={inputRef}
/>
{checking && <LinearProgress />}
</DialogContent>
<DialogActions>
<Button
onClick={handleClickClose}
disabled={checking}
color="primary"
>
{translate('ra.action.cancel')}
</Button>
<Button
onClick={handleSave}
disabled={checking || token === ''}
color="primary"
data-testid="listenbrainz-token-save"
>
{translate('ra.action.save')}
</Button>
</DialogActions>
</Dialog>
</>
)
}
+1
View File
@@ -2,3 +2,4 @@ export * from './AboutDialog'
export * from './AddToPlaylistDialog'
export * from './SelectPlaylistInput'
export * from './HelpDialog'
export * from './ListenBrainzTokenDialog'