[charts] Add global charts aggregated across opted-in users

This commit is contained in:
2026-09-01 11:39:25 -04:00
parent 0d405f67e0
commit d569d31715
16 changed files with 888 additions and 166 deletions

View File

@ -622,7 +622,7 @@ When a new books arrives inside of a KoReader import, the metadata is not enrich
source (previously it would crash).
- Routed =enrich_book_metadata= to the =background= worker queue.
** TODO [#B] There should a global chart aggregator that builds charts across all users :charts:feature:
** DONE [#B] There should a global chart aggregator that builds charts across all users :charts:feature:
:PROPERTIES:
:ID: ccc257d5-7d35-42b0-9af2-2941b67880fd
:END:
@ -636,6 +636,37 @@ bronze). There should also be a toggle in profile settings that allows a user to
include their scrobbles in global aggregation. If that check box is not selected
(and it should off by default) that user is not included in the global charts.
*** Implementation
- Global chart records are stored as =ChartRecord= rows with a NULL =user=
(the column is already nullable), so they reuse the existing model,
upserting, indexing and chart rendering infrastructure.
- Added =UserProfile.include_in_global_charts= (default off) plus a settings
form checkbox; users who do not opt in are excluded from aggregation.
Toggling the setting triggers =scrobbles.tasks.rebuild_global_charts_for_user()=
which rebuilds every global chart period the user has scrobbles in, so the
change is reflected immediately instead of waiting for the next scheduled
chart build.
- Refactored ~vrobbler/apps/charts/utils.py~: extracted the media type config
into a module-level =MEDIA_CONFIG= and pulled the aggregation and upsert
logic into shared =_aggregate_media()= and =_upsert_chart_records()=
helpers used by both =build_charts()= and the new =build_global_charts()=.
- Added =build_global_charts()= plus =build_global_daily/weekly/monthly/yearly_charts()=
wrappers. Global charts aggregate scrobbles from opted-in users only and
keep just the top three items (gold, silver, bronze) per media type/period.
- Wired global chart building into the scheduled Celery tasks
(~vrobbler/apps/scrobbles/tasks.py~): =create_yesterdays_charts()=,
=rebuild_weekly_charts()=, =rebuild_monthly_charts()= and
=rebuild_yearly_charts()= now also build the matching global charts.
- Added =GlobalChartView= at =/charts/global/= (~charts.GlobalChartView~) with a
new ~charts/global_chart_index.html~ template showing the medal top three
per media type, with the same year/month/week navigation as user charts.
- Anonymous users now see the global top-three charts on media detail pages:
~scrobbles.views.ChartContextMixin~ queries =user__isnull=True= records
when the request user is anonymous.
- Tests in ~vrobbler/apps/charts/tests/test_views.py~ and new global chart
tests in ~vrobbler/apps/charts/tests/test_utils.py~.
** DONE [#B] Make it possible for anonymous users to view media objects :media:templates:
:PROPERTIES: