Skip to content

feat: smart playlist seeding, per-user play tracking, and Playwright tests#9

Closed
psykzz wants to merge 4 commits into
mainfrom
feature/smart-playlist-seeding
Closed

feat: smart playlist seeding, per-user play tracking, and Playwright tests#9
psykzz wants to merge 4 commits into
mainfrom
feature/smart-playlist-seeding

Conversation

@psykzz

@psykzz psykzz commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Smart Playlist Seeding & Per-User Play Tracking

Summary

This PR implements the full feature plan from PLAN.md — per-user implicit rating system, smarter playlist generation with preference-based reseeding, onboarding cadence, and a Playwright e2e test suite.


What Changed

Phase 1 — Per-User Play/Skip Tracking (schema)

  • UserTrackStats model: per-user playCount and skipCount per track
  • Rating.implicit field: distinguishes system-generated ratings from explicit user choices
  • Removed global Track.playCount (was shared across all users, now per-user in UserTrackStats)
  • Prisma migration included

Phase 2 — Implicit Rating Service

  • implicitRatingService.js: evaluates net = playCount - skipCount per user/track
    • net ≥ 5 → implicit Like; net ≤ -5 → implicit Dislike; neutral zone → remove implicit rating
  • /api/tracks/complete now upserts UserTrackStats and calls evaluateImplicitRating
  • /api/tracks/skip new route — records skip event and re-evaluates implicit rating
  • /api/ratings deletes any implicit rating before upserting an explicit one (explicit always wins)

Phase 3 — Player Skip Detection

  • 80% completion threshold fires /complete
  • Skip is detected if elapsed ≥ 5s AND currentTime/duration < 20% — fires /skip
  • All navigation paths (prev/next buttons, keyboard, media keys) run skip detection

Phase 4 — Onboarding Cadence

  • Two-step onboarding modal: genre picker → cadence picker (daily / weekly / monthly)
  • /api/onboarding/seed accepts { genres, cadence } and upserts CadenceSetting

Smart Playlist Generation (new)

  • Liked tracks are never dropped: explicit or implicit score > 0 always included
  • Rotation by play count: when liked tracks exceed 70% of cycle size, least-played liked songs are prioritised so every favourite gets airtime over successive cycles
  • 30% discovery slots: always reserved for neutral/unrated tracks to surface new music
  • Liked tracks protected from file purge: cleanupService now skips any track with a positive rating before deleting audio files

Preference-Based Reseeding

  • lastfmService: added fetchSimilarArtists
  • schedulerService: smarter seedFromLastfm uses UserTrackStats + ratings to build artist/genre preference profile; expands via similar artists; library soft cap of 250 tracks

Bug Fixes

  • Profile menu z-index (appeared behind page content)
  • DebugPage background (invalid CSS gradient syntax)
  • DownloadPanel progress counter (X / Y done)
  • Rate limiting removed (family-hosted service, not public-facing)

Playwright E2E Test Suite (20 tests, all passing)

  • e2e/auth.spec.js — registration, login, error states
  • e2e/onboarding.spec.js — genre selection, cadence step, back nav, seeding
  • e2e/app.spec.js — profile menu z-index, debug page, download panel, player bar

Testing

# Run all e2e tests (requires dev servers running)
npm test

# or with auto-start
START_SERVERS=1 npm test

All 20 Playwright tests pass locally.

- Add UserTrackStats model for per-user play/skip counts
- Add Rating.implicit boolean to distinguish system-generated ratings
- Remove Track.playCount (moved to per-user UserTrackStats)
- Add Prisma migration for schema changes
@psykzz

psykzz commented Jun 7, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the smaller split PRs (#10-#20). All changes have been merged individually.

@psykzz psykzz closed this Jun 7, 2026
@psykzz psykzz reopened this Jun 7, 2026
@psykzz psykzz closed this Jun 7, 2026
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.

1 participant