feat: scrobbling
This commit is contained in:
+23
-2
@@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { useAuthState } from 'react-admin'
|
import { fetchUtils, useAuthState } from 'react-admin'
|
||||||
import ReactJkMusicPlayer from 'react-jinke-music-player'
|
import ReactJkMusicPlayer from 'react-jinke-music-player'
|
||||||
import 'react-jinke-music-player/assets/index.css'
|
import 'react-jinke-music-player/assets/index.css'
|
||||||
import { syncQueue } from './queue'
|
import { markScrobbled, syncQueue } from './queue'
|
||||||
|
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
bounds: 'body',
|
bounds: 'body',
|
||||||
@@ -49,6 +49,26 @@ const Player = () => {
|
|||||||
|
|
||||||
const OnAudioProgress = (info) => {
|
const OnAudioProgress = (info) => {
|
||||||
const progress = (info.currentTime / info.duration) * 100
|
const progress = (info.currentTime / info.duration) * 100
|
||||||
|
if (isNaN(info.duration) || progress < 90) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const item = queue.queue.find((item) => item.id === info.id)
|
||||||
|
if (item && !item.scrobbled) {
|
||||||
|
dispatch(markScrobbled(info.id, true))
|
||||||
|
fetchUtils.fetchJson(
|
||||||
|
`/rest/scrobble?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=NavidromeUI&id=${info.id}&submission=true`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const OnAudioPlay = (info) => {
|
||||||
|
console.log('AUDIOPLAY: ', info)
|
||||||
|
if (info.duration) {
|
||||||
|
dispatch(markScrobbled(info.id, false))
|
||||||
|
fetchUtils.fetchJson(
|
||||||
|
`/rest/scrobble?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=NavidromeUI&id=${info.id}&submission=false`
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authenticated && options.audioLists.length > 0) {
|
if (authenticated && options.audioLists.length > 0) {
|
||||||
@@ -57,6 +77,7 @@ const Player = () => {
|
|||||||
{...options}
|
{...options}
|
||||||
onAudioListsChange={OnAudioListsChange}
|
onAudioListsChange={OnAudioListsChange}
|
||||||
onAudioProgress={OnAudioProgress}
|
onAudioProgress={OnAudioProgress}
|
||||||
|
onAudioPlay={OnAudioPlay}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -3,13 +3,14 @@ import 'react-jinke-music-player/assets/index.css'
|
|||||||
const PLAYER_ADD_TRACK = 'PLAYER_ADD_TRACK'
|
const PLAYER_ADD_TRACK = 'PLAYER_ADD_TRACK'
|
||||||
const PLAYER_SET_TRACK = 'PLAYER_SET_TRACK'
|
const PLAYER_SET_TRACK = 'PLAYER_SET_TRACK'
|
||||||
const PLAYER_SYNC_QUEUE = 'PLAYER_SYNC_QUEUE'
|
const PLAYER_SYNC_QUEUE = 'PLAYER_SYNC_QUEUE'
|
||||||
|
const PLAYER_SCROBBLE = 'PLAYER_SCROBBLE'
|
||||||
|
|
||||||
const mapToAudioLists = (item) => ({
|
const mapToAudioLists = (item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.title,
|
name: item.title,
|
||||||
singer: item.artist,
|
singer: item.artist,
|
||||||
cover: `/rest/getCoverArt.view?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=Jamstash&size=300&id=${item.id}`,
|
cover: `/rest/getCoverArt?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=NavidromeUI&size=300&id=${item.id}`,
|
||||||
musicSrc: `/rest/stream.view?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=Jamstash&id=${
|
musicSrc: `/rest/stream?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=NavidromeUI&id=${
|
||||||
item.id
|
item.id
|
||||||
}&ts=${new Date().getTime()}`
|
}&ts=${new Date().getTime()}`
|
||||||
})
|
})
|
||||||
@@ -29,6 +30,11 @@ const syncQueue = (data) => ({
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const markScrobbled = (id, submission = false) => ({
|
||||||
|
type: PLAYER_SCROBBLE,
|
||||||
|
data: { id, submission }
|
||||||
|
})
|
||||||
|
|
||||||
const playQueueReducer = (
|
const playQueueReducer = (
|
||||||
previousState = { queue: [], clear: true },
|
previousState = { queue: [], clear: true },
|
||||||
{ type, data }
|
{ type, data }
|
||||||
@@ -42,9 +48,17 @@ const playQueueReducer = (
|
|||||||
return { queue: [mapToAudioLists(data)], clear: true }
|
return { queue: [mapToAudioLists(data)], clear: true }
|
||||||
case PLAYER_SYNC_QUEUE:
|
case PLAYER_SYNC_QUEUE:
|
||||||
return { queue: data, clear: false }
|
return { queue: data, clear: false }
|
||||||
|
case PLAYER_SCROBBLE:
|
||||||
|
const newQueue = previousState.queue.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
scrobbled: item.scrobbled || (item.id === data.id && data.submission)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return { queue: newQueue, clear: false }
|
||||||
default:
|
default:
|
||||||
return previousState
|
return previousState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { addTrack, setTrack, syncQueue, playQueueReducer }
|
export { addTrack, setTrack, syncQueue, markScrobbled, playQueueReducer }
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const AddToQueueButton = ({ selectedIds }) => {
|
|||||||
const addToQueue = () => {
|
const addToQueue = () => {
|
||||||
selectedIds.forEach((id) => {
|
selectedIds.forEach((id) => {
|
||||||
dataProvider.getOne('song', { id }).then((response) => {
|
dataProvider.getOne('song', { id }).then((response) => {
|
||||||
console.log(response.data)
|
|
||||||
dispatch(addTrack(response.data))
|
dispatch(addTrack(response.data))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user