feat(index): add last played music via maloja
All checks were successful
build dist / build-dist (push) Successful in 29s

This commit is contained in:
z0x 2025-04-18 22:47:20 -04:00
parent 70dc2d08a6
commit 41d2c7cbac
6 changed files with 99 additions and 5 deletions

View file

@ -0,0 +1,8 @@
<div
id="last-track-widget"
class="motion-music opacity-0 flex flex-col absolute top-0 left-0 m-8"
>
<p>Loading music data...</p>
</div>
<script src="/src/js/music.ts"></script>

View file

@ -1,7 +1,7 @@
import { animate, stagger } from "motion";
const elements = document.querySelectorAll(
".motion-links, .motion-logo, .motion-text, .motion-footer",
".motion-links, .motion-logo, .motion-text, .motion-music, .motion-footer",
);
animate(
@ -20,9 +20,10 @@ document.addEventListener("keydown", ({ key }: KeyboardEvent) => {
m: "a.matrix",
};
const link = document.querySelector(
shortcuts[key.toLowerCase()] || "",
) as HTMLAnchorElement | null;
const selector = shortcuts[key.toLowerCase()];
if (!selector) return;
const link = document.querySelector(selector) as HTMLAnchorElement | null;
if (!link?.href) return;
const a = Object.assign(document.createElement("a"), {

77
src/js/music.ts Normal file
View file

@ -0,0 +1,77 @@
interface Track {
artists: string[];
title: string;
album: { albumtitle: string };
}
interface Scrobble {
time: number;
track: Track;
}
async function fetchAndDisplayLastTrack() {
const container = document.getElementById("last-track-widget");
if (!container) {
console.error("Container element not found!");
return;
}
try {
let res: Response;
try {
res = await fetch("https://z0x.ca/music");
if (!res.ok) throw new Error("WAN fetch failed");
} catch (e) {
res = await fetch("https://z0x.home.arpa/music");
}
if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`);
}
const data: { status: string; list: Scrobble[] } = await res.json();
let lastTrack: Track | null = null;
if (data?.status === "ok" && data.list?.length) {
lastTrack = data.list.sort(
(a: Scrobble, b: Scrobble) => b.time - a.time,
)[0].track;
}
if (lastTrack) {
container.innerHTML = `
<span class="mb-2 flex gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 10v3"/><path d="M6 6v11"/><path d="M10 3v18"/><path d="M14 8v7"/><path d="M18 5v13"/><path d="M22 10v3"/></svg>
<span class="text-sm text-primary">
Last played..
</span>
</span>
<span class="text-md mb-2 font-bold leading-none">
${lastTrack.title}
</span>
<span class="text-xs text-muted-foreground">
<span class="font-semibold text-secondary-foreground">
by
</span>
${lastTrack.artists[0]}
</span>
<span class="text-xs text-muted-foreground">
<span class="font-semibold text-secondary-foreground">
on
</span>
${lastTrack.album.albumtitle}
</span>
`;
} else {
container.innerHTML = "<p>No tracks found.</p>";
}
} catch (e) {
console.error("Fetch error:", e);
container.innerHTML = "<p>Error loading tracks.</p>";
} finally {
container.classList.remove("opacity-0");
container.classList.add("opacity-100");
}
}
fetchAndDisplayLastTrack();

View file

@ -1,6 +1,7 @@
---
import Links from "@/components/Links.astro";
import Logo from "@/components/Logo.astro";
import Music from "@/components/Music.astro";
import Text from "@/components/Text.astro";
import Layout from "@/layouts/Layout.astro";
---
@ -9,4 +10,5 @@ import Layout from "@/layouts/Layout.astro";
<Text text="z0x"/>
<Logo />
<Links />
<Music />
</Layout>