diff --git a/src/app.pcss b/src/app.pcss index fca8ba5..42b58ef 100644 --- a/src/app.pcss +++ b/src/app.pcss @@ -50,6 +50,18 @@ } @layer base { + h1 { + @apply text-2xl; + @apply font-bold; + } + h2 { + @apply text-xl; + @apply font-bold; + } + h3 { + @apply text-lg; + @apply font-bold; + } * { @apply border-border; } diff --git a/src/lib/AudioState.svelte.ts b/src/lib/AudioState.svelte.ts new file mode 100644 index 0000000..ffcf914 --- /dev/null +++ b/src/lib/AudioState.svelte.ts @@ -0,0 +1 @@ +export let audioStore: HTMLAudioElement = $state(new Audio()); diff --git a/src/lib/components/custom/LoadingSpinner.svelte b/src/lib/components/custom/LoadingSpinner.svelte new file mode 100644 index 0000000..08c9aba --- /dev/null +++ b/src/lib/components/custom/LoadingSpinner.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/src/lib/components/custom/PlayerFrame.svelte b/src/lib/components/custom/PlayerFrame.svelte new file mode 100644 index 0000000..ef40d6b --- /dev/null +++ b/src/lib/components/custom/PlayerFrame.svelte @@ -0,0 +1,29 @@ + + + + +
+ {#if mounted} +

Paused: {audio.paused}

+

Volume: {audio.volume}

+

Duration: {audio.duration}

+ {#if audio.paused} + + {:else} + + {/if} + {:else} +

Nothing going on here

+ {/if} +
diff --git a/src/lib/components/custom/QueueFrame.svelte b/src/lib/components/custom/QueueFrame.svelte new file mode 100644 index 0000000..7d0fc77 --- /dev/null +++ b/src/lib/components/custom/QueueFrame.svelte @@ -0,0 +1,47 @@ + + + + +{#snippet playerQueue()} + {#each queue as song, idx} +

playSong(idx)}>{song.artist} - {song.title} ({timeFormat(song.duration)})

+ {/each} + + +{/snippet} + +
+
+

Current Queue

+
+ + +
+ + {#if loading} +
+
+

Fetching Play Queue

+ +
+ {@render playerQueue()} +
+ {:else} + {@render playerQueue()} + {/if} +
\ No newline at end of file diff --git a/src/lib/opensubsonic.ts b/src/lib/opensubsonic.ts index 5d0d421..b2c481a 100644 --- a/src/lib/opensubsonic.ts +++ b/src/lib/opensubsonic.ts @@ -6,13 +6,40 @@ export module OpenSubsonic { export let password = ""; let token = ""; let salt = ""; - export let base = "https://navidrome.neshweb.net"; + export let base = "https://music.neshweb.net"; const apiVer = "1.16.1"; // Version supported by Navidrome. Variable for easier updating const clientName = "Lytter"; - export function getApiPath(path: string) { + export async function get(path: string, parameters: {parameter: string, value: string}[] = []) { + const apiPath = getApiUrl(path, parameters); + const res = (await fetch(apiPath)); + if (res.ok) { + switch (res.headers.get("content-type")) { + case("application/json"): { + return (await res.json())["subsonic-response"]; + } + case("audio/mp4"): { + return res; + } + } + } + else { + return false; + } + } + + export function getApiUrl(path: string, parameters: {parameter: string, value: string}[] = []) { + let apiPath = generateBasePath(path); + parameters.forEach(({parameter, value}) => { + apiPath = apiPath + `&${parameter}=${value}`; + }) + + return apiPath; + } + + const generateBasePath = (path: string) => { if (username === "") { - let cookie = Cookies.get("subsonicUsername"); + const cookie = Cookies.get("subsonicUsername"); if (typeof cookie !== "undefined") { username = cookie; } @@ -34,13 +61,13 @@ export module OpenSubsonic { return `${base}/rest/${path}?u=${username}&s=${salt}&t=${token}&v=${apiVer}&c=${clientName}&f=json`; } - function generateToken() { + const generateToken = () => { salt = "staticfornow"; token = Md5.hashStr(password + salt); } export function storeCredentials() { - let options = { + const options = { expires: 7, path: "/", sameSite: "strict", diff --git a/src/lib/time-format.ts b/src/lib/time-format.ts new file mode 100644 index 0000000..81193e4 --- /dev/null +++ b/src/lib/time-format.ts @@ -0,0 +1,7 @@ +export function timeFormat(time: number) { + const minutes = (time / 60).toFixed(0).toString(); + const seconds = time % 60; + const secondsString = (seconds < 10) ? '0' + seconds.toString() : seconds.toString() + + return minutes + ":" + secondsString; +} \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 351ee4a..487590e 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,4 +2,9 @@ import "../app.pcss"; - \ No newline at end of file +
+
+

Navbar

+
+ +
\ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 5982b0a..993c4b4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,2 +1,159 @@ -

Welcome to SvelteKit

-

Visit kit.svelte.dev to read the documentation

+ + + + +
+
+

Left Sidebar

+
+
+

Center

+ + + {#if typeof audio !== "undefined"} +

{audio.currentTime}

+ {/if} +
+ +
+
+ {#if typeof audio !== "undefined"} + + {/if} +
+ diff --git a/src/routes/login/login-form.svelte b/src/routes/login/login-form.svelte index 634c4f6..c2bcc5a 100644 --- a/src/routes/login/login-form.svelte +++ b/src/routes/login/login-form.svelte @@ -11,10 +11,9 @@ superForm, } from "sveltekit-superforms"; import { zodClient } from "sveltekit-superforms/adapters"; - import {Circle2} from "svelte-loading-spinners"; - import {Md5} from "ts-md5"; import Cookies from 'js-cookie' import {goto} from "$app/navigation"; + import LoadingSpinner from "$lib/components/custom/LoadingSpinner.svelte"; let { data }: SuperValidated> = $props<{ data: SuperValidated> }>(); @@ -23,15 +22,19 @@ onUpdated() { OpenSubsonic.username = previousForm.get("username"); OpenSubsonic.password = previousForm.get("password"); - let path = OpenSubsonic.getApiPath("ping"); - fetch(path).then(async (data) => { - let res = (await data.json())["subsonic-response"]; - if (res.status === "ok") { - OpenSubsonic.storeCredentials(); - loading = false; - let route = Cookies.get("preLoginRoute") - Cookies.remove("preLoginRoute", { path: "/login" }) - goto(route); + OpenSubsonic.get("ping").then((data) => { + if (data) { + if (data.status === "ok") { + OpenSubsonic.storeCredentials(); + loading = false; + let route = Cookies.get("preLoginRoute") + Cookies.remove("preLoginRoute", { path: "/login" }) + goto(route); + } + else { + error = true; + loading = false; + } } else { error = true; @@ -69,12 +72,7 @@
{#if loading} - + {:else} Login {/if} diff --git a/yarn.lock b/yarn.lock index eff9575..c844edb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2186,7 +2186,7 @@ svelte-preprocess@^5.1.3: sorcery "^0.11.0" strip-indent "^3.0.0" -svelte@^5.0.0-next: +svelte@^5.0.0-next.110: version "5.0.0-next.110" resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.0.0-next.110.tgz#90ccb7500fc257b21f311f28bd82110585c2f58c" integrity sha512-RDeoTJtI7HRx1VPROJ2qeibL14OPTQGmNrjM8Lug/N4hJXtolmA7USKggcHL3RXl1loS5Zb1R0IV7stfS7GhQg==