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 = ref(null); const station: Ref = ref(null); const playing: Ref = ref(false); const instance: Ref = ref(null); const songInfo: Ref = ref(null); const updateTimer: Ref = 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 | 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 | 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 }; });