| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- import {useReducer, useEffect} from 'react';
- import Sound from 'react-sound';
- import Main from './Main';
- import Queue from './Queue';
- import Controls from './Controls';
- import MediaSession from './MediaSession.js';
- const NO_SOUND = {url: '', playStatus: Sound.status.STOPPED};
- const NO_METADATA = {artist: '', album: '', title: '', cover: ''};
- const NO_QUEUE = {items: [], pos: -1};
- const NO_ERROR = null;
- function storeQueue(queue) {
- localStorage.setItem('queue', JSON.stringify(queue));
- }
- function loadQueue() {
- const queue = localStorage.getItem('queue');
- return queue && JSON.parse(queue);
- }
- function playTrack(track, status) {
- return {
- sound: {url: track.url,
- position: 0,
- playStatus: (status || Sound.status.PLAYING)},
- metadata: {
- title: track.title,
- artist: track.artist,
- album: track.album,
- cover: track.cover
- },
- error: NO_ERROR
- }
- }
- function playQueue(state, pos) {
- if (pos < 0 || pos >= state.queue.items.length)
- return {...state, sound: NO_SOUND, metadata: NO_METADATA};
- const queue = {...state.queue, pos}
- storeQueue(queue);
- return {...state, queue, ...playTrack(state.queue.items[pos])}
- }
- function playerReducer(state, action) {
- switch (action.type) {
- case 'ALBUM_PLAY': {
- if (!action.payload || !action.payload.tracks) return state;
- const queue = {items: action.payload.tracks}
- return playQueue({...state, queue}, (action.payload.pos || 0))}
- case 'ALBUM_ENQUEUE': {
- if (!action.payload) return state;
- const queue = {...state.queue, items: state.queue.items.concat(action.payload.tracks)};
- return {...state, queue}}
- case 'CONTROL_PLAY':
- return {...state, sound: {...state.sound, playStatus: Sound.status.PLAYING}}
- case 'CONTROL_PAUSE':
- return {...state, sound: {...state.sound, playStatus: Sound.status.PAUSED}}
- case 'CONTROL_PREV':
- return playQueue(state, state.queue.pos - 1);
- case 'CONTROL_NEXT':
- return playQueue(state, state.queue.pos + 1);
- case 'CONTROL_STOP':
- return {...state, queue: {...state.queue, pos:-1}, sound: NO_SOUND, metadata: NO_METADATA}
- case 'QUEUE_PLAY':
- return playQueue(state, action.payload);
- case 'QUEUE_LOAD': {
- const queue = action.payload;
- return {...state, queue, ...playTrack(queue.items[queue.pos], Sound.status.PAUSED)}}
- case 'SOUND_ERROR':
- return {...state, sound: NO_SOUND, metadata: NO_METADATA, error: action.payload}
- case 'SOUND_PLAYING':
- return {...state, sound: {...state.sound, ...action.payload}}
- case 'SOUND_FINISHED':
- return playQueue(state, state.queue.pos + 1);
- default: throw new Error(`Unknown action type: ${action.type}`);
- }
- }
- export default function Player() {
- const INIT = {sound: NO_SOUND,
- error: NO_ERROR,
- queue: NO_QUEUE,
- metadata: NO_METADATA}
- const [state, dispatch] = useReducer(playerReducer, INIT);
- useEffect(()=>{
- const queue = loadQueue();
- if (queue) dispatch({type: 'QUEUE_LOAD', payload: queue});
- }, []);
- return (
- <>
- <Main dispatch={dispatch} />
- <Queue queue={state.queue} dispatch={dispatch} />
- <Controls {...state} dispatch={dispatch} />
- <Sound {...state.sound}
- onError={(code,desc) => dispatch({type: 'SOUND_ERROR', payload: {code, desc}})}
- onPlaying={(payload) => dispatch({type: 'SOUND_PLAYING', payload})}
- onFinishedPlaying={() => dispatch({type: 'SOUND_FINISHED'})} />
- <MediaSession
- {...state.metadata}
- onPlay={()=>dispatch({type:'CONTROL_PLAY'})}
- onPause={()=>dispatch({type:'CONTROL_PAUSE'})}
- onPreviousTrack={()=>dispatch({type:'CONTROL_PREV'})}
- onNextTrack={()=>dispatch({type:'CONTROL_NEXT'})}
- />
- </>
- );
- }
|