125 lines
3.4 KiB
TypeScript

import { defineStore } from "pinia";
import { ref, type Ref } from "vue";
import { useRoute } from "vue-router";
import axios, { CancelToken } from "axios";
import { api } from "@";
type TimerId = number;
const setAsyncTimeout = (ms: number) => {
return new Promise((resolve) => {
setTimeout(resolve, ms * 1000);
});
};
export const usePlayer = defineStore("player", () => {
const stations: Ref<api.StationInfo[]> = ref(null);
const station: Ref<api.StationInfo> = ref(null);
const playing: Ref<boolean> = ref(false);
const instance: Ref<HTMLAudioElement> = ref(null);
const songInfo: Ref<api.SongInfo> = ref(null);
const updateTimer: Ref<TimerId> = ref(null);
const create = () => {
let audio: HTMLAudioElement = new Audio();
audio.id = "audioPlayer";
audio.className = "hidden";
audio.preload = "auto";
audio.onplay = async () => {
playing.value = true;
await update();
};
audio.onpause = () => {
playing.value = false;
clearTimeout(updateTimer.value);
};
document.body.appendChild(audio);
instance.value = audio;
};
const update = async () => {
if (station.value.status !== api.StationStatus.Receive) {
songInfo.value = null;
return;
}
await refreshSongInfo();
clearTimeout(updateTimer.value);
if (songInfo.value.duration) {
updateTimer.value = await setAsyncTimeout(songInfo.value.duration - songInfo.value.elapsed);
} else {
updateTimer.value = await setAsyncTimeout(5);
}
if (playing.value) {
await update();
}
};
const play = (_station: api.StationInfo | null = null) => {
if (_station) {
station.value = _station;
instance.value.src = _station.url;
}
if (!instance.value.src){
return;
}
instance.value.load();
instance.value.play();
};
const pause = () => {
if (!instance.value.src) {
return;
}
instance.value.pause();
};
const toggle = () => {
if (playing.value) {
pause();
} else {
play();
}
};
const volume = (value: number) => {
instance.value.volume = Math.min(Math.max(value * 0.01, 0), 1);
};
const volumeEvent = (event: Event) => {
volume(event.target.value);
};
const refreshStations = async (error: Ref<object | null> | null = null) => {
await api.stationsInfo({ throwOnError: true })
.then(async res => {
stations.value = res.data;
})
.catch(err => {
if (error) {
error.value = "Failed to retrieve stations";
}
});
};
const refreshSongInfo = async (error: Ref<object | null> | null = null) => {
await api.songStatus ({ body: { id: station.value.id }, throwOnError: true })
.then(async res => {
songInfo.value = res.data;
})
.catch(err => {
songInfo.value = null;
if (error) {
error.value = "Failed to retrieve song info";
}
});
};
return { stations, station, playing, create, play, pause, toggle, volume, volumeEvent, songInfo, refreshStations, refreshSongInfo };
});