111 lines
2.5 KiB
JavaScript
111 lines
2.5 KiB
JavaScript
import {writable} from 'svelte/store';
|
|
import {tweened} from 'svelte/motion';
|
|
import {cubicOut} from 'svelte/easing';
|
|
|
|
export let songPlayerStore = null;
|
|
export let currentTimeStore = null;
|
|
|
|
const DEFAULT_STATE = {
|
|
currentHash: null,
|
|
playing: false,
|
|
duration: 0,
|
|
currentTime: 0,
|
|
volume: 0.3,
|
|
};
|
|
|
|
export default () => {
|
|
if (songPlayerStore) return songPlayerStore;
|
|
|
|
let currentState = {...DEFAULT_STATE};
|
|
let audio = null;
|
|
currentTimeStore = tweened(0, {duration: 10, easing: cubicOut});
|
|
|
|
const {subscribe, set, update} = writable(currentState);
|
|
|
|
function cleanup() {
|
|
if (audio) {
|
|
audio.removeEventListener('timeupdate', handleTimeUpdate);
|
|
audio.removeEventListener('loadedmetadata', handleMetadata);
|
|
audio.removeEventListener('ended', handleEnded);
|
|
audio.removeEventListener('pause', handleEnded);
|
|
audio.pause();
|
|
audio.currentTime = 0;
|
|
|
|
audio = null;
|
|
}
|
|
}
|
|
|
|
function handleTimeUpdate() {
|
|
currentTimeStore.set(audio.currentTime);
|
|
}
|
|
|
|
function handleMetadata() {
|
|
update(state => ({...state, duration: audio.duration}));
|
|
}
|
|
|
|
function handleEnded() {
|
|
update(state => ({...state, playing: false, currentHash: null}));
|
|
}
|
|
|
|
function togglePlay(hash, local = false) {
|
|
update(state => {
|
|
const isPlaying = hash == state.currentHash ? !state.playing : true;
|
|
|
|
let url = local ? `https://cdn.songs.beatleader.com/${hash}.mp3` : `https://eu.cdn.beatsaver.com/${hash.toLowerCase()}.mp3`;
|
|
|
|
if (hash !== state.currentHash) {
|
|
cleanup();
|
|
currentTimeStore.set(0);
|
|
audio = new Audio(url);
|
|
audio.volume = state.volume;
|
|
audio.addEventListener('timeupdate', handleTimeUpdate);
|
|
audio.addEventListener('loadedmetadata', handleMetadata);
|
|
audio.addEventListener('ended', handleEnded);
|
|
audio.addEventListener('pause', handleEnded);
|
|
} else if (!audio) {
|
|
audio = new Audio(url);
|
|
audio.volume = state.volume;
|
|
audio.addEventListener('timeupdate', handleTimeUpdate);
|
|
audio.addEventListener('loadedmetadata', handleMetadata);
|
|
audio.addEventListener('ended', handleEnded);
|
|
audio.addEventListener('pause', handleEnded);
|
|
}
|
|
|
|
if (isPlaying) {
|
|
audio?.play();
|
|
} else {
|
|
audio?.pause();
|
|
}
|
|
|
|
return {
|
|
...state,
|
|
currentHash: hash,
|
|
playing: isPlaying,
|
|
};
|
|
});
|
|
}
|
|
|
|
function setVolume(volume) {
|
|
update(state => {
|
|
if (audio) {
|
|
audio.volume = volume;
|
|
}
|
|
return {...state, volume};
|
|
});
|
|
}
|
|
|
|
const reset = () => {
|
|
cleanup();
|
|
set(DEFAULT_STATE);
|
|
};
|
|
|
|
songPlayerStore = {
|
|
subscribe,
|
|
togglePlay,
|
|
setVolume,
|
|
reset,
|
|
};
|
|
|
|
return songPlayerStore;
|
|
};
|