From 0a74c692d21bf15e39a6d566b3de98db116d084c Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Tue, 31 Mar 2026 17:19:14 -0400 Subject: [PATCH] [widgets] Fix the date filter --- vrobbler/apps/music/aggregators.py | 5 +- vrobbler/apps/scrobbles/views.py | 99 ++++++++++++++++++------------ 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/vrobbler/apps/music/aggregators.py b/vrobbler/apps/music/aggregators.py index b046772..0d8905d 100644 --- a/vrobbler/apps/music/aggregators.py +++ b/vrobbler/apps/music/aggregators.py @@ -84,11 +84,12 @@ def live_charts( chart_period: str = "all", limit: int = 15, app_label: str = "music", + as_of: datetime = None, ) -> QuerySet: - now = timezone.now() + now = as_of if as_of else timezone.now() tzinfo = now.tzinfo now = now.date() - if user.is_authenticated: + if user.is_authenticated and not as_of: now = now_user_timezone(user.profile) tzinfo = now.tzinfo diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index 787c353..9cb0b88 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -915,12 +915,7 @@ class BaseEmbeddableWidget(TemplateView): if date_param: try: - if "W" in date_param and date_param[4] == "-": - parsed_date = datetime.strptime(date_param, "%Y-W%W").date() - elif "-" in date_param and len(date_param) > 4: - parsed_date = datetime.strptime(date_param, "%Y-%m-%d").date() - else: - parsed_date = datetime.strptime(date_param, "%Y").date() + parsed_date = datetime.strptime(date_param, "%Y-%m-%d").date() except ValueError: parsed_date = None @@ -937,24 +932,31 @@ class BaseEmbeddableWidget(TemplateView): period = self.kwargs.get("period", "week") if period == "month": start = now.replace(day=1) + if now.month == 12: + end = now.replace(year=now.year + 1, month=1, day=1) + else: + end = now.replace(month=now.month + 1, day=1) label = now.strftime("%B %Y") elif period == "year": start = now.replace(month=1, day=1) + end = now.replace(year=now.year + 1, month=1, day=1) label = now.strftime("%Y") else: start = now - timedelta(days=now.isoweekday() % 7) + end = start + timedelta(days=7) label = f"Week {now.isocalendar()[1]}" - return start, label + return start, end, label - def get_items(self, user, start_date, model=None): + def get_items(self, user, start_date, end_date, model=None): from django.db.models import Count model = model or self.model queryset = ( model.objects.filter( - scrobble__user=user, + scrobble__user_id=user.id, scrobble__timestamp__gte=start_date, + scrobble__timestamp__lt=end_date, **self.scrobble_filter, ) .annotate(count=Count("scrobble", distinct=True)) @@ -976,10 +978,10 @@ class BaseEmbeddableWidget(TemplateView): context["media_type"] = self.media_type context["count_label"] = self.count_label - start_date, period_label = self.get_date_range(user) + start_date, end_date, period_label = self.get_date_range(user) context["period_label"] = period_label - items = self.get_items(user, start_date) + items = self.get_items(user, start_date, end_date) context["items"] = items context["no_data_message"] = self.no_data_message @@ -1000,6 +1002,35 @@ class EmbeddableTopArtistsWidget(TemplateView): raise Http404("Public widgets are not enabled for this user") return user, profile + def get_date_range(self, user): + date_param = self.request.GET.get("date") + + if date_param: + try: + parsed_date = datetime.strptime(date_param, "%Y-%m-%d").date() + except ValueError: + parsed_date = None + + if parsed_date: + now = parsed_date + else: + now = timezone.now().date() + else: + now = timezone.now() + if user.is_authenticated: + now = now_user_timezone(user.profile) + now = now.date() + + period = self.kwargs.get("period", "week") + if period == "month": + label = now.strftime("%B %Y") + elif period == "year": + label = now.strftime("%Y") + else: + label = f"Week {now.isocalendar()[1]}" + + return now, label + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) user, profile = self.get_user_and_profile() @@ -1010,34 +1041,20 @@ class EmbeddableTopArtistsWidget(TemplateView): context["count_label"] = self.count_label context["no_data_message"] = self.no_data_message + now, period_label = self.get_date_range(user) + period = self.kwargs.get("period", "week") period_map = {"week": "last7", "month": "last30", "year": "year"} chart_period = period_map.get(period, "last7") - artist = {"user": user, "media_type": "Artist", "limit": 10} + artist = {"user": user, "media_type": "Artist", "limit": 10, "as_of": now} items = list(live_charts(**artist, chart_period=chart_period)) for item in items: item.count = item.num_scrobbles context["items"] = items - - from datetime import timedelta - - from django.utils import timezone - - now = timezone.now() - if user.is_authenticated: - now = now_user_timezone(user.profile) - now = now.date() - - if period == "month": - context["period_label"] = now.strftime("%B %Y") - elif period == "year": - context["period_label"] = now.strftime("%Y") - else: - start = now - timedelta(days=now.isoweekday() % 7) - context["period_label"] = "This Week" + context["period_label"] = period_label return context @@ -1163,10 +1180,10 @@ class EmbeddableTopBoardGamesWidget(BaseEmbeddableWidget): no_data_message = "No board games played" scrobble_filter = {"scrobble__played_to_completion": True} - def get_items(self, user, start_date): + def get_items(self, user, start_date, end_date): from boardgames.models import BoardGame - return super().get_items(user, start_date, BoardGame) + return super().get_items(user, start_date, end_date, BoardGame) class EmbeddableTopBooksWidget(BaseEmbeddableWidget): @@ -1174,21 +1191,23 @@ class EmbeddableTopBooksWidget(BaseEmbeddableWidget): count_label = "reads" no_data_message = "No books read" - def get_items(self, user, start_date): + def get_items(self, user, start_date, end_date): from books.models import Book from django.db.models import Count, Exists, OuterRef completed_subquery = Book.objects.filter( - scrobble__user=user, + scrobble__user_id=user.id, scrobble__timestamp__gte=start_date, + scrobble__timestamp__lt=end_date, scrobble__long_play_complete=True, pk=OuterRef("pk"), ) queryset = ( Book.objects.filter( - scrobble__user=user, + scrobble__user_id=user.id, scrobble__timestamp__gte=start_date, + scrobble__timestamp__lt=end_date, ) .annotate( count=Count("scrobble", distinct=True), @@ -1209,10 +1228,10 @@ class EmbeddableTopTrailsWidget(BaseEmbeddableWidget): count_label = "visits" no_data_message = "No trails visited" - def get_items(self, user, start_date): + def get_items(self, user, start_date, end_date): from trails.models import Trail - return super().get_items(user, start_date, Trail) + return super().get_items(user, start_date, end_date, Trail) class EmbeddableTopFoodsWidget(BaseEmbeddableWidget): @@ -1220,10 +1239,10 @@ class EmbeddableTopFoodsWidget(BaseEmbeddableWidget): count_label = "meals" no_data_message = "No foods logged" - def get_items(self, user, start_date): + def get_items(self, user, start_date, end_date): from foods.models import Food - return super().get_items(user, start_date, Food) + return super().get_items(user, start_date, end_date, Food) class EmbeddableTopTasksWidget(BaseEmbeddableWidget): @@ -1231,7 +1250,7 @@ class EmbeddableTopTasksWidget(BaseEmbeddableWidget): count_label = "sessions" no_data_message = "No tasks logged" - def get_items(self, user, start_date): + def get_items(self, user, start_date, end_date): from tasks.models import Task - return super().get_items(user, start_date, Task) + return super().get_items(user, start_date, end_date, Task)