poolpat-plays

poolpat-portfolio

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

Pages

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

Stack

Project Structure

├── .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

🎵 Camoufox + Discord Spotify Integration

Launched: 2026-04-27
Pipeline: pipeline/spotify_discord_analytics.py (313 lines, fully documented)

What It Does

Real-time monitoring with Discord remote control:

  1. Streaming playback tracking — polls Spotify every 15-30s via Web API
  2. Discord bot integration — control playback via !play, !pause, !status
  3. SQLite analytics DB — 4 tables: playback_history, sessions, daily_stats, device_log
  4. Auto token refresh — handles 401 errors gracefully
  5. 300+ track capability — marathon sessions with automatic pagination
  6. Camoufox enhanced — anti-detect browser for robust OAuth

Quick Start

# 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

Discord Remote Control

Add your webhook to .env.discord:

echo "DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/..." > .env.discord

Commands sent to Discord webhook:

Pipeline Features

File: pipeline/spotify_discord_analytics.py

Configuration Files

.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
     }
   }
}

Usage Examples

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\"]}')
"

Monotonic Invariant

Play data never decreases:

Camoufox Integration

Setup

# 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

Spotify Setup (one-time)

  1. Register an app at developer.spotify.com/dashboard
  2. Add redirect URI: http://127.0.0.1:8888/callback
  3. Run the auth flow:
     python3 pipeline/spotify_auth.py
     # Enter your Client ID when prompted
     # Authorize in browser → get refresh token
    
  4. Add secrets to GitHub Actions:
    • SPOTIFY_CLIENT_ID
    • SPOTIFY_CLIENT_SECRET
    • SPOTIFY_REFRESH_TOKEN

Running the Pipeline Locally

# 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 -a before source .env to export the variables. Plain source .env sets them but doesn’t export to subprocesses.

Data Pipeline

The Python fetcher runs daily at 07:15 UTC via GitHub Actions:

  1. Spotify (user-scoped): PKCE refresh token → top tracks (short/medium/long term), recently played
  2. Spotify (public): Client Credentials → catalog popularity scores (0-100)
  3. SoundCloud: RSS feed + v2 API → play counts, catalog metadata
  4. Apple Music: API or web scraping → track catalog (plays are manual entry)
  5. Camoufox integration: Local-first playback tracking with monotonic invariant
  6. Enforces a monotonic invariant — play counts never decrease between fetches
  7. Commits updated data/ files to main → triggers site rebuild

Required Secrets

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)

Platform Notes

Affiliate Attribution

Every Apple Music link is built through the validated link() helper (packages/affiliate-helper/js/):

Origin

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

Credits