Files
minstrel/internal/db/migrations/0102_genre_mix_variant.down.sql
T
bvandeusenandClaude Opus 5.5 dbaa8b7d57
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m47s
release / govulncheck (push) Successful in 25s
release / integration (push) Failing after 4m38s
release / android (push) Successful in 4m3s
release / Build signed APK (push) Successful in 4m34s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
feat: genre mixes — a daily playlist per genre you listen to, on a "Your genres" Home row (#6904)
A new system playlist kind, genre_mix: up to 10 "{Genre} mix" playlists per
user, rebuilt daily with the other system mixes.

Which genres: library genres with at least 25 playable tracks across 3
artists, ranked in tiers — taste-profile genres first (matched
case-insensitively, so ID3 "Post-Punk" and folksonomy "post-punk" are one),
then genres the user has played or liked, then the rest of the library, which
only tops a short shelf up to 4. A genre whose artist set is a near
duplicate of one already picked (Jaccard >= 0.5) is skipped, so "Lo-Fi" and
"Lo-Fi Hip Hop" don't both appear but "Alternative Rock" survives "Rock". A
genre that can't fill 15 tracks gives way to the next.

Each mix is 50 tracks: 3 in 5 the user already knows (played through or
liked), the rest unheard in that genre, interleaved, with the usual
per-album/per-artist caps. Tracks skipped twice and more often than played
are left out. The order changes daily and holds within a day. Picks are
stamped taste / taste_unheard, and genre_mix plays count toward rotation and
the recommendation metrics.

Migration 0102 adds genre_mix to the playlists variant constraints.

Web and Android each get a "Your genres" row in name order, hidden until a
mix exists. Kinds with several playlists per user now play by playlist id
wherever the client used to test seed_artist_id (web card, detail page
self-heal), keyed on the server's refreshable flag; on Android genre_mix
joins songs_like_artist as not refreshable. The web detail page's
"mix was rebuilt" reload now finds a Songs-like or genre mix by name instead
of calling the by-kind shuffle, which those kinds don't have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:30:41 -05:00

38 lines
1.5 KiB
SQL

-- Restores the 0028 constraint set. Genre-mix rows would violate it, so they
-- go first.
DELETE FROM playlists WHERE system_variant = 'genre_mix';
ALTER TABLE playlists DROP CONSTRAINT IF EXISTS playlists_kind_variant_consistent;
ALTER TABLE playlists
ADD CONSTRAINT playlists_kind_variant_consistent CHECK (
(kind = 'user' AND system_variant IS NULL)
OR
(kind = 'system' AND system_variant IN (
'for_you', 'songs_like_artist', 'discover',
'deep_cuts', 'rediscover', 'new_for_you',
'on_this_day', 'first_listens'
))
);
ALTER TABLE playlists DROP CONSTRAINT IF EXISTS playlists_seed_consistent;
ALTER TABLE playlists
ADD CONSTRAINT playlists_seed_consistent CHECK (
(system_variant IS NULL AND seed_artist_id IS NULL)
OR
(system_variant = 'for_you' AND seed_artist_id IS NULL)
OR
(system_variant = 'discover' AND seed_artist_id IS NULL)
OR
(system_variant = 'deep_cuts' AND seed_artist_id IS NULL)
OR
(system_variant = 'rediscover' AND seed_artist_id IS NULL)
OR
(system_variant = 'new_for_you' AND seed_artist_id IS NULL)
OR
(system_variant = 'on_this_day' AND seed_artist_id IS NULL)
OR
(system_variant = 'first_listens' AND seed_artist_id IS NULL)
OR
(system_variant = 'songs_like_artist' AND seed_artist_id IS NOT NULL)
);