From 2a254e28d0a2f334201483c6f49afd3524a8bc85 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Sun, 18 May 2025 23:20:47 -0400 Subject: [PATCH] [templates] Start redesigning the dashboard --- vrobbler/apps/scrobbles/models.py | 56 +++++++ vrobbler/apps/scrobbles/views.py | 76 ++------- .../templates/scrobbles/_last_scrobbles.html | 154 ++++++++++++++++-- 3 files changed, 207 insertions(+), 79 deletions(-) diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index d206900..50b99e4 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -2,6 +2,7 @@ import calendar import datetime import json import logging +from collections import defaultdict from typing import Optional from uuid import uuid4 @@ -514,6 +515,10 @@ class Scrobble(TimeStampedModel): MOOD = "Mood", "Mood" BRICKSET = "BrickSet", "Brick set" + @classmethod + def list(cls): + return list(map(lambda c: c.value, cls)) + uuid = models.UUIDField(editable=False, **BNULL) video = models.ForeignKey(Video, on_delete=models.DO_NOTHING, **BNULL) track = models.ForeignKey(Track, on_delete=models.DO_NOTHING, **BNULL) @@ -597,6 +602,57 @@ class Scrobble(TimeStampedModel): long_play_seconds = models.BigIntegerField(**BNULL) long_play_complete = models.BooleanField(**BNULL) + @classmethod + def for_year(cls, user, year): + return cls.objects.filter(timestamp__year=year, user=user) + + @classmethod + def for_month(cls, user, year, month): + return cls.objects.filter( + timestamp__year=year, timestamp__month=month, user=user + ) + + @classmethod + def for_day(cls, user, year, day, month): + return cls.objects.filter( + timestamp__year=year, + timestamp__month=month, + timestamp__day=day, + user=user, + ) + + @classmethod + def for_day_dict( + cls, user_id: int, year: int, month: int, day: int + ) -> dict: + scrobbles_by_type = defaultdict(list) + scrobbles = cls.objects.filter( + timestamp__year=year, + timestamp__month=month, + timestamp__day=day, + user_id=user_id, + ).order_by("-timestamp") + + for scrobble in scrobbles: + scrobbles_by_type[scrobble.media_type].append(scrobble) + + return scrobbles_by_type + + @classmethod + def for_week(cls, user, year, week): + return cls.objects.filter( + timestamp__year=year, timestamp__week=week, user=user + ) + + @classmethod + def in_progress_for_user(cls, user_id: int) -> models.QuerySet: + return cls.objects.filter( + user=user_id, + in_progress=True, + played_to_completion=False, + is_paused=False, + ) + @property def last_serial_scrobble(self) -> Optional["Scrobble"]: from scrobbles.models import Scrobble diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index 3c6434b..0391642 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -3,9 +3,9 @@ import json import logging from datetime import datetime, timedelta +import pendulum import pytz from django.apps import apps -from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.db.models import Count, Q @@ -52,7 +52,6 @@ from scrobbles.tasks import ( from scrobbles.utils import ( get_long_plays_completed, get_long_plays_in_progress, - get_recently_played_board_games, ) logger = logging.getLogger(__name__) @@ -107,32 +106,19 @@ class RecentScrobbleList(ListView): def get_context_data(self, **kwargs): data = super().get_context_data(**kwargs) user = self.request.user + data["date"] = "" if user.is_authenticated: + date = self.request.GET.get("date", "") + today = timezone.localtime(timezone.now()) + user_id = self.request.user.id + year = today.year + month = today.month + day = today.day + if date: + year, month, day = date.split("-") + data["date"] = pendulum.parse(date) - completed_for_user = Scrobble.objects.filter( - played_to_completion=True, user=user - ) - data["long_play_in_progress"] = get_long_plays_in_progress(user) - data["play_again"] = get_recently_played_board_games(user) - data["video_scrobble_list"] = completed_for_user.filter( - video__isnull=False - ).order_by("-timestamp")[:15] - - 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["videogame_scrobble_list"] = completed_for_user.filter( - video_game__isnull=False - ).order_by("-timestamp")[:15] - - data["boardgame_scrobble_list"] = completed_for_user.filter( - board_game__isnull=False - ).order_by("-timestamp")[:15] + data = data | Scrobble.for_day_dict(user_id, year, month, day) data["active_imports"] = AudioScrobblerTSVImport.objects.filter( processing_started__isnull=False, @@ -698,45 +684,13 @@ class ChartRecordView(TemplateView): media_type = self.request.GET.get("media", "Track") user = self.request.user params = {} + context_data["chart_type"] = self.request.GET.get( + "chart_type", "maloja" + ) context_data["artist_charts"] = {} if not date: limit = 20 - artist_params = {"user": user, "media_type": "Artist"} - context_data["current_artist_charts"] = { - "today": live_charts( - **artist_params, chart_period="today", limit=limit - ), - "week": live_charts( - **artist_params, chart_period="week", limit=limit - ), - "month": live_charts( - **artist_params, chart_period="month", limit=limit - ), - "year": live_charts( - **artist_params, chart_period="year", limit=limit - ), - "all": live_charts(**artist_params, limit=limit), - } - - track_params = {"user": user, "media_type": "Track"} - context_data["current_track_charts"] = { - "today": live_charts( - **track_params, chart_period="today", limit=limit - ), - "week": live_charts( - **track_params, chart_period="week", limit=limit - ), - "month": live_charts( - **track_params, chart_period="month", limit=limit - ), - "year": live_charts( - **track_params, chart_period="year", limit=limit - ), - "all": live_charts(**track_params, limit=limit), - } - - limit = 14 artist = {"user": user, "media_type": "Artist", "limit": limit} # This is weird. They don't display properly as QuerySets, so we cast to lists context_data["chart_keys"] = { diff --git a/vrobbler/templates/scrobbles/_last_scrobbles.html b/vrobbler/templates/scrobbles/_last_scrobbles.html index 4ea2041..55392c6 100644 --- a/vrobbler/templates/scrobbles/_last_scrobbles.html +++ b/vrobbler/templates/scrobbles/_last_scrobbles.html @@ -1,7 +1,6 @@ {% load humanize %} {% load naturalduration %}
-

Last Scrobbles

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

@@ -30,6 +29,22 @@ + + + +
@@ -46,9 +61,10 @@ - {% for scrobble in object_list %} + {{Track|length}} + {% for scrobble in Track %} - {{scrobble.timestamp|naturaltime}} + {% if scrobble.in_progress %}Listening now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %} {% if scrobble.track.album.cover_image %} {% else %} @@ -65,7 +81,6 @@
-

Latest watched

@@ -77,9 +92,9 @@ - {% for scrobble in video_scrobble_list %} + {% for scrobble in Video %} - + {% if scrobble.video.cover_image %} {% else %} @@ -105,15 +120,17 @@ + - {% for scrobble in sport_scrobble_list %} + {% for scrobble in SportEvent %} - + + {% endfor %} @@ -123,7 +140,6 @@
-

Latest Podcasted

{{scrobble.timestamp|naturaltime}}{% if scrobble.in_progress %}Watching now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}Title Round LeagueTime watched
{{scrobble.timestamp|naturaltime}}{% if scrobble.in_progress %}Watching now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %} {{scrobble.sport_event.title}} {{scrobble.sport_event.round.name}} {{scrobble.sport_event.round.season.league}}{{scrobble.playback_position_seconds|natural_duration}}
@@ -134,8 +150,9 @@ - {% for scrobble in podcast_scrobble_list %} + {% for scrobble in PodcastEpisode %} + @@ -148,7 +165,6 @@
-

Latest Video Games

{% if scrobble.in_progress %}Listening now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %} {{scrobble.timestamp|naturaltime}} {{scrobble.podcast_episode.title}} {{scrobble.podcast_episode.podcast}}
@@ -156,14 +172,14 @@ - + - {% for scrobble in videogame_scrobble_list %} + {% for scrobble in VideoGame %} - + {% if scrobble.screenshot %} {% else %} @@ -184,7 +200,6 @@
-

Latest Board Games

Date Cover/Screenshot TitleTime played (mins)Time played Percent complete
{{scrobble.timestamp|naturaltime}}{% if scrobble.in_progress %}Sessioning now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}
@@ -192,13 +207,13 @@ - + - {% for scrobble in boardgame_scrobble_list %} + {% for scrobble in BoardGame %} - + @@ -208,5 +223,108 @@
Date Cover TitleTime played (mins)Time played
{{scrobble.timestamp|naturaltime}}{% if scrobble.in_progress %}Tabling now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %} {{scrobble.media_obj.title}} {{scrobble.playback_position_seconds|natural_duration}}
+ +
+
+ + + + + + + + + + + {% for scrobble in WebPage %} + + + + + + + {% endfor %} + +
DateCoverTitleTime browsing
{% if scrobble.in_progress %}Browsing now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.playback_position_seconds|natural_duration}}
+
+
+ +
+
+ + + + + + + + + + + {% for scrobble in Beer %} + + + + + + + {% endfor %} + +
DateCoverTitleTime drinking
{% if scrobble.in_progress %}Drinking now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.playback_position_seconds|natural_duration}}
+
+
+ +
+
+ + + + + + + + + + + {% for scrobble in Book %} + + + + + + + {% endfor %} + +
DateCoverTitleTime reading
{% if scrobble.in_progress %}Reading now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.playback_position_seconds|natural_duration}}
+
+
+ +
+
+ + + + + + + + + + {% for scrobble in Task %} + + + + + + {% endfor %} + +
DateTitleTime doing
{% if scrobble.in_progress %}Doing now{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.playback_position_seconds|natural_duration}}
+
+
+