Skip to content

Party mode: guests join with a code and add songs to the queue - #163

Merged
elcapitantommy merged 1 commit into
mainfrom
party-mode
Oct 19, 2026
Merged

elcapitantommy merged 1 commit into
mainfrom
party-mode

Conversation

@elcapitantommy

Copy link
Copy Markdown
Owner

Requested by Tom · project thread

Before: only the signed-in account could add to what's playing.

After: Party mode (sidebar, or the account sheet on mobile) starts a named party such as "Tomify Rocks!" and shows a six-letter access code and a /join/<code> link. Guests open the link on their phones, type their name (no Tomify account needed), search the library, add songs, see what's playing and what's next, and vote. The host sets a wait between each guest's adds (off, or 30 seconds to 10 minutes), how many songs each guest can have waiting, and whether voting is on. The host can remove songs or guests, and can end the party.

Closes #162.

How

  • Worker worker/features/party.ts, routes under /api/party (host: start/load/update/end, set an item queued/played, remove item/guest; guest: /join, /guest, /guest/search, /guest/queue, /guest/vote/:id, /guest/cover/:id). New migration drizzle/0017_parties.sql (parties, party_guests, party_queue, party_votes). Guest songs are re-read with getSong so guests can't inject track data, and guests only get song fields (no file paths).
  • Guest login: as Tom chose, guests search as the host. The host's Subsonic token and salt are sealed with TOMIFY_MEDIA_KEY (already set in prod) and deleted when the party ends or goes idle for 12 hours. Tom's alternative is also supported: if TOMIFY_PARTY_USERNAME and TOMIFY_PARTY_PASSWORD are set, guests use that Navidrome account and the host's login isn't stored.
  • Spam limits: per-guest wait between adds, a cap on waiting songs, no duplicates, no songs played in the last hour, 60 guests max, and wrong codes limited per IP (20 per 10 minutes, per Worker isolate).
  • Ordering: most votes first when voting is on. Otherwise, and between songs with equal votes, guests take turns.
  • Host player (src/stores/party.ts, PartyRuntime in the app shell): every 5 s it inserts the top waiting song straight after the current track, one at a time, so votes keep reordering the rest. It reports now playing for guests and marks songs played once they start. Only the device that started the party (or the one playing) does this, so a second open tab doesn't add songs twice.
  • Guest page src/pages/PartyGuest.tsx renders before the login check for /join/..., and the guest token is kept in localStorage.
  • Worker size budget raised from 160 KB to 176 KB. The minified Worker is now 174,524 B (it was about 163.7 KB). Needed because this adds ~10 KB.
  • Docs: README "Party mode", ARCHITECTURE config + migration tables.

Tests

  • Route test against real SQLite covers the full flow: 503 without a key, sealed credential, wrong code, guest search as the host, duplicates, limits, cooldown, turns, votes, queued/played, recently played, kicking a guest, and ending the party.
  • Unit tests cover nextPartyStep (vitest) and orderPartyQueue.
  • pnpm lint (2 existing warnings), typecheck, test, and build all pass.
  • The guest page was checked at phone size against mocked API responses. It has not been tried with real guests yet.

Deploy

Site only. Merging auto-deploys it, and pnpm run deploy applies D1 migration 0017_parties.sql. No agent change. If the Cloudflare build doesn't apply migrations, run npx pnpm run deploy once.


Generated by Claude Code

Hosts start a party (name, wait between adds, songs waiting per guest,
voting) and share a six-letter code. Guests open /join/<code> on their
phones without a Tomify login, search the library, add songs and vote.
The host's player puts the next guest song after the current track.
Guests search as a party login when one is set, otherwise as the host,
whose token is sealed with TOMIFY_MEDIA_KEY and deleted with the party.

Closes #162

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VYE1d3E4kQyA3bwSz73av4
@elcapitantommy elcapitantommy self-assigned this Oct 19, 2026
@elcapitantommy
elcapitantommy merged commit 5124912 into main Oct 19, 2026
2 checks passed
@elcapitantommy
elcapitantommy deleted the party-mode branch October 19, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Party mode: shared queue that guests join with an access code

2 participants