/* * sophies.rocks * * Copyright (C) 2026 Zofia Szweda * * This file is part of sophies.rocks. * * sophies.rocks is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * sophies.rocks is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with sophies.rocks. If not, see . */ const LIBREFM_USER = "sophii.xyz"; const LIBREFM_API_KEY = "00000000000000000000000000000000"; const LIBREFM_CACHE_KEY = "scrobbles-cache"; const LIBREFM_CACHE_TTL_MS = 60_000; async function loadScrobbles(limit = 7) { const cached = localStorage.getItem(LIBREFM_CACHE_KEY); if (cached) { const { data, ts } = JSON.parse(cached); if (Date.now() - ts < LIBREFM_CACHE_TTL_MS) return data; } const url = `https://libre.fm/2.0/?method=user.getrecenttracks&user=${LIBREFM_USER}&api_key=${LIBREFM_API_KEY}&format=json&limit=${limit}`; const res = await fetch(url); if (!res.ok) throw new Error("Could not fetch scrobbles"); const data = await res.json(); const tracks = data.recenttracks?.track ?? []; localStorage.setItem(LIBREFM_CACHE_KEY, JSON.stringify({ data: tracks, ts: Date.now() })); return tracks; } async function renderScrobbles() { const list = document.querySelector("#recent-scrobbles ul"); try { const tracks = await loadScrobbles(); if (tracks.length === 0) { list.innerHTML = "
  • No scrobbles yet.
  • "; return; } list.innerHTML = ""; tracks.forEach((track) => { const li = document.createElement("li"); const artist = track.artist?.["#text"] ?? ""; const nowPlaying = track["@attr"]?.nowplaying === "true"; li.innerHTML = ` ${track.name}
    ${artist}${nowPlaying ? " - listening now" : ""}
    `; list.appendChild(li); }); } catch (err) { console.error("Failed to load libre.fm scrobbles:", err); list.innerHTML = "
  • Couldn't load scrobbles right now.
  • "; } } renderScrobbles();