From e75c22d5836bcc2aaf5a55cea64f173a81540360 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Wed, 18 Jan 2023 00:39:12 -0500 Subject: [PATCH] Add timezone support and an authenticated view --- vrobbler/apps/music/aggregators.py | 118 ++++++++++++------ vrobbler/apps/profiles/utils.py | 12 +- vrobbler/apps/scrobbles/views.py | 58 +++++---- vrobbler/settings.py | 9 +- vrobbler/templates/base.html | 13 +- .../templates/scrobbles/scrobble_list.html | 56 +++++++-- 6 files changed, 185 insertions(+), 81 deletions(-) diff --git a/vrobbler/apps/music/aggregators.py b/vrobbler/apps/music/aggregators.py index 7e7d1b7..098519f 100644 --- a/vrobbler/apps/music/aggregators.py +++ b/vrobbler/apps/music/aggregators.py @@ -1,12 +1,13 @@ -from django.db.models import Q, Count, Sum -from typing import List, Optional -from scrobbles.models import Scrobble -from music.models import Track, Artist -from videos.models import Video - -from django.utils import timezone from datetime import datetime, timedelta +from typing import List, Optional +import pytz +from django.db.models import Count, Q, Sum +from django.utils import timezone +from music.models import Artist, Track +from scrobbles.models import Scrobble +from videos.models import Video +from vrobbler.apps.profiles.utils import now_user_timezone NOW = timezone.now() START_OF_TODAY = datetime.combine(NOW.date(), datetime.min.time(), NOW.tzinfo) @@ -17,58 +18,103 @@ STARTING_DAY_OF_CURRENT_MONTH = NOW.date().replace(day=1) STARTING_DAY_OF_CURRENT_YEAR = NOW.date().replace(month=1, day=1) -def scrobble_counts(): - finished_scrobbles_qs = Scrobble.objects.filter(played_to_completion=True) +def scrobble_counts(user): + + now = timezone.now() + user_filter = Q() + if user.is_authenticated: + now = now_user_timezone(user.profile) + user_filter = Q(user=user) + + start_of_today = datetime.combine( + now.date(), datetime.min.time(), now.tzinfo + ) + starting_day_of_current_week = now.date() - timedelta( + days=now.today().isoweekday() % 7 + ) + starting_day_of_current_month = now.date().replace(day=1) + starting_day_of_current_year = now.date().replace(month=1, day=1) + + finished_scrobbles_qs = Scrobble.objects.filter( + user_filter, played_to_completion=True + ) data = {} data['today'] = finished_scrobbles_qs.filter( - timestamp__gte=START_OF_TODAY + timestamp__gte=start_of_today ).count() data['week'] = finished_scrobbles_qs.filter( - timestamp__gte=STARTING_DAY_OF_CURRENT_WEEK + timestamp__gte=starting_day_of_current_week ).count() data['month'] = finished_scrobbles_qs.filter( - timestamp__gte=STARTING_DAY_OF_CURRENT_MONTH + timestamp__gte=starting_day_of_current_month ).count() data['year'] = finished_scrobbles_qs.filter( - timestamp__gte=STARTING_DAY_OF_CURRENT_YEAR + timestamp__gte=starting_day_of_current_year ).count() data['alltime'] = finished_scrobbles_qs.count() return data -def week_of_scrobbles(media: str = 'tracks') -> dict[str, int]: +def week_of_scrobbles(user=None, media: str = 'tracks') -> dict[str, int]: + + now = timezone.now() + user_filter = Q() + if user.is_authenticated: + now = now_user_timezone(user.profile) + user_filter = Q(user=user) + + start_of_today = datetime.combine( + now.date(), datetime.min.time(), now.tzinfo + ) + scrobble_day_dict = {} + base_qs = Scrobble.objects.filter(user_filter, played_to_completion=True) + media_filter = Q(track__isnull=False) + if media == 'movies': + media_filter = Q(video__video_type=Video.VideoType.MOVIE) + if media == 'series': + media_filter = Q(video__video_type=Video.VideoType.TV_EPISODE) for day in range(6, -1, -1): - start = START_OF_TODAY - timedelta(days=day) - end = datetime.combine(start, datetime.max.time(), NOW.tzinfo) + start = start_of_today - timedelta(days=day) + end = datetime.combine(start, datetime.max.time(), now.tzinfo) day_of_week = start.strftime('%A') - if media == 'movies': - media_filter = Q(video__videotype=Video.VideoType.MOVIE) - if media == 'series': - media_filter = Q(video__videotype=Video.VideoType.TV_EPISODE) - scrobble_day_dict[day_of_week] = ( - Scrobble.objects.filter(media_filter) - .filter( - timestamp__gte=start, - timestamp__lte=end, - played_to_completion=True, - ) - .count() - ) + + scrobble_day_dict[day_of_week] = base_qs.filter( + media_filter, + timestamp__gte=start, + timestamp__lte=end, + played_to_completion=True, + ).count() return scrobble_day_dict -def top_tracks(filter: str = "today", limit: int = 15) -> List["Track"]: - time_filter = Q(scrobble__timestamp__gte=START_OF_TODAY) +def top_tracks( + user: "User", filter: str = "today", limit: int = 15 +) -> List["Track"]: + + now = timezone.now() + if user.is_authenticated: + now = now_user_timezone(user.profile) + + start_of_today = datetime.combine( + now.date(), datetime.min.time(), now.tzinfo + ) + starting_day_of_current_week = now.date() - timedelta( + days=now.today().isoweekday() % 7 + ) + starting_day_of_current_month = now.date().replace(day=1) + starting_day_of_current_year = now.date().replace(month=1, day=1) + + time_filter = Q(scrobble__timestamp__gte=start_of_today) if filter == "week": - time_filter = Q(scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_WEEK) + time_filter = Q(scrobble__timestamp__gte=starting_day_of_current_week) if filter == "month": - time_filter = Q(scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_MONTH) + time_filter = Q(scrobble__timestamp__gte=starting_day_of_current_month) if filter == "year": - time_filter = Q(scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_YEAR) + time_filter = Q(scrobble__timestamp__gte=starting_day_of_current_year) return ( Track.objects.filter(time_filter) @@ -77,7 +123,9 @@ def top_tracks(filter: str = "today", limit: int = 15) -> List["Track"]: ) -def top_artists(filter: str = "today", limit: int = 15) -> List["Artist"]: +def top_artists( + user: "User", filter: str = "today", limit: int = 15 +) -> List["Artist"]: time_filter = Q(track__scrobble__timestamp__gte=START_OF_TODAY) if filter == "week": time_filter = Q( diff --git a/vrobbler/apps/profiles/utils.py b/vrobbler/apps/profiles/utils.py index effd5bb..15866f3 100644 --- a/vrobbler/apps/profiles/utils.py +++ b/vrobbler/apps/profiles/utils.py @@ -1,6 +1,9 @@ import datetime -import settings + import pytz +from django.conf import settings +from django.utils import timezone + # need to translate to a non-naive timezone, even if timezone == settings.TIME_ZONE, so we can compare two dates def to_user_timezone(date, profile): @@ -17,7 +20,12 @@ def to_system_timezone(date, profile): ) -def now_timezone(): +def now_user_timezone(profile): + timezone.activate(pytz.timezone(profile.timezone)) + return timezone.localtime(timezone.now()) + + +def now_system_timezone(): return ( datetime.datetime.now() .replace(tzinfo=pytz.timezone(settings.TIME_ZONE)) diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index e068206..c0c842d 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -9,6 +9,7 @@ from django.utils import timezone from django.views.decorators.csrf import csrf_exempt from django.views.generic import FormView from django.views.generic.list import ListView +import pytz from rest_framework import status from rest_framework.decorators import api_view from rest_framework.response import Response @@ -45,31 +46,44 @@ class RecentScrobbleList(ListView): def get_context_data(self, **kwargs): data = super().get_context_data(**kwargs) + user = self.request.user now = timezone.now() - data['now_playing_list'] = Scrobble.objects.filter( - in_progress=True, - is_paused=False, - timestamp__lte=now, - ) - data['video_scrobble_list'] = Scrobble.objects.filter( - video__isnull=False, played_to_completion=True - ).order_by('-timestamp')[:15] - data['podcast_scrobble_list'] = Scrobble.objects.filter( - podcast_episode__isnull=False, played_to_completion=True - ).order_by('-timestamp')[:15] - data['sport_scrobble_list'] = Scrobble.objects.filter( - sport_event__isnull=False, played_to_completion=True - ).order_by('-timestamp')[:15] - # data['top_daily_tracks'] = top_tracks() - # data['top_weekly_tracks'] = top_tracks(filter='week') - data['top_monthly_tracks'] = top_tracks(filter='month') + if self.request.user.is_authenticated: + timezone.activate(pytz.timezone(user.profile.timezone)) + now = timezone.localtime(timezone.now()) + data['now_playing_list'] = Scrobble.objects.filter( + in_progress=True, + is_paused=False, + timestamp__lte=now, + user=user, + ) - # data['top_daily_artists'] = top_artists() - data['top_weekly_artists'] = top_artists(filter='week') - data['top_monthly_artists'] = top_artists(filter='month') + completed_for_user = Scrobble.objects.filter( + played_to_completion=True, user=user + ) + data['video_scrobble_list'] = completed_for_user.filter( + video__isnull=False + ).order_by('-timestamp')[:15] - data["weekly_data"] = week_of_scrobbles() - data['counts'] = scrobble_counts() + data['podcast_scrobble_list'] = completed_for_user.filter( + podcast_episode__isnull=False + ).order_by('-timestamp')[:15] + + data['sport_scrobble_list'] = completed_for_user.filter( + sport_event__isnull=False + ).order_by('-timestamp')[:15] + + # data['top_daily_tracks'] = top_tracks() + data['top_weekly_tracks'] = top_tracks(user, filter='week') + data['top_monthly_tracks'] = top_tracks(user, filter='month') + + # data['top_daily_artists'] = top_artists() + data['top_weekly_artists'] = top_artists(user, filter='week') + data['top_monthly_artists'] = top_artists(user, filter='month') + + data["weekly_data"] = week_of_scrobbles(user=user) + + data['counts'] = scrobble_counts(user) data['imdb_form'] = ScrobbleForm return data diff --git a/vrobbler/settings.py b/vrobbler/settings.py index 938b97c..39e6e14 100644 --- a/vrobbler/settings.py +++ b/vrobbler/settings.py @@ -53,7 +53,7 @@ TMDB_API_KEY = os.getenv("VROBBLER_TMDB_API_KEY", "") DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -TIME_ZONE = os.getenv("VROBBLER_TIME_ZONE", "EST") +TIME_ZONE = os.getenv("VROBBLER_TIME_ZONE", "US/Eastern") ALLOWED_HOSTS = ["*"] CSRF_TRUSTED_ORIGINS = [ @@ -61,16 +61,9 @@ CSRF_TRUSTED_ORIGINS = [ ] X_FRAME_OPTIONS = "SAMEORIGIN" - CACHALOT_TIMEOUT = os.getenv("VROBBLER_CACHALOT_TIMEOUT", 3600) REDIS_URL = os.getenv("VROBBLER_REDIS_URL", None) -CELERY_TASK_ALWAYS_EAGER = os.getenv("VROBBLER_SKIP_CELERY", False) -CELERY_BROKER_URL = REDIS_URL if REDIS_URL else "memory://localhost/" -CELERY_RESULT_BACKEND = "django-db" -CELERY_TIMEZONE = os.getenv("VROBBLER_TIME_ZONE", "EST") -CELERY_TASK_TRACK_STARTED = True - INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", diff --git a/vrobbler/templates/base.html b/vrobbler/templates/base.html index 34a4e6e..c5c0af0 100644 --- a/vrobbler/templates/base.html +++ b/vrobbler/templates/base.html @@ -10,6 +10,7 @@ + @@ -175,16 +176,18 @@ + {% if user.is_authenticated %}
{% csrf_token %} {{ imdb_form }}
+ {% endif %} @@ -194,7 +197,7 @@
{% endblock %}