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 ( <>
dispatch({type: 'SOUND_ERROR', payload: {code, desc}})} onPlaying={(payload) => dispatch({type: 'SOUND_PLAYING', payload})} onFinishedPlaying={() => dispatch({type: 'SOUND_FINISHED'})} /> dispatch({type:'CONTROL_PLAY'})} onPause={()=>dispatch({type:'CONTROL_PAUSE'})} onPreviousTrack={()=>dispatch({type:'CONTROL_PREV'})} onNextTrack={()=>dispatch({type:'CONTROL_NEXT'})} /> ); }