Both Discover rec rows already exclude what you own/watch, so novelty is baked in; the missing lever is a popularity penalty. apply_adventurousness(items, level) re-ranks dicts (score + optional 0-100 popularity) so globally-popular candidates sink as the dial rises. Pure + reusable across both rec rows. level<=0 returns the input order unchanged (a copy) — fully additive, no regression; 1.0 applies the full penalty (a popularity-100 pick loses 70% of its score). Missing popularity is never penalised. 5 seam tests (no-op+copy, demotion, proportional penalty, missing-pop, clamping). 37 pass. Wiring (scan stores popularity -> routes re-rank live -> Settings slider) is the next increment. |
||
|---|---|---|
| .. | ||
| __init__.py | ||
| beatport.py | ||
| deezer.py | ||
| endpoints.py | ||
| hero.py | ||
| listenbrainz.py | ||
| listening_recommendations.py | ||
| manual_match.py | ||
| matching.py | ||
| playlist.py | ||
| qobuz.py | ||
| quality_scanner.py | ||
| scoring.py | ||
| spotify_public.py | ||
| sync.py | ||
| tidal.py | ||
| youtube.py | ||