Skip to content

feat(weekly-rotation): make the mix shareable - #14587

Merged
dylanjeffers merged 1 commit into
mainfrom
feat/weekly-rotation-share
Sep 8, 2026
Merged

feat(weekly-rotation): make the mix shareable#14587
dylanjeffers merged 1 commit into
mainfrom
feat/weekly-rotation-share

Conversation

@dylanjeffers

@dylanjeffers dylanjeffers commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

What

A Weekly Rotation can now be shared. Share produces audius.co/explore/weekly-rotation/:handle, which shows that listener's mix to anyone (the endpoint is public, no auth), and unfurls with a 2x2 collage of the mix's first four tracks rendered by og.audius.co/weekly-rotation/:handle?week=YYYY-WW.

The bare /explore/weekly-rotation stays the signed-in user's own mix. Under /explore rather than /:handle/weekly-rotation because /:handle/:slug is the track permalink pattern.

By package

common

  • ShareType / ShareModalRequest / ShareContent gain weeklyRotation. The content is just the listener (User): there's no entity behind the mix, the link is a function of the handle.
  • useWeeklyRotation({ userId }) takes an optional target user; defaults to the viewer.
  • Share / ShareToTwitter analytics get a weeklyRotation kind.
  • WEEKLY_ROTATION_USER_PAGE + weeklyRotationPage(handle). Copy says Wednesday: the rollover moved (api PR).

web

  • Share button next to Play. The share modal builds the link from the handle and copies it directly with the same Share event the sagas emit, there being no social saga for a non-entity.
  • Handle route registered in both router trees. The page resolves the handle via useUserByHandle, titles as "{name}'s Weekly Rotation" for someone else's mix, and only the handle route gets og:image + canonical (the bare route is per-viewer and shouldn't be indexed as anyone's).
  • New Vike SSR entry ssr/weekly-rotation (/explore/weekly-rotation/@handle): fetches the user for the name, emits the collage URL as og:image, summary_large_image. The bare route still falls to the explore handler, which now has a weekly-rotation entry in exploreMap.
  • utils/weeklyRotationPeriod.ts: dependency-free mirror of the API's Wednesday-shifted ISO week, used by SSR (which avoids @audius/common/utils) and the client. Same test cases as the Go side so they can't drift apart. 7 vitest cases.

mobile

  • Share icon in the top bar. Drawer offers DM, X, Copy Link, and the system sheet. No Instagram/TikTok/Snapchat story rows: those need a single streamable mp3 for the FFmpeg background video, which a mix doesn't have.
  • WeeklyRotationScreen takes an optional handle param; explore/weekly-rotation/:handle? added to the explore deep-link map.

Verified

  • tsc clean in common, web, mobile. ESLint clean on every touched file.
  • weeklyRotationPeriod.test.ts passes.
  • The collage endpoint was rendered locally against prod (see og PR).

Not verified

  • Mobile share drawer and deep link compile but were not exercised on a simulator.

Depends on

Product note

Michael's Weekly Rotation thread describes the mix as new music from artists you follow / have liked. The shipped ranking does the opposite on purpose. Not changed here; flagged on the api PR.

🤖 Generated with Claude Code

A Weekly Rotation can now be linked. Sharing produces
/explore/weekly-rotation/:handle, which shows that listener's mix to anyone
(the endpoint is public), and unfurls with a 2x2 collage of the mix's first
four tracks rendered by og.audius.co. The bare /explore/weekly-rotation
stays the signed-in user's own mix.

Under /explore rather than /:handle/weekly-rotation because /:handle/:slug
is the track permalink pattern.

- common: `weeklyRotation` share type, request and content; the content
  is just the listener, since there is no entity behind the mix.
  useWeeklyRotation takes an optional userId. Share analytics get a
  `weeklyRotation` kind. Copy says Wednesday: the rollover moved.
- web: Share button on the page; the share modal builds the link from the
  handle and copies it directly, there being no social saga to route
  through. The handle route is registered in both router trees and gets a
  Vike SSR entry that emits the collage as og:image with the period
  stamped into the URL as a cache-buster. getWeeklyRotationPeriod mirrors
  the API's Wednesday-shifted ISO week and carries the same test cases.
- mobile: share icon in the top bar, the share drawer offers DM, X, Copy
  Link and the system sheet (the story paths need a single streamable
  track, which a mix does not have), the screen takes an optional handle,
  and explore/weekly-rotation/:handle? is deep-linkable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9ac5e47

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

dylanjeffers added a commit to AudiusProject/api that referenced this pull request Sep 8, 2026
… shared (#1034)

## Why

Weekly Rotation is becoming shareable
(`audius.co/explore/weekly-rotation/:handle`: AudiusProject/apps#14587
and AudiusProject/og#6). Two things on the API side had to change for a
shared link to mean anything.

## What

**Rollover moves to Wednesday 00:00 UTC** (was the ISO week boundary,
Monday). Product call from Michael's Weekly Rotation thread: Monday
already belongs to the other weekly surfaces and Friday is Spotify's.
The period is still identified by an ISO `(year, week)` pair, it's the
ISO week shifted forward two days, so cache keys, the jitter seed and
share links keep their shape. `weeklyRotationPeriod` /
`weeklyRotationPeriodStart` are inverses and tested as such.

**Listener history is frozen at the rollover instant.** Plays, saves,
reposts and follows are now read as of the period's start
(`@periodStart`) rather than the request. Before this, playing a track
*from* the mix met the played-exclusion and removed it on the next cache
miss, so a mix shared on Wednesday was a different, shorter list by
Thursday. The mix has to survive being listened to.

Still drifts mid-week: the trending candidate pool and engagement
counts. Freezing those needs a stored snapshot table; not in scope here.

## Tests

- `TestWeeklyRotationPeriod`: rollover instant, one second before it,
Monday/Tuesday belonging to the previous period, non-UTC input, the
2026/2027 year boundary, and a round trip over every hour of 2026.
- `TestV1UsersWeeklyRotationKeepsTracksPlayedThisPeriod`: a play dated
now leaves the track in the mix; a play from 8 days ago still excludes.
- Existing fixtures dated their history 8 days back so they predate any
possible rollover.

All eight weekly-rotation tests pass against the compose DB.

## Not in this PR

Michael's thread also describes the mix as new music from artists you
follow / have liked. The shipped ranking does the opposite on purpose
(followed artists demoted, For You is the in-network surface). Needs a
product decision before anyone touches the scoring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@dylanjeffers
dylanjeffers merged commit 5f3fa5d into main Sep 8, 2026
17 checks passed
@dylanjeffers
dylanjeffers deleted the feat/weekly-rotation-share branch September 8, 2026 23:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant