A daily homepage of album suggestions, seeded from your Spotify playlists.
Every day, a cron job picks a handful of artists you already follow (via a configured playlist) and features one random album from each on the homepage. Click through to open in Spotify. Not feeling it? Hit the trash icon on any card to permanently dismiss that artist — none of their albums will be suggested again.
Originally extracted from hartreeworks.org; see the backstory at wow.pjh.is/journal/vibe-spotify.
- Weekly: a cron sweeps your configured Spotify playlist(s) and adds any new artists to
spotify_artists. - Daily: a cron picks ~9 random non-dismissed artists, fetches a random album from each, and writes rows to
spotify_featured_albumsfor that date. - Homepage reads the featured albums for today (falling back to the most recent day if today is empty) and renders them as a grid.
- Dismiss writes
dismissed_aton the artist row; future runs skip them.
- Next.js 15 (App Router) on Vercel
- Supabase (Postgres + RLS)
- Spotify Web API (refresh-token auth)
- Create an app at https://developer.spotify.com/dashboard.
- Under Redirect URIs, add
https://YOUR-DOMAIN/api/spotify-auth(andhttp://localhost:3000/api/spotify-authfor local use). - Note the Client ID and Client Secret.
- Create a project at https://supabase.com.
- In the SQL editor, run
supabase/schema.sql. - From Project Settings → API, copy:
- Project URL →
NEXT_PUBLIC_SUPABASE_URL anonpublic key →NEXT_PUBLIC_SUPABASE_ANON_KEYservice_rolekey →SUPABASE_SERVICE_ROLE_KEY
- Project URL →
Copy .env.example to .env.local (or set them in Vercel). Fill in the Supabase and Spotify credentials, then generate secrets:
# Shared secret for cron requests
openssl rand -hex 32 # → CRON_SECRET
# One-time gate for the OAuth setup route
openssl rand -hex 32 # → SETUP_SECRETSet SPOTIFY_PLAYLIST_ID to a single playlist, or SPOTIFY_PLAYLIST_IDS to a comma-separated list. The playlist must be owned by the Spotify account you authenticate as.
With SETUP_SECRET set, visit:
https://YOUR-DOMAIN/api/spotify-auth?secret=YOUR_SETUP_SECRET
(Or http://localhost:3000/api/spotify-auth?secret=... locally.) You'll be redirected to Spotify to authorise, then back to a JSON page containing your refresh_token.
- Copy the
refresh_tokenintoSPOTIFY_REFRESH_TOKEN. - Redeploy (or restart
yarn dev). - Unset
SETUP_SECRET— the setup route will then return 403 and stay disabled.
Trigger the two cron endpoints manually once:
curl -H "Authorization: Bearer $CRON_SECRET" \
https://YOUR-DOMAIN/api/cron/spotify-sync-artists
curl -H "Authorization: Bearer $CRON_SECRET" \
https://YOUR-DOMAIN/api/cron/spotify-feature-albumsThe first populates spotify_artists from your playlist(s); the second picks today's featured albums. Open / and you should see them.
vercel.json already schedules:
/api/cron/spotify-sync-artists— weekly, Sundays 02:00 UTC/api/cron/spotify-feature-albums— daily at 03:00 UTC
Vercel automatically attaches the Authorization: Bearer $CRON_SECRET header on scheduled calls.
yarn install
yarn devOpen http://localhost:3000.
In dev, the spotify-feature-albums endpoint doesn't require the bearer token, so you can just open http://localhost:3000/api/cron/spotify-feature-albums in a browser to regenerate today's picks.
app/
page.tsx # "Today's records" homepage
RecordsGrid.tsx # Client grid + dismiss dialog
api/
records/dismiss/route.ts # POST — mark an artist dismissed
spotify-auth/route.ts # One-time OAuth setup (SETUP_SECRET gated)
cron/
spotify-sync-artists/route.ts # Weekly — pull artists from playlists
spotify-feature-albums/route.ts # Daily — pick random albums
components/ui/ # shadcn/ui primitives
lib/
spotify-auth.ts # Spotify token exchange + authed fetch
supabase/{server,service}.ts # Supabase clients
supabase/schema.sql # Database schema
Two env vars adjust the daily selection:
MAX_ALBUMS_PER_DAY(default9) — how many albums to feature per dayMAX_CLASSICAL_PER_DAY(default1) — cap on classical artists per day (classical = matched by genre keywords: orchestra, symphony, baroque, opera, etc.)
MIT. See LICENSE.