quintodrome/ui/src/audioplayer/Player.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

226 lines
6.4 KiB
JavaScript
Raw Normal View History

2020-06-19 15:43:33 -08:00
import React, { useCallback, useMemo } from 'react'
2020-07-08 17:23:51 -08:00
import ReactGA from 'react-ga'
import { useDispatch, useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { useAuthState, useDataProvider, useTranslate } from 'react-admin'
import ReactJkMusicPlayer from 'react-jinke-music-player'
import 'react-jinke-music-player/assets/index.css'
import subsonic from '../subsonic'
2020-09-24 09:34:17 -08:00
import {
scrobble,
syncQueue,
currentPlaying,
setVolume,
clearQueue,
} from './queue'
import themes from '../themes'
import { makeStyles } from '@material-ui/core/styles'
2020-07-08 17:23:51 -08:00
import config from '../config'
import Hotkeys from 'react-hot-keys'
const useStyle = makeStyles((theme) => ({
audioTitle: {
textDecoration: 'none',
color: theme.palette.primary.light,
},
}))
let audioInstance = null
2020-02-07 05:40:52 -09:00
const Player = () => {
const classes = useStyle()
2020-02-07 05:40:52 -09:00
const translate = useTranslate()
const currentTheme = useSelector((state) => state.theme)
const theme = themes[currentTheme] || themes.DarkTheme
const playerTheme = (theme.player && theme.player.theme) || 'dark'
2020-06-19 15:43:33 -08:00
const audioTitle = useCallback(
(audioInfo) => (
<Link
to={`/album/${audioInfo.albumId}/show`}
className={classes.audioTitle}
>
{audioInfo.name ? `${audioInfo.name} - ${audioInfo.singer}` : ''}
</Link>
),
[classes.audioTitle]
)
2020-02-07 05:40:52 -09:00
const defaultOptions = {
theme: playerTheme,
2020-02-07 05:40:52 -09:00
bounds: 'body',
mode: 'full',
autoPlay: false,
2020-02-07 05:40:52 -09:00
preload: true,
autoPlayInitLoadPlayList: true,
loadAudioErrorPlayNext: false,
2020-02-07 05:40:52 -09:00
clearPriorAudioLists: false,
2020-09-24 09:34:17 -08:00
showDestroy: true,
2020-02-07 05:40:52 -09:00
showDownload: false,
showReload: false,
glassBg: false,
showThemeSwitch: false,
showMediaSession: true,
2020-02-07 05:40:52 -09:00
defaultPosition: {
top: 300,
left: 120,
},
locale: {
playListsText: translate('player.playListsText'),
openText: translate('player.openText'),
closeText: translate('player.closeText'),
notContentText: translate('player.notContentText'),
clickToPlayText: translate('player.clickToPlayText'),
clickToPauseText: translate('player.clickToPauseText'),
nextTrackText: translate('player.nextTrackText'),
previousTrackText: translate('player.previousTrackText'),
reloadText: translate('player.reloadText'),
volumeText: translate('player.volumeText'),
toggleLyricText: translate('player.toggleLyricText'),
toggleMiniModeText: translate('player.toggleMiniModeText'),
destroyText: translate('player.destroyText'),
downloadText: translate('player.downloadText'),
removeAudioListsText: translate('player.removeAudioListsText'),
audioTitle: audioTitle,
clickToDeleteText: (name) =>
translate('player.clickToDeleteText', { name }),
emptyLyricText: translate('player.emptyLyricText'),
playModeText: {
order: translate('player.playModeText.order'),
orderLoop: translate('player.playModeText.orderLoop'),
singleLoop: translate('player.playModeText.singleLoop'),
shufflePlay: translate('player.playModeText.shufflePlay'),
},
2020-02-07 05:40:52 -09:00
},
}
2020-06-19 15:43:33 -08:00
const dataProvider = useDataProvider()
const dispatch = useDispatch()
const queue = useSelector((state) => state.queue)
const { authenticated } = useAuthState()
const options = useMemo(() => {
2020-02-07 05:40:52 -09:00
return {
...defaultOptions,
clearPriorAudioLists: queue.clear,
autoPlay: queue.clear || queue.playIndex === 0,
playIndex: queue.playIndex,
2020-02-07 05:40:52 -09:00
audioLists: queue.queue.map((item) => item),
2020-06-24 11:33:59 -08:00
defaultVolume: queue.volume,
2020-02-07 05:40:52 -09:00
}
2020-09-24 05:58:01 -08:00
}, [queue.clear, queue.queue, queue.volume, queue.playIndex, defaultOptions])
2020-06-19 15:43:33 -08:00
const OnAudioListsChange = useCallback(
(currentPlayIndex, audioLists) => {
dispatch(syncQueue(currentPlayIndex, audioLists))
},
[dispatch]
)
2020-06-19 15:43:33 -08:00
const OnAudioProgress = useCallback(
(info) => {
if (info.ended) {
document.title = 'Navidrome'
}
const progress = (info.currentTime / info.duration) * 100
if (isNaN(info.duration) || progress < 90) {
return
}
const item = queue.queue.find((item) => item.trackId === info.trackId)
if (item && !item.scrobbled) {
dispatch(scrobble(info.trackId, true))
subsonic.scrobble(info.trackId, true)
}
},
[dispatch, queue.queue]
)
2020-02-05 06:11:42 -09:00
2020-06-24 11:33:59 -08:00
const onAudioVolumeChange = useCallback(
(volume) => dispatch(setVolume(volume)),
[dispatch]
)
2020-06-19 15:43:33 -08:00
const OnAudioPlay = useCallback(
(info) => {
dispatch(currentPlaying(info))
if (info.duration) {
document.title = `${info.name} - ${info.singer} - Navidrome`
dispatch(scrobble(info.trackId, false))
subsonic.scrobble(info.trackId, false)
2020-07-08 17:23:51 -08:00
if (config.gaTrackingId) {
ReactGA.event({
category: 'Player',
action: 'Play song',
label: `${info.name} - ${info.singer}`,
})
}
2020-06-19 15:43:33 -08:00
}
},
[dispatch]
)
2020-06-19 15:43:33 -08:00
const onAudioPause = useCallback(
(info) => {
dispatch(currentPlaying(info))
},
[dispatch]
)
2020-06-19 15:43:33 -08:00
const onAudioEnded = useCallback(
(currentPlayId, audioLists, info) => {
dispatch(currentPlaying(info))
dataProvider.getOne('keepalive', { id: info.trackId })
},
[dispatch, dataProvider]
)
2020-09-24 09:34:17 -08:00
const onBeforeDestroy = useCallback(() => {
return new Promise((resolve, reject) => {
dispatch(clearQueue())
reject()
})
}, [dispatch])
const onKeyUp = useCallback((keyName, e) => {
if (keyName === 'space') {
e.preventDefault()
}
}, [])
const onKeyDown = useCallback((keyName, e) => {
if (keyName === 'space') {
e.preventDefault()
audioInstance && audioInstance.togglePlay()
}
}, [])
if (authenticated && options.audioLists.length > 0) {
return (
<Hotkeys
keyName="space"
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
allowRepeat={false}
>
<ReactJkMusicPlayer
{...options}
quietUpdate
onAudioListsChange={OnAudioListsChange}
onAudioProgress={OnAudioProgress}
onAudioPlay={OnAudioPlay}
onAudioPause={onAudioPause}
onAudioEnded={onAudioEnded}
onAudioVolumeChange={onAudioVolumeChange}
onBeforeDestroy={onBeforeDestroy}
getAudioInstance={(instance) => {
audioInstance = instance
}}
/>
</Hotkeys>
)
}
document.title = 'Navidrome'
return null
}
export default Player