Tunesday is a tiny terminal app that helps your team pick a weekly music provider, collect everyone’s YouTube picks, and spit out a playlist.
Relaxed office ritual meets minimal CLI fun.
The tool evolved around our long-standing team tradition of celebrating Tunesdays in the development team @USP
We wish each other "a happy Tunesday", appreciate how wonderful it is to have music, and finally — typically at the end of our daily meeting — run this tool to determine who will provide today's soundtrack.
- Tu(n)esday-aware: refuses to run on non-Tuesdays... unless you insist.
- Fun little TUI: arrow keys to navigate, Enter to select, Esc/Ctrl-C to bail (it will still try to save).
- Paste any YouTube link (watch, youtu.be, shorts) — the tool will normalize the ID and fetch the title.
- Local-first: data is just a JSON file in your repo/home dir.
- Radio mode: stream tunesday tunes in your command line.
-
Build
- With Makefile:
make build - Or plain Go:
go build -o build/tunesday ./cmd/tunesday
- With Makefile:
-
Run
- Default: ./build/tunesday
- Force run on a day-that-shall-not-be-named: ./build/tunesday --force-tunesday
- Radio mode: ./build/tunesday --radio (plays tunes with live progress bar and history)
-
Keys inside the app
- ↑/↓ to move
- Enter to select
- Esc to go back/exit menu
- Ctrl-C to quit
-
Keys in Radio Mode
- Space: Pause/Resume playback
- ←/→: Previous/Next tune
- ↑/↓: Volume Up/Down
- Esc: Quit to menu
- Ctrl-C: Quit application
- Select today's tune provider: choose who's on deck, paste a YouTube link, it will grab the title.
- Manually add a tune to list: type it in old-school.
- Get complete list of tunes: list for bragging rights.
- Manage Tunesday participants: add/remove/disable/enable members.
- Get youtube playlist link: a sharable link that bundles the IDs you've collected.
- Exit: The tool will save on the way out. Promise.
Tunesday picks today's provider using weighted random: people with fewer tunes get higher chance!
Formula: weight = 1.0 + max(0, average - personTunes)
Penalty: Last submitter gets -90% weight (avoids consecutive picks)
You'll see:
Alice [█░░░░░░░░░] (1.0)
▶ Bob [██████████] (3.0) ← 3x more likely!
Charlie [█░░░░░░░░░] (1.0)
Over time, everyone provides roughly equal tunes! 🎵
- Start radio mode:
./build/tunesday --radio - Choose from:
- Play all tunes (shuffled): Randomizes playlist order
- Play all tunes (in order): Plays in original order
- Select a tune to play: Pick a specific track
- Browse by provider: Filter tunes by who added them
To use the --radio flag, install these dependencies:
- mpv: Terminal media player
- https://github.com/mpv-player/mpv
- Ubuntu/Debian:
sudo apt install mpv - macOS:
brew install mpv
- yt-dlp: YouTube stream extractor (optional, mpv may use it internally)
- https://github.com/yt-dlp/yt-dlp
- Ubuntu/Debian:
pip install yt-dlp - macOS:
brew install yt-dlp
- Storage file: tunesday.json (in current working directory).
- Change location with env var:
- TUNESDAY_DATA_FILE=/path/to/wherever.json ./build/tunesday
- Example file:
example.tunesday.jsonis provided in the repo. Copy it to get started:cp example.tunesday.json tunesday.json
- Participants (with how many times they’ve provided tunes)
- The list of tunes (title, link, normalized YouTube ID, provider, timestamp)
- Not Tuesday? Then enforce it with
--force-tunesday. But don't abuse this! - Share your data with your team by pointing TUNESDAY_DATA_FILE at a repo file or syncing it somewhere.
- Does this sync to the cloud? No. It’s delightfully offline. However, you can simply sync the .json file somewhere you like... (and share it with your team)
- Will it lose my data if I mash Ctrl-C? It tries very hard to save before exiting.
- Can I use Vimeo/SoundCloud? Currently not, the happy path is YouTube.
- Accepts links like:
- Trims tracking bits (&si=... and friends) and keep it clean.
- Uses github.com/kkdai/youtube to fetch titles, thanks!! 🙏
- no API key needed for basic title lookup.
- Requirements: Go 1.23+
- Build:
make build - Test:
make testorgo test ./...
- cmd/tunesday: entrypoint
- internal/app: app loop and menu wiring
- internal/termui: tiny text UI helpers (menu, headers, etc.)
- internal/storage: JSON file store (atomic saves)
- internal/playlist: YouTube parsing + title fetcher
- internal/core: simple data structs
- See LICENSE. Be nice, share tunes.
