- JavaScript 79.5%
- Python 12.3%
- HTML 5.1%
- CSS 3.1%
Track feature clicks, subscriptions, micro-transactions, top-ups, share receipt, and close app as Plausible custom events. Cache-bust style.css and app.js using Last-Modified headers from HEAD requests — no build step needed, caches break on file change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| public | ||
| tools | ||
| .gitignore | ||
| CLAUDE.md | ||
| README.md | ||
Pay2Play! — The Worst Music Player
A satirical music player where every interaction is paywalled. Pause? That's $0.01. Resume? Separate charge. Turn off repeat? That costs more than turning it on.
Part of donothireus.com.
Quick start
No build step, no package manager. Just serve the public/ directory:
cd public/
python3 -m http.server 8080
# open http://localhost:8080
Or with any other static file server (Caddy, nginx, etc).
Project structure
public/
├── index.html # HTML shell, CDN script tags, meta/OG tags
├── style.css # Animations, hover/focus states, range styling
├── app.js # All React components and logic (JSX via Babel)
└── audio/ # Drop MP3 files here for real music
├── songs.json # Generated by tools/probe-songs.py (gitignored)
└── .gitkeep
tools/
└── probe-songs.py # Probe audio files → songs.json
Deploying to donothireus.com
Just serve the public/ directory. If you're using Caddy
(which I know you are), something like:
donothireus.com {
root * /srv/donothireus/public
file_server
encode gzip
}
Or to put it at a subpath like /payplay:
donothireus.com {
handle /payplay/* {
root * /srv/donothireus/payplay/public
uri strip_prefix /payplay
file_server
}
}
Audio: procedural vs real music
By default the player uses Tone.js to generate procedural synth loops — no external audio files needed. This is funny on its own ("even the songs are cheaply made") but you can swap in real CC-licensed tracks.
Switching to self-hosted MP3s
- Download CC-BY licensed MP3s (see sources below)
- Put them in
public/audio/ - Run the probe tool to generate
songs.json:
./tools/probe-songs.py -d public/audio
# Writes public/audio/songs.json automatically
The app fetches audio/songs.json on startup. If it exists and
contains tracks, they replace the procedural builtins. If not,
the synth songs are used as a fallback.
The generated JSON looks like:
[
{
"title": "Sneaky Snitch",
"artist": "Kevin MacLeod",
"duration": 120,
"url": "/audio/sneaky-snitch.mp3",
"color": "#e74c3c"
}
]
Title and artist are extracted from ID3 tags when available, falling back to the filename. Duration comes from ffprobe.
You can also probe specific files or write to a custom path:
./tools/probe-songs.py public/audio/track1.mp3 public/audio/track2.mp3
./tools/probe-songs.py -o public/audio/songs.json *.mp3
Where to get CC-BY music
All of these are free to use with attribution (CC-BY or CC0):
Kevin MacLeod / Incompetech (CC-BY 4.0)
- https://incompetech.com/music/royalty-free/
- Thousands of tracks, well-known, easy to search by mood/genre
- Attribution: "Title" Kevin MacLeod (incompetech.com) Licensed under Creative Commons: By Attribution 4.0
- Also mirrored on archive.org: https://archive.org/details/Incompetech
Free Music Archive (various CC licenses — filter for CC-BY)
- https://freemusicarchive.org/
- Filter by license type, download MP3s directly
- Check each track's specific license
SampleSwap (CC-BY-NC-SA for most tracks)
- https://sampleswap.org/mp3/creative-commons/free-music.php
- 320kbps MP3s, various genres
Pixabay Music (Pixabay License — free, no attribution required)
- https://pixabay.com/music/
- No API key needed for downloads, but no hotlinking
Download and host workflow
# Example: grab a Kevin MacLeod track
cd public/audio/
wget -O sneaky-snitch.mp3 "https://incompetech.com/music/royalty-free/mp3-royaltyfree/Sneaky%20Snitch.mp3"
# Generate songs.json from all audio in the directory
cd ../..
./tools/probe-songs.py -d public/audio
Attribution
If using CC-BY music, add attribution. The fine print at the bottom of the player is a good place, or add a separate credits section. Kevin MacLeod's required format:
"Track Title" Kevin MacLeod (incompetech.com) Licensed under Creative Commons: By Attribution 4.0 https://creativecommons.org/licenses/by/4.0/
How it works
- React 18 loaded from CDN, JSX compiled by Babel standalone
- Tone.js for procedural synth audio (no build step needed)
- HTML5 Audio API for self-hosted MP3 playback
- Zero dependencies to install, zero build tools
- All state is client-side, nothing persisted
The starting wallet is randomized between $0.50 and $10.00 each page load. The +$10 button lets people keep exploring all the paywalls (with a $0.50 processing fee, naturally).
License
Do whatever you want with this. It's a joke.