From ae41a4086611be8c7265f0f4b8083b11e9a3227b Mon Sep 17 00:00:00 2001 From: zoop Date: Thu, 10 Sep 2026 14:51:53 -0400 Subject: [PATCH] change scrobbling to last.fm --- .dev.vars.example | 15 +- public/badges/brgr.png | Bin 0 -> 6365 bytes src/components/Buttons.astro | 4 + src/components/Music.astro | 307 +++++++++++++--------------------- src/components/Stats.astro | 93 +--------- src/components/Webrings.astro | 2 +- src/data/site.ts | 1 + src/layouts/Base.astro | 2 +- src/pages/api/lastfm.json.ts | 149 +++++++++++++++++ src/pages/index.astro | 2 +- src/scripts/music.ts | 289 +++++++++++++++++++------------- src/styles/global.css | 115 ++++++++++++- 12 files changed, 574 insertions(+), 405 deletions(-) create mode 100644 public/badges/brgr.png create mode 100644 src/pages/api/lastfm.json.ts diff --git a/.dev.vars.example b/.dev.vars.example index 9afce7d..50a9f0b 100644 --- a/.dev.vars.example +++ b/.dev.vars.example @@ -6,12 +6,15 @@ ADMIN_PASSWORD= # 32+ random bytes, e.g. `openssl rand -hex 32` SESSION_SECRET= -# one-time: get a refresh token via the spotify authorization-code flow with -# scopes: user-read-currently-playing user-read-recently-played user-top-read -# without these the "now playing" / "on repeat" sections just stay hidden. -SPOTIFY_CLIENT_ID= -SPOTIFY_CLIENT_SECRET= -SPOTIFY_REFRESH_TOKEN= +# music widget — now playing + weekly scrobble stats from last.fm. reads a PUBLIC +# profile, so just a key (last.fm/api/account/create) + your username. no auth. +LASTFM_API_KEY= +LASTFM_USER= + +# (legacy) spotify — no longer used; the music widget is on last.fm now. +# SPOTIFY_CLIENT_ID= +# SPOTIFY_CLIENT_SECRET= +# SPOTIFY_REFRESH_TOKEN= # currently-reading widget — personal token from https://hardcover.app/account/api HARDCOVER_TOKEN= diff --git a/public/badges/brgr.png b/public/badges/brgr.png new file mode 100644 index 0000000000000000000000000000000000000000..59f42432481bd8a1e9868968cef257baa1b29d97 GIT binary patch literal 6365 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 literal 0 HcmV?d00001 diff --git a/src/components/Buttons.astro b/src/components/Buttons.astro index a171c25..891aecd 100644 --- a/src/components/Buttons.astro +++ b/src/components/Buttons.astro @@ -314,6 +314,10 @@ const badgeUrl = `https://${site.domain}/badges/zachy.gif`; z-index: 3; transform: translate(var(--x), calc(var(--y) - 5px)) rotate(0deg) scale(1.2); } + .badge:hover ~ .badge, + .badge:focus-visible ~ .badge { + transform: translate(var(--x), calc(var(--y) - 7px)) rotate(var(--t)); + } .badge:hover::before, .badge:focus-visible::before { top: 3px; diff --git a/src/components/Music.astro b/src/components/Music.astro index 7d251c6..a559fa1 100644 --- a/src/components/Music.astro +++ b/src/components/Music.astro @@ -22,7 +22,7 @@ import { Icon } from "astro-icon/components"; hidden /> -