export default class AudioPlayer { files = {} players = {} current_background_id = 0 constructor() { this.done = this.done.bind(this) } load(graph) { this.files = graph.uploads .filter(upload => upload.tag === 'audio') .reduce((accumulator, item) => { accumulator[item.id] = item return accumulator }, {}) } done(id) { console.log('remove', id) delete this.players[id] } playPage(page) { const { background_audio_id, restart_audio } = page.settings console.log('playPage', background_audio_id) if ( this.current_background_id && this.current_background_id !== background_audio_id && this.current_background_id in this.players ) { this.players[this.current_background_id].stop() } if (background_audio_id in this.files) { this.current_background_id = background_audio_id this.playFile({ item: this.files[background_audio_id], restart: !!restart_audio, }) } } playFile({ item, restart, loop }) { const { id } = item if (id in this.players) { if (restart) { this.players[id].restart() } return this.players[id] } else { this.players[id] = new Player(item, this.done) this.players[id].play() return this.players[id] } } } class Player { constructor(item, done) { this.item = item this.done = done this.audio = document.createElement('audio') this.handleEnded = this.handleEnded.bind(this) this.handleError = this.handleError.bind(this) this.release = this.release.bind(this) this.audio.addEventListener('ended', this.handleEnded) this.audio.addEventListener('error', this.handleError) this.audio.src = item.url } release() { this.audio.removeEventListener('ended', this.handleEnded) this.audio.removeEventListener('error', this.handleError) this.done(this.item.id) this.item = null this.done = null this.audio = null } handleError(error) { console.error(error) this.release() } handleEnded() { this.release() } play() { console.log('play', this.item.id) this.audio.play() } restart() { console.log('replay', this.item.id) this.audio.currentTime = 0 this.audio.play() } stop() { console.log('stop', this.item.id) this.audio.pause() this.release() } }