From 602d1e0ddbcb94971fa913d33957a2e51380b39f Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Tue, 10 Jan 2023 14:40:59 -0500 Subject: [PATCH] Add better frontend, the first of many! --- vrobbler/apps/music/aggregators.py | 70 ++++ vrobbler/apps/scrobbles/views.py | 16 +- vrobbler/settings.py | 1 + vrobbler/templates/base.html | 312 ++++++++++++++---- .../templates/scrobbles/scrobble_list.html | 135 +++++--- 5 files changed, 429 insertions(+), 105 deletions(-) create mode 100644 vrobbler/apps/music/aggregators.py diff --git a/vrobbler/apps/music/aggregators.py b/vrobbler/apps/music/aggregators.py new file mode 100644 index 0000000..cce0ae7 --- /dev/null +++ b/vrobbler/apps/music/aggregators.py @@ -0,0 +1,70 @@ +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 + + +NOW = timezone.now() +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) + + +def scrobble_counts(): + finished_scrobbles_qs = Scrobble.objects.filter(in_progress=False) + data = {} + data['today'] = finished_scrobbles_qs.filter(timestamp__gte=START_OF_TODAY).count() + data['week'] = finished_scrobbles_qs.filter(timestamp__gte=STARTING_DAY_OF_CURRENT_WEEK).count() + data['month'] = finished_scrobbles_qs.filter(timestamp__gte=STARTING_DAY_OF_CURRENT_MONTH).count() + data['year'] = finished_scrobbles_qs.filter(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]: + scrobble_day_dict= {} + media_filter = Q(track__isnull=True) + + for day in range(1,8): + 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.MOVIE) + scrobble_day_dict[day_of_week] = Scrobble.objects.filter(media_filter).filter(timestamp__lte=START_OF_TODAY, timestamp__gt=end, in_progress=False).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) + if filter == "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) + if filter == "year": + time_filter = Q(scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_YEAR) + + return Track.objects.annotate(num_scrobbles=Count("scrobble", distinct=True)).filter(time_filter).order_by("-num_scrobbles")[:limit] + +def top_artists(filter: str="today", limit: int=15) -> List["Artist"]: + time_filter = Q(track__scrobble__timestamp__gte=START_OF_TODAY) + if filter == "week": + time_filter = Q(track__scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_WEEK) + if filter == "month": + time_filter = Q(track__scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_MONTH) + if filter == "year": + time_filter = Q(track__scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_YEAR) + + return Artist.objects.annotate(num_scrobbles=Sum("track__scrobble", distinct=True)).filter(time_filter).order_by("-num_scrobbles")[:limit] + +def artist_scrobble_count(artist_id: int, filter: str = "today") -> int: + return ( + Scrobble.objects.filter(track__artist=artist_id) + .count() + ) diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index 87a9935..15224ad 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -21,6 +21,7 @@ from scrobbles.models import Scrobble from scrobbles.serializers import ScrobbleSerializer from scrobbles.utils import convert_to_seconds from videos.models import Video +from vrobbler.apps.music.aggregators import scrobble_counts, top_tracks, week_of_scrobbles logger = logging.getLogger(__name__) @@ -43,19 +44,26 @@ class RecentScrobbleList(ListView): def get_context_data(self, **kwargs): data = super().get_context_data(**kwargs) now = timezone.now() - last_three_minutes = timezone.now() - timedelta(minutes=3) + last_eight_minutes = timezone.now() - timedelta(minutes=8) # Find scrobbles from the last 10 minutes data['now_playing_list'] = Scrobble.objects.filter( in_progress=True, - timestamp__gte=last_three_minutes, + is_paused=False, + timestamp__gte=last_eight_minutes, timestamp__lte=now, ) + data['video_scrobble_list'] = Scrobble.objects.filter(video__isnull=False, in_progress=False).order_by('-timestamp')[:10] + data['top_daily_tracks'] = top_tracks() + data['top_weekly_tracks'] = top_tracks(filter='week') + data['top_monthly_tracks'] = top_tracks(filter='month') + data["weekly_data"] = week_of_scrobbles() + data['counts'] = scrobble_counts() return data def get_queryset(self): - return Scrobble.objects.filter(in_progress=False).order_by( + return Scrobble.objects.filter(track__isnull=False, in_progress=False).order_by( '-timestamp' - ) + )[:25] @csrf_exempt diff --git a/vrobbler/settings.py b/vrobbler/settings.py index bb4f415..a15e814 100644 --- a/vrobbler/settings.py +++ b/vrobbler/settings.py @@ -89,6 +89,7 @@ INSTALLED_APPS = [ "rest_framework", "allauth", "allauth.account", + "allauth.socialaccount", "django_celery_results", ] diff --git a/vrobbler/templates/base.html b/vrobbler/templates/base.html index 9b709ba..ea40008 100644 --- a/vrobbler/templates/base.html +++ b/vrobbler/templates/base.html @@ -1,4 +1,5 @@ {% load static %} +{% load humanize %} @@ -7,11 +8,10 @@ - + + - - {% block head_extra %}{% endblock %} - - - - -
- + -

{% block title %}{% endblock %}

+
+
+ -
{% block content %} {% endblock %}
+ {% block extra_js %} + + + {% endblock %} diff --git a/vrobbler/templates/scrobbles/scrobble_list.html b/vrobbler/templates/scrobbles/scrobble_list.html index f670cdc..9228023 100644 --- a/vrobbler/templates/scrobbles/scrobble_list.html +++ b/vrobbler/templates/scrobbles/scrobble_list.html @@ -1,50 +1,99 @@ {% extends "base.html" %} - {% load humanize %} -{% block title %}{% endblock %} {% block content %} - {% if now_playing_list %} -

Now playing

- {% for scrobble in now_playing_list %} - {% if scrobble.video %} -
-
{{scrobble.video.title}} - {{scrobble.video}}
-
- Started {{scrobble.created|naturaltime}} from {{scrobble.source}} +
+
+

Dashboard

+
+
+ + +
+ +
+
-
- -
-
-
- {% endif %} - {% if scrobble.track %} -
-
{{scrobble.track.title}} by {{scrobble.track.artist}} from {{scrobble.track.album}}
-
- Started {{scrobble.created|naturaltime}} from {{scrobble.source}} -
- -
-
-
- {% endif %} -
- {% endfor %} - {% endif %} -

Last scrobbles

- + + + +

Top this week

+
+ + + + + + + + + + + {% for track in top_weekly_tracks %} + + + + + + + {% endfor %} + +
#TrackArtistAlbum
{{track.num_scrobbles}}{{track.title}}{{track.artist.name}}{{track.album.name}}
+
+ +

Latest scrobbles

+

Today {{counts.today}} | This Week {{counts.week}} | This Month {{counts.month}} | This Year {{counts.year}} | All Time {{counts.alltime}}

+
+ + + + + + + + + + + {% for scrobble in object_list %} + + + + + + + {% endfor %} + +
TimeTrackArtistSource
{{scrobble.timestamp|naturaltime}}{{scrobble.track.title}}{{scrobble.track.artist.name}}{{scrobble.source}}
+
+ +

Latest watched

+
+ + + + + + + + + + + + {% for scrobble in video_scrobble_list %} + + + + + + + + {% endfor %} + +
TimeTitleSeriesSeason & EpisodeSource
{{scrobble.timestamp|naturaltime}}{{scrobble.video.title}}{% if scrobble.video.tv_series %}{{scrobble.video.tv_series}}{% endif %}{% if scrobble.video.tv_series %}{{scrobble.video.season_number}}, {{scrobble.video.episode_number}}{% endif %}{{scrobble.source}}
+
+ {% endblock %}