Unified artist portfolio for Poolpat — live play stats, full discography, and liner notes across SoundCloud, Spotify, and Apple Music.
Live site: thepoolpat.github.io/poolpat-portfolio
| Route | Description |
|---|---|
/ |
Home — hero carousel, live stats summary, platform links |
/stats/ |
Play count trends (Chart.js), per-platform breakdowns, top tracks |
/discography/ |
Release card grid with artwork, chart badges |
/releases/[slug]/ |
Per-release liner notes, track listings, Apple Music CTAs |
pipeline/fetch_plays.py) — fetches SoundCloud, Spotify, Apple Music daily via GitHub Actionspackages/affiliate-helper/js/ — validated Apple Music URLs with campaign tracking├── .github/workflows/
│ ├── deploy.yml # Build Astro → deploy to GitHub Pages
│ └── fetch-plays.yml # Daily Python pipeline (cron 07:15 UTC)
├── packages/affiliate-helper/ # Apple Music affiliate link builder (JS)
├── pipeline/
│ ├── fetch_plays.py # Multi-platform play count scraper
│ ├── spotify_auth.py # Spotify PKCE OAuth flow
│ ├── spotify_client.py # Spotify API client (typed, with retry)
│ ├── spotify_errors.py # Typed error hierarchy
│ ├── requirements.txt
│ └── tests/ # 20 unit tests
├── examples/ # Runnable Spotify demos
├── data/ # Auto-committed by pipeline
│ ├── plays.json # Latest play count snapshot
│ ├── history.csv # Time-series (appended daily)
│ └── rss_tracks.json # SoundCloud catalog
├── public/artwork/ # Release cover images (1200px, web-optimized)
└── src/
├── data/releases.json # Hand-maintained release catalog (7 releases)
├── layouts/Base.astro # HTML shell, SEO, a11y
├── components/ # Astro components
├── pages/ # Route pages
└── styles/global.css # Unified design tokens
Launched: 2026-04-27
Pipeline: pipeline/spotify_discord_analytics.py (313 lines, fully documented)
Real-time monitoring with Discord remote control:
!play, !pause, !statusplayback_history, sessions, daily_stats, device_log# 1. Run the pipeline (logs start immediately)
cd ~/poolpat-portfolio/pipeline
python3 spotify_discord_analytics.py
# Press Enter to start logging (15s polling)
# Press 'q' to quit and see 7-day stats
# Press 'h' for help
Add your webhook to .env.discord:
echo "DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/..." > .env.discord
Commands sent to Discord webhook:
!play <track> — Play track/artist/playlist!pause — Pause current playback!next — Skip to next!status — Show current track info!stats [days] — Show analytics (default: 7 days)!devices — List available playback devicesFile: pipeline/spotify_discord_analytics.py
poll_playback() — Fetches current state from Spotify APIlog_playback() — Logs to SQLite and sends Discord webhookget_playback_stats(days) — Query analytics: top artists, tracks_send_discord() — Sends formatted playback notifications.env.spotify (auto-generated by hermes auth spotify)
SPOTIFY_CLIENT_ID=88d1cb87aba74f809133542879d8885c
SPOTIFY_REDIRECT_URI=http://127.0.0.1:8888/callback
SPOTIFY_SCOPES=user-read-playback-state,user-library-read,...
SPOTIFY_REFRESH_TOKEN=***
config/camoufox_spotify.json
{
"camoufox": {
"enabled": true,
"base_url": "http://127.0.0.1:8888",
"spotify_integration": {
"client_id": "88d1cb87aba74f809133542879d8885c",
"auto_refresh": true,
"device_poll_interval_ms": 5000
}
}
}
Continuous logging (marathon mode):
cd ~/poolpat-portfolio/pipeline
python3 spotify_discord_analytics.py
# Press Enter → starts logging
# Logs 300+ tracks across multi-hour sessions
# Each track auto-syncs to Discord webhook
Batch analytics (finite mode):
python3 spotify_enhanced_analytics.py --iterations 50
# Polls 50× at 3-5s intervals → auto-exits
# Event log exported to CSV/JSON at end
One-off query:
python3 -c "
from pipeline.spotify_discord_analytics import SpotifyDiscordAnalytics
a = SpotifyDiscordAnalytics()
stats = a.get_playback_stats(days=7)
print(f'Top: {stats[\"top_track\"]} by {stats[\"top_track_artist\"]}')
"
Play data never decreases:
playback_historyMAX()ws://localhost:64895/.../Users/mortymcfly/.cache/spotify_oauth# Install dependencies
npm install
pip3 install -r pipeline/requirements.txt
# Development server
npm run dev
# Production build (public GitHub Pages)
DEPLOY_TARGET=public npm run build
# TypeScript check
npm run check
http://127.0.0.1:8888/callback python3 pipeline/spotify_auth.py
# Enter your Client ID when prompted
# Authorize in browser → get refresh token
SPOTIFY_CLIENT_IDSPOTIFY_CLIENT_SECRETSPOTIFY_REFRESH_TOKEN# Create .env (not committed)
cp pipeline/.env.example .env
# Fill in your credentials, then:
set -a && source .env && set +a
python3 pipeline/fetch_plays.py
Note: Use
set -abeforesource .envto export the variables. Plainsource .envsets them but doesn’t export to subprocesses.
The Python fetcher runs daily at 07:15 UTC via GitHub Actions:
data/ files to main → triggers site rebuild| Secret | Purpose |
|---|---|
SPOTIFY_CLIENT_ID |
Spotify API access |
SPOTIFY_CLIENT_SECRET |
Spotify API access |
SPOTIFY_REFRESH_TOKEN |
User-scoped Spotify data (PKCE) |
CAMOUXF_HOME |
Camoufox cache directory (local-first mode) |
APPLE_MUSIC_TOKEN |
Apple Music API access (optional — requires paid Developer Program) |
total_streams and monthly_listeners are preserved from manual entry (Spotify for Artists). The API provides popularity scores and top tracks.Every Apple Music link is built through the validated link() helper (packages/affiliate-helper/js/):
web-portfolio-{slug}-{placement}This repo unifies two earlier projects:
| Project | What it contributed |
|---|---|
| poolpat-plays | Data pipeline, GitHub Actions workflow, play count data |
| Integrations | Camoufox-Spotify local-first data feed with monotonic streaming invariant |
~/spotty_logs/logs.db