feat: initial integration of react-jinke-music-player

This commit is contained in:
Deluan
2020-02-04 09:26:54 -05:00
parent 220ffd5324
commit 4a82a6cb02
13 changed files with 417 additions and 44 deletions
+26 -16
View File
@@ -1,31 +1,41 @@
// in src/App.js
import React from 'react'
import { Admin, Resource } from 'react-admin'
import dataProvider from './dataProvider'
import authProvider from './authProvider'
import { Login, Layout, DarkTheme } from './layout'
import { DarkTheme, Layout, Login } from './layout'
import user from './user'
import song from './song'
import album from './album'
import artist from './artist'
import { createMuiTheme } from '@material-ui/core/styles'
import { Player, playQueueReducer } from './player'
const theme = createMuiTheme(DarkTheme)
const App = () => (
<Admin
theme={theme}
dataProvider={dataProvider}
authProvider={authProvider}
layout={Layout}
loginPage={Login}
>
{(permissions) => [
<Resource name="artist" {...artist} options={{ subMenu: 'library' }} />,
<Resource name="album" {...album} options={{ subMenu: 'library' }} />,
<Resource name="song" {...song} options={{ subMenu: 'library' }} />,
permissions === 'admin' ? <Resource name="user" {...user} /> : null
]}
</Admin>
<>
<div>
<Admin
theme={theme}
customReducers={{ queue: playQueueReducer }}
dataProvider={dataProvider}
authProvider={authProvider}
layout={Layout}
loginPage={Login}
>
{(permissions) => [
<Resource
name="artist"
{...artist}
options={{ subMenu: 'library' }}
/>,
<Resource name="album" {...album} options={{ subMenu: 'library' }} />,
<Resource name="song" {...song} options={{ subMenu: 'library' }} />,
permissions === 'admin' ? <Resource name="user" {...user} /> : null,
<Player />
]}
</Admin>
</div>
</>
)
export default App
-1
View File
@@ -50,7 +50,6 @@ const AlbumList = (props) => (
exporter={false}
bulkActionButtons={false}
filters={<AlbumFilter />}
perPage={15}
>
<Datagrid expand={<AlbumDetails />} rowClick={albumRowClick}>
<TextField source="name" />
-1
View File
@@ -28,7 +28,6 @@ const ArtistList = (props) => (
exporter={false}
bulkActionButtons={false}
filters={<ArtistFilter />}
perPage={15}
>
<Datagrid rowClick={artistRowClick}>
<TextField source="name" />
-1
View File
@@ -1,4 +1,3 @@
// in src/Menu.js
import React, { useState, createElement } from 'react'
import { useSelector } from 'react-redux'
import { useMediaQuery } from '@material-ui/core'
+66
View File
@@ -0,0 +1,66 @@
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useAuthState } from 'react-admin'
import ReactJkMusicPlayer from 'react-jinke-music-player'
import 'react-jinke-music-player/assets/index.css'
import { syncQueue } from './queue'
const defaultOptions = {
bounds: 'body',
mode: 'full',
autoPlay: true,
preload: true,
autoPlayInitLoadPlayList: true,
clearPriorAudioLists: false,
showDownload: false,
showReload: false,
glassBg: false,
showThemeSwitch: false,
playModeText: {
order: 'order',
orderLoop: 'orderLoop',
singleLoop: 'singleLoop',
shufflePlay: 'shufflePlay'
},
defaultPosition: {
top: 300,
left: 120
}
}
const addQueueToOptions = (queue) => {
return {
...defaultOptions,
autoPlay: true,
clearPriorAudioLists: queue.clear,
audioLists: queue.queue.map((item) => item)
}
}
const Player = () => {
const dispatch = useDispatch()
const queue = useSelector((state) => state.queue)
const options = addQueueToOptions(queue)
const { authenticated } = useAuthState()
const OnAudioListsChange = (currentPlayIndex, audioLists) => {
dispatch(syncQueue(audioLists))
}
const OnAudioProgress = (info) => {
const progress = (info.currentTime / info.duration) * 100
}
if (authenticated && options.audioLists.length > 0) {
return (
<ReactJkMusicPlayer
{...options}
onAudioListsChange={OnAudioListsChange}
onAudioProgress={OnAudioProgress}
/>
)
}
return <div />
}
export default Player
+4
View File
@@ -0,0 +1,4 @@
import Player from './Player'
import { addTrack, setTrack, playQueueReducer } from './queue'
export { Player, addTrack, setTrack, playQueueReducer }
+50
View File
@@ -0,0 +1,50 @@
import 'react-jinke-music-player/assets/index.css'
const PLAYER_ADD_TRACK = 'PLAYER_ADD_TRACK'
const PLAYER_SET_TRACK = 'PLAYER_SET_TRACK'
const PLAYER_SYNC_QUEUE = 'PLAYER_SYNC_QUEUE'
const mapToAudioLists = (item) => ({
id: item.id,
name: item.title,
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}`,
musicSrc: `/rest/stream.view?u=admin&p=enc:73756e6461&f=json&v=1.8.0&c=Jamstash&id=${
item.id
}&ts=${new Date().getTime()}`
})
const addTrack = (data) => ({
type: PLAYER_ADD_TRACK,
data
})
const setTrack = (data) => ({
type: PLAYER_SET_TRACK,
data
})
const syncQueue = (data) => ({
type: PLAYER_SYNC_QUEUE,
data
})
const playQueueReducer = (
previousState = { queue: [], clear: true },
{ type, data }
) => {
switch (type) {
case PLAYER_ADD_TRACK:
const queue = previousState.queue
queue.push(mapToAudioLists(data))
return { queue, clear: false }
case PLAYER_SET_TRACK:
return { queue: [mapToAudioLists(data)], clear: true }
case PLAYER_SYNC_QUEUE:
return { queue: data, clear: false }
default:
return previousState
}
}
export { addTrack, setTrack, syncQueue, playQueueReducer }
+23
View File
@@ -0,0 +1,23 @@
import React from 'react'
import { Button, useDataProvider, useUnselectAll } from 'react-admin'
import { useDispatch } from 'react-redux'
import { addTrack } from '../player'
const AddToQueueButton = ({ selectedIds }) => {
const dispatch = useDispatch()
const dataProvider = useDataProvider()
const unselectAll = useUnselectAll()
const addToQueue = () => {
selectedIds.forEach((id) => {
dataProvider.getOne('song', { id }).then((response) => {
console.log(response.data)
dispatch(addTrack(response.data))
})
})
unselectAll('song')
}
return <Button color="secondary" label="Add To Queue" onClick={addToQueue} />
}
export default AddToQueueButton
+30
View File
@@ -0,0 +1,30 @@
import React from 'react'
import PropTypes from 'prop-types'
import PlayArrowIcon from '@material-ui/icons/PlayArrow'
import { IconButton } from '@material-ui/core'
import { useDispatch } from 'react-redux'
import { setTrack } from '../player'
const defaultIcon = <PlayArrowIcon fontSize="small" />
const PlayButton = ({
record,
icon = defaultIcon,
action = setTrack,
...rest
}) => {
const dispatch = useDispatch()
return (
<IconButton onClick={() => dispatch(action(record))} {...rest}>
{icon}
</IconButton>
)
}
PlayButton.propTypes = {
record: PropTypes.any,
icon: PropTypes.element,
action: PropTypes.func
}
export default PlayButton
+34 -24
View File
@@ -1,4 +1,4 @@
import React from 'react'
import React, { Fragment } from 'react'
import {
BooleanField,
Datagrid,
@@ -7,12 +7,14 @@ import {
List,
NumberField,
SearchInput,
TextInput,
Show,
SimpleShowLayout,
TextField
TextField,
TextInput
} from 'react-admin'
import { BitrateField, DurationField, Title } from '../common'
import AddToQueueButton from './AddToQueueButton'
import PlayButton from './PlayButton'
const SongFilter = (props) => (
<Filter {...props}>
@@ -22,6 +24,12 @@ const SongFilter = (props) => (
</Filter>
)
const SongBulkActionButtons = (props) => (
<Fragment>
<AddToQueueButton {...props} />
</Fragment>
)
const SongDetails = (props) => {
return (
<Show {...props} title=" ">
@@ -37,26 +45,28 @@ const SongDetails = (props) => {
)
}
const SongList = (props) => (
<List
{...props}
title={<Title subTitle={'Songs'} />}
sort={{ field: 'title', order: 'ASC' }}
exporter={false}
bulkActionButtons={false}
filters={<SongFilter />}
perPage={15}
>
<Datagrid expand={<SongDetails />}>
<TextField source="title" />
<TextField source="album" />
<TextField source="artist" />
<NumberField label="Track #" source="trackNumber" />
<NumberField label="Disc #" source="discNumber" />
<TextField source="year" />
<DurationField label="Time" source="duration" />
</Datagrid>
</List>
)
const SongList = (props) => {
return (
<List
{...props}
title={<Title subTitle={'Songs'} />}
sort={{ field: 'title', order: 'ASC' }}
exporter={false}
bulkActionButtons={<SongBulkActionButtons />}
filters={<SongFilter />}
>
<Datagrid expand={<SongDetails />}>
<PlayButton {...props} />
<TextField source="title" />
<TextField source="album" />
<TextField source="artist" />
<NumberField label="Track #" source="trackNumber" />
<NumberField label="Disc #" source="discNumber" />
<TextField source="year" />
<DurationField label="Time" source="duration" />
</Datagrid>
</List>
)
}
export default SongList