125 lines
3.4 KiB
TypeScript
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 };
|
|
});
|