Web and mobile:
- Follower/following lists (tap the counts), with Follow buttons and
"Remove" on your own followers.
- Profile ⋯ menu: block (with confirmation) / unblock, and report with a
reason and optional note. "Follows you" label, "Follow back", and a
banner on profiles you've blocked.
- Blocked accounts list in Settings, with unblock.
Web only: /admin for the admin account: stats, open/resolved reports,
resolve, suspend/unsuspend.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
The server now sends each fresh position on every poll that has one, and
sends positions advanced to send time; clients count only the time since
they received it. Bars realign every poll and no longer drift by however
far the viewer's clock is off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
- Feed and profile cards show a progress bar with elapsed/total time, only
when the source reports a real position (Plex, Jellyfin, the Android
reader). It ticks locally between updates. Apple Music's guessed
position is no longer reported.
- The Android reader advances MediaSession's stale position to now, stamps
when it was read (the server corrects for upload delay), and reports
seeks. The server pushes an update to watchers when a position jumps.
- When a polled source says where in the song someone is, the next poll is
scheduled just after the song ends (never sooner than 5s), instead of
waiting out the full interval.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
"Forgot your password?" on web and mobile sends a one-time link (1 hour)
to the account's email; the website's reset page sets the new password,
signs out every other session and signs in. The request responds the same
whether or not the email has an account, and the email goes out in the
background so timing doesn't reveal it either. Only a hash of the link
token is stored. Sends through SMTP_* settings; without them, emails are
logged (and captured in tests).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
- Upload a profile picture on web and mobile. The API square-crops it to
512px WebP, strips metadata (phone photos carry GPS), stores it in
Postgres and serves it with immutable caching. Avatar URLs are stored as
paths, so they survive moving the API. Arbitrary avatar URLs are no
longer accepted (they'd let a profile track its viewers).
- New accounts get the username as typed as their display name; existing
accounts are backfilled, and clearing it falls back to the username.
- Service names in Settings get a brand-coloured badge and larger type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
- Redesign matching the web: album-art backdrops, Reanimated equalizer,
spinning live ring, drifting ambient background, gradient buttons with
spring press feedback and haptics, Space Grotesk headings, animated feed
(enter + layout transitions); fix invisible tab labels
- Four-step onboarding for new accounts: which app you listen with (sets
where songs open), the matching share setup, find friends (search,
scan, invite), and a featured song. Skippable; stored server-side
- QR codes: My code (share link) and an in-app scanner (camera only, no
microphone permission)
- Spotify setup via Last.fm or ListenBrainz with guided linking; Android
shares Spotify automatically through the phone reader
- New logo as app icon, adaptive/monochrome icon and splash
- app.config.ts allows cleartext only for local http:// test builds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
- Every feature is free for everyone (the plan system stays for later);
remaining limits are abuse guards
- Optional website donation link (NEXT_PUBLIC_DONATION_URL). Not shown in
the mobile apps, where tips to the developer generally need in-app
purchase
- Last.fm/ListenBrainz-sourced plays link to the user's profile, as
Last.fm's API terms require
- Connections track when they last saw activity; a scrobbler silent for
over a week prompts re-linking Spotify (its link expires every 6 months)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
A local Expo module listens to system media sessions (the only way
Android exposes other apps' playback, gated by notification access; we
never read notifications). It filters to known music apps, debounces and
deduplicates changes, sends a heartbeat while playing, and delivers
reports through WorkManager so they survive the app being closed.
- One-screen onboarding that doubles as Google Play's prominent
disclosure, opening straight to the app's toggle in Android settings
- Only media notifications are pre-ticked on that settings screen
- Device registration is single-flight (several screens react to the
same permission change) and self-heals if the server revokes a token
- Sign-out revokes the phone's token; resuming sharing re-sends the
current track immediately
- Pause controls in Settings and on the feed
- Fix invisible tab icons and labels on Android
- Keep Metro out of build output so it doesn't exhaust file watchers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
A play is recorded when a new track starts (pausing and resuming doesn't
count; returning after 10+ minutes does). Profiles show the last 10,
excluding the track playing now; 50 are kept per user. Recent plays are
free on every plan; the paid flag is renamed to fullHistory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
Native tabs for feed, friend search, profile and settings, with feature
parity with the web app. Sessions are stored in SecureStore, realtime
disconnects in the background, and Spotify/Plex sign-in returns to the app
via the URL scheme.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8