2024-04-21 21:00:45 +00:00
|
|
|
<svelte:options runes={true} />
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import {OpenSubsonic} from "$lib/opensubsonic";
|
|
|
|
import {onMount} from "svelte";
|
|
|
|
import QueueFrame from "$lib/components/custom/QueueFrame.svelte";
|
2024-04-21 21:39:56 +00:00
|
|
|
//import PlayerFrame from "$lib/components/custom/PlayerFrame.svelte";
|
|
|
|
import {Button} from "$lib/components/ui/button";
|
|
|
|
import {browser} from "$app/environment";
|
2024-04-21 21:00:45 +00:00
|
|
|
|
|
|
|
//let audioSource: HTMLAudioElement = $state(new Audio());
|
|
|
|
//let paused: boolean = $derived(audioSource.paused);
|
|
|
|
//let volume: number = $derived(audioSource.volume);
|
|
|
|
|
|
|
|
|
|
|
|
let source: HTMLAudioElement = $state();
|
2024-04-22 14:53:03 +00:00
|
|
|
let title = $state("");
|
2024-04-22 18:02:29 +00:00
|
|
|
let queueIndex = $state(0);
|
|
|
|
let currentSong = $state({
|
|
|
|
queueIndex
|
|
|
|
});
|
2024-04-21 21:39:56 +00:00
|
|
|
let isPaused = $state(true);
|
|
|
|
let volume = $state(0.2);
|
|
|
|
let progress = $state(0);
|
|
|
|
let duration = $state(0);
|
2024-04-21 21:00:45 +00:00
|
|
|
|
|
|
|
let queue: Array<unknown> = $state([]);
|
|
|
|
|
|
|
|
async function fetchQueue() {
|
|
|
|
const data = await OpenSubsonic.get("getPlayQueue");
|
|
|
|
if (data) {
|
|
|
|
queue = [];
|
|
|
|
queue = queue.concat(data.playQueue.entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 14:53:03 +00:00
|
|
|
async function fetchNowPlaying() {
|
|
|
|
const data = await OpenSubsonic.get("getNowPlaying");
|
|
|
|
let foundInNowPlaying = false;
|
|
|
|
if (data && data.nowPlaying.entry) {
|
|
|
|
data.nowPlaying.entry.forEach((entry) => {
|
|
|
|
if (entry.username == OpenSubsonic.username) {
|
|
|
|
title = entry.title;
|
|
|
|
newSong(entry);
|
|
|
|
foundInNowPlaying = true;
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (!foundInNowPlaying && queue.length != 0) {
|
|
|
|
newSong(queue[0])
|
2024-04-22 18:02:29 +00:00
|
|
|
currentSong.queueIndex = 0;
|
2024-04-22 14:53:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-21 21:00:45 +00:00
|
|
|
async function saveQueue() {
|
|
|
|
let songs = [];
|
|
|
|
|
|
|
|
queue.forEach((song, idx) => {
|
|
|
|
if (idx === 0) {
|
|
|
|
songs.push({parameter: "current", value: song.id})
|
|
|
|
songs.push({parameter: "id", value: song.id})
|
|
|
|
// Add Progress within current song
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
songs.push({parameter: "id", value: song.id})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
const data = await OpenSubsonic.get("savePlayQueue", songs);
|
|
|
|
if (data) {
|
|
|
|
await fetchQueue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function removeSongFromQueue(idx: number) {
|
|
|
|
if (idx > -1) {
|
|
|
|
queue.splice(idx, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-22 14:50:48 +00:00
|
|
|
function playSong(song: unknown, songIndex: number) {
|
|
|
|
//const chosenSong = queue[songIndex];
|
|
|
|
pause();
|
|
|
|
newSong(song);
|
2024-04-22 18:02:29 +00:00
|
|
|
currentSong.queueIndex = songIndex;
|
2024-04-22 14:50:48 +00:00
|
|
|
play();
|
|
|
|
}
|
|
|
|
|
|
|
|
function newSong(song: number) {
|
2024-04-21 21:00:45 +00:00
|
|
|
let parameters = [
|
2024-04-22 14:50:48 +00:00
|
|
|
{ parameter: "id", value: song.id },
|
2024-04-21 21:00:45 +00:00
|
|
|
//{ parameter: "maxBitRate", value: } // TODO
|
|
|
|
//{ parameter: "format", value: } // TODO
|
|
|
|
//{ parameter: "timeOffset", value: } // TODO? Only Video related
|
|
|
|
//{ parameter: "size", value: } // TODO? Only Video related
|
|
|
|
{ parameter: "estimateContentLength", value: "true" },
|
|
|
|
//{ parameter: "converted", value: } // TODO? Only Video related
|
|
|
|
];
|
|
|
|
let url = OpenSubsonic.getApiUrl("stream", parameters);
|
2024-04-21 21:39:56 +00:00
|
|
|
source = new Audio(url); // Assign new URL
|
|
|
|
|
|
|
|
// Reassign Event Handlers
|
|
|
|
source.onloadedmetadata = () => {
|
|
|
|
duration = source.duration;
|
|
|
|
};
|
|
|
|
|
|
|
|
source.onplay = () => {
|
|
|
|
source.volume = volume;
|
|
|
|
isPaused = source.paused;
|
|
|
|
}
|
|
|
|
|
|
|
|
source.onpause = () => {
|
|
|
|
isPaused = source.paused;
|
|
|
|
}
|
|
|
|
|
|
|
|
source.ontimeupdate = () => {
|
|
|
|
progress = source.currentTime;
|
|
|
|
}
|
2024-04-22 14:50:48 +00:00
|
|
|
|
|
|
|
source.load();
|
2024-04-21 21:39:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function play() {
|
|
|
|
source.play().catch(() => {});
|
2024-04-21 21:00:45 +00:00
|
|
|
}
|
2024-04-21 21:39:56 +00:00
|
|
|
function pause() {
|
2024-04-21 21:00:45 +00:00
|
|
|
source.pause();
|
|
|
|
}
|
|
|
|
|
2024-04-21 21:39:56 +00:00
|
|
|
$effect(() => {
|
|
|
|
if (source) {
|
|
|
|
source.volume = volume;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
function progressPercent() {
|
|
|
|
return progress / duration * 100 || 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function displayTime(rawSeconds: number) {
|
|
|
|
const intSeconds = rawSeconds.toFixed(0);
|
|
|
|
const seconds = intSeconds % 60;
|
|
|
|
const minutes = (intSeconds / 60).toFixed(0) % 60;
|
|
|
|
const hours = (intSeconds / 360).toFixed(0);
|
|
|
|
|
|
|
|
if (hours == 0) {
|
|
|
|
return `${minutes.toString()}:${seconds.toString().padStart(2, 0)}`
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return `${hours}:${minutes.toString().padStart(2, 0)}:${seconds.toString().padStart(2, 0)}`
|
|
|
|
}
|
2024-04-21 21:00:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onMount(() => {
|
2024-04-22 14:53:03 +00:00
|
|
|
fetchQueue().then(() => {
|
|
|
|
fetchNowPlaying();
|
|
|
|
});
|
2024-04-21 21:00:45 +00:00
|
|
|
source = new Audio();
|
|
|
|
})
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<div class="border border-2 flex-1 grid grid-cols-5">
|
|
|
|
<div class="border border-2 col-span-1">
|
|
|
|
<h1>Left Sidebar</h1>
|
|
|
|
</div>
|
|
|
|
<div class="border border-2 col-span-3">
|
|
|
|
<h1>Center</h1>
|
2024-04-21 21:39:56 +00:00
|
|
|
<button onclick={() => volume += 0.1}>Louder</button>
|
|
|
|
<button onclick={() => volume -= 0.1}>Quieter</button>
|
2024-04-21 21:00:45 +00:00
|
|
|
</div>
|
2024-04-22 18:02:29 +00:00
|
|
|
<QueueFrame {queue} {fetchQueue} {saveQueue} {removeSongFromQueue} {playSong} currentIndex={currentSong.queueIndex} />
|
2024-04-21 21:00:45 +00:00
|
|
|
</div>
|
|
|
|
<div class="border border-2 min-h-24 h-24">
|
2024-04-21 21:39:56 +00:00
|
|
|
<div class="flex flex-row gap-2">
|
2024-04-22 14:53:03 +00:00
|
|
|
<p class="border p-2">Song: {title}</p>
|
2024-04-21 21:39:56 +00:00
|
|
|
<p class="border p-2">Volume: {volume}</p>
|
|
|
|
<p class="border p-2">{displayTime(progress)}/{displayTime(duration)}</p>
|
|
|
|
<p class="border p-2">{progressPercent().toFixed(2)}%</p>
|
|
|
|
{#if isPaused}
|
|
|
|
<Button onclick={play}>Play</Button>
|
|
|
|
{:else}
|
|
|
|
<Button onclick={pause}>Pause</Button>
|
|
|
|
{/if}
|
|
|
|
</div>
|
2024-04-21 21:00:45 +00:00
|
|
|
</div>
|
|
|
|
|