Implement Last.fm account linking UI
This commit is contained in:
committed by
Deluan Quintão
parent
8b62a58b4c
commit
5fbfd9c81e
@@ -1 +1,17 @@
|
|||||||
Success! Your account is linked to Last.FM. You can close this tab now.
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>Account Linking Success</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>
|
||||||
|
Success! Your account is linked to Last.fm. You can close this tab now.
|
||||||
|
</h2>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
window.close();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
+7
-2
@@ -297,7 +297,11 @@
|
|||||||
"delete_user_title": "Delete user '%{name}'",
|
"delete_user_title": "Delete user '%{name}'",
|
||||||
"delete_user_content": "Are you sure you want to delete this user and all their data (including playlists and preferences)?",
|
"delete_user_content": "Are you sure you want to delete this user and all their data (including playlists and preferences)?",
|
||||||
"notifications_blocked": "You have blocked Notifications for this site in your browser's settings",
|
"notifications_blocked": "You have blocked Notifications for this site in your browser's settings",
|
||||||
"notifications_not_available": "This browser does not support desktop notifications or you are not accessing Navidrome over https"
|
"notifications_not_available": "This browser does not support desktop notifications or you are not accessing Navidrome over https",
|
||||||
|
"lastfmLinkSuccess": "Last.fm successfully linked and scrobbling enabled",
|
||||||
|
"lastfmLinkFailure": "Last.fm could not be linked",
|
||||||
|
"lastfmUnlinkSuccess": "Last.fm unlinked and scrobbling disabled",
|
||||||
|
"lastfmUnlinkFailure": "Last.fm could not unlinked"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"library": "Library",
|
"library": "Library",
|
||||||
@@ -310,7 +314,8 @@
|
|||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"defaultView": "Default View",
|
"defaultView": "Default View",
|
||||||
"desktop_notifications": "Desktop Notifications"
|
"desktop_notifications": "Desktop Notifications",
|
||||||
|
"lastfmScrobbling": "Scrobble to Last.fm"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"albumList": "Albums",
|
"albumList": "Albums",
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
import { useNotify, useTranslate } from 'react-admin'
|
||||||
|
import {
|
||||||
|
FormControl,
|
||||||
|
FormControlLabel,
|
||||||
|
LinearProgress,
|
||||||
|
Switch,
|
||||||
|
} from '@material-ui/core'
|
||||||
|
import { useInterval } from '../common'
|
||||||
|
import config from '../config'
|
||||||
|
import { baseUrl, openInNewTab } from '../utils'
|
||||||
|
import { httpClient } from '../dataProvider'
|
||||||
|
|
||||||
|
const Progress = (props) => {
|
||||||
|
const { setLinked, setCheckingLink } = props
|
||||||
|
const notify = useNotify()
|
||||||
|
let linkCheckDelay = 2000
|
||||||
|
let linkChecks = 30
|
||||||
|
const openedTab = useRef()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const callbackEndpoint = baseUrl(
|
||||||
|
`/api/lastfm/link/callback?uid=${localStorage.getItem('userId')}`
|
||||||
|
)
|
||||||
|
const callbackUrl = `${window.location.origin}${callbackEndpoint}`
|
||||||
|
openedTab.current = openInNewTab(
|
||||||
|
`https://www.last.fm/api/auth/?api_key=${config.lastFMApiKey}&cb=${callbackUrl}`
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const endChecking = (success) => {
|
||||||
|
linkCheckDelay = null
|
||||||
|
setCheckingLink(false)
|
||||||
|
if (success) {
|
||||||
|
notify('message.lastfmLinkSuccess', 'success')
|
||||||
|
} else {
|
||||||
|
notify('message.lastfmLinkFailure', 'warning')
|
||||||
|
}
|
||||||
|
setLinked(success)
|
||||||
|
}
|
||||||
|
|
||||||
|
useInterval(() => {
|
||||||
|
httpClient('/api/lastfm/link')
|
||||||
|
.then((response) => {
|
||||||
|
let result = false
|
||||||
|
if (response.json.status === true) {
|
||||||
|
result = true
|
||||||
|
endChecking(true)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (!result && openedTab.current?.closed === true) {
|
||||||
|
endChecking(false)
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
|
if (!result && --linkChecks === 0) {
|
||||||
|
endChecking(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
endChecking(false)
|
||||||
|
})
|
||||||
|
}, linkCheckDelay)
|
||||||
|
|
||||||
|
return <LinearProgress />
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LastfmScrobbleToggle = (props) => {
|
||||||
|
const notify = useNotify()
|
||||||
|
const translate = useTranslate()
|
||||||
|
const [linked, setLinked] = useState(null)
|
||||||
|
const [checkingLink, setCheckingLink] = useState(false)
|
||||||
|
|
||||||
|
const toggleScrobble = () => {
|
||||||
|
if (!linked) {
|
||||||
|
setCheckingLink(true)
|
||||||
|
} else {
|
||||||
|
httpClient('/api/lastfm/link', { method: 'DELETE' })
|
||||||
|
.then(() => {
|
||||||
|
setLinked(false)
|
||||||
|
notify('message.lastfmUnlinkSuccess', 'success')
|
||||||
|
})
|
||||||
|
.catch(() => notify('message.lastfmUnlinkFailure', 'warning'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
httpClient('/api/lastfm/link')
|
||||||
|
.then((response) => {
|
||||||
|
setLinked(response.json.status === true)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setLinked(false)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormControl>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Switch
|
||||||
|
id={'lastfm'}
|
||||||
|
color="primary"
|
||||||
|
checked={linked || checkingLink}
|
||||||
|
disabled={linked === null || checkingLink}
|
||||||
|
onChange={toggleScrobble}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<span>{translate('menu.personal.options.lastfmScrobbling')}</span>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{checkingLink && (
|
||||||
|
<Progress setLinked={setLinked} setCheckingLink={setCheckingLink} />
|
||||||
|
)}
|
||||||
|
</FormControl>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import { SelectLanguage } from './SelectLanguage'
|
|||||||
import { SelectTheme } from './SelectTheme'
|
import { SelectTheme } from './SelectTheme'
|
||||||
import { SelectDefaultView } from './SelectDefaultView'
|
import { SelectDefaultView } from './SelectDefaultView'
|
||||||
import { NotificationsToggle } from './NotificationsToggle'
|
import { NotificationsToggle } from './NotificationsToggle'
|
||||||
import { ScrobbleToggle } from './ScrobbleToggle'
|
import { LastfmScrobbleToggle } from './LastfmScrobbleToggle'
|
||||||
import config from '../config'
|
import config from '../config'
|
||||||
|
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
@@ -24,7 +24,7 @@ const Personal = () => {
|
|||||||
<SelectLanguage />
|
<SelectLanguage />
|
||||||
<SelectDefaultView />
|
<SelectDefaultView />
|
||||||
<NotificationsToggle />
|
<NotificationsToggle />
|
||||||
{config.devEnableScrobble && <ScrobbleToggle />}
|
{config.devEnableScrobble && <LastfmScrobbleToggle />}
|
||||||
</SimpleForm>
|
</SimpleForm>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,84 +0,0 @@
|
|||||||
import { useState } from 'react'
|
|
||||||
import { useNotify, useTranslate } from 'react-admin'
|
|
||||||
import {
|
|
||||||
FormControl,
|
|
||||||
FormControlLabel,
|
|
||||||
LinearProgress,
|
|
||||||
Switch,
|
|
||||||
} from '@material-ui/core'
|
|
||||||
import { useInterval } from '../common'
|
|
||||||
import { baseUrl } from '../utils'
|
|
||||||
|
|
||||||
const Progress = (props) => {
|
|
||||||
const { setLinked, setCheckingLink } = props
|
|
||||||
const translate = useTranslate()
|
|
||||||
const notify = useNotify()
|
|
||||||
let linkCheckDelay = 2000
|
|
||||||
let linkChecks = 5
|
|
||||||
// openInNewTab(
|
|
||||||
// '/api/lastfm/link'
|
|
||||||
// )
|
|
||||||
|
|
||||||
const endChecking = (success) => {
|
|
||||||
linkCheckDelay = null
|
|
||||||
setCheckingLink(false)
|
|
||||||
if (success) {
|
|
||||||
notify(translate('Last.fm successfully linked!'), 'success')
|
|
||||||
} else {
|
|
||||||
notify(translate('Last.fm could not be linked'), 'warning')
|
|
||||||
}
|
|
||||||
setLinked(success)
|
|
||||||
}
|
|
||||||
|
|
||||||
useInterval(() => {
|
|
||||||
fetch(baseUrl(`/api/lastfm/link/status?c=${linkChecks}`))
|
|
||||||
.then((response) => response.text())
|
|
||||||
.then((response) => {
|
|
||||||
if (response === 'true') {
|
|
||||||
endChecking(true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
endChecking(false)
|
|
||||||
throw new Error(error)
|
|
||||||
})
|
|
||||||
|
|
||||||
if (--linkChecks === 0) {
|
|
||||||
endChecking(false)
|
|
||||||
}
|
|
||||||
}, linkCheckDelay)
|
|
||||||
|
|
||||||
return linkChecks > 0 && <LinearProgress />
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ScrobbleToggle = (props) => {
|
|
||||||
const translate = useTranslate()
|
|
||||||
const [linked, setLinked] = useState(false)
|
|
||||||
const [checkingLink, setCheckingLink] = useState(false)
|
|
||||||
const toggleScrobble = () => {
|
|
||||||
if (!linked) {
|
|
||||||
return setCheckingLink(true)
|
|
||||||
}
|
|
||||||
setLinked(!linked)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormControl>
|
|
||||||
<FormControlLabel
|
|
||||||
control={
|
|
||||||
<Switch
|
|
||||||
id={'notifications'}
|
|
||||||
color="primary"
|
|
||||||
checked={linked || checkingLink}
|
|
||||||
disabled={checkingLink}
|
|
||||||
onChange={toggleScrobble}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label={<span>{translate('Scrobble to Last.FM')}</span>}
|
|
||||||
/>
|
|
||||||
{checkingLink && (
|
|
||||||
<Progress setLinked={setLinked} setCheckingLink={setCheckingLink} />
|
|
||||||
)}
|
|
||||||
</FormControl>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
export const openInNewTab = (url) => {
|
export const openInNewTab = (url) => {
|
||||||
const win = window.open(url, '_blank')
|
const win = window.open(url, '_blank')
|
||||||
win.focus()
|
win.focus()
|
||||||
|
return win
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user