diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index b5adee3..8a49a90 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -604,45 +604,39 @@ class Scrobble(TimeStampedModel): @classmethod def for_year(cls, user, year): - return cls.objects.filter(timestamp__year=year, user=user) + return cls.objects.filter(timestamp__year=year, user=user).order_by( + "-timestamp" + ) @classmethod def for_month(cls, user, year, month): return cls.objects.filter( timestamp__year=year, timestamp__month=month, user=user - ) + ).order_by("-timestamp") @classmethod - def for_day(cls, user, year, day, month): + def for_day(cls, user, year, month, day): 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 - ) + ).order_by("-timestamp") + + @classmethod + def as_dict_by_type(cls, scrobble_qs: models.QuerySet) -> dict: + scrobbles_by_type = defaultdict(list) + + for scrobble in scrobble_qs: + scrobbles_by_type[scrobble.media_type].append(scrobble) + + return scrobbles_by_type @classmethod def in_progress_for_user(cls, user_id: int) -> models.QuerySet: @@ -847,7 +841,10 @@ class Scrobble(TimeStampedModel): @property def elapsed_time(self) -> int | None: if self.played_to_completion: - return self.playback_position_seconds + if self.playback_position_seconds: + return self.playback_position_seconds + if self.media_obj.run_time_seconds: + return self.media_obj.run_time_seconds return (timezone.now() - self.timestamp).seconds @property diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index be54607..48d16c5 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -2,9 +2,9 @@ import calendar import json import logging from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta import pendulum -from pendulum.parsing.exceptions import ParserError import pytz from django.apps import apps from django.contrib import messages @@ -109,20 +109,92 @@ class RecentScrobbleList(ListView): user = self.request.user data["date"] = "" if user.is_authenticated: - date = self.request.GET.get("date", "") - today = timezone.localtime(timezone.now()) + self.queryset = self.get_queryset().filter(user=user) user_id = self.request.user.id - year = today.year - month = today.month - day = today.day - if date: + + today = timezone.localtime(timezone.now()) + date_str = self.request.GET.get("date", "") + date = today + if date_str: try: - data["date"] = pendulum.parse(date) - year, month, day = date.split("-") + date = pendulum.parse(date_str) except: pass - - data = data | Scrobble.for_day_dict(user_id, year, month, day) + if date_str: + if date_str == "this_week" or "-W" in date_str: + next_date = date + timedelta(weeks=+2) + prev_date = date + timedelta(weeks=-1) + if date.isocalendar()[1] < today.isocalendar()[1]: + data[ + "next_link" + ] = f"?date={next_date.strftime('%Y-W%W')}" + data["prev_link"] = f"?date={prev_date.strftime('%Y-W%W')}" + data[ + "title" + ] = f"Week {date.strftime('%-W')} of {date.year}" + data = data | Scrobble.as_dict_by_type( + Scrobble.for_week( + user_id, date.year, date.isocalendar()[1] + ) + ) + elif date_str == "this_month" or date_str.count("-") == 1: + next_date = date + relativedelta(months=1) + prev_date = date + relativedelta(months=-1) + if date.month < today.month: + data[ + "next_link" + ] = f"?date={next_date.strftime('%Y-%m')}" + data["title"] = f"{date.strftime('%B %Y')}" + data["prev_link"] = f"?date={prev_date.strftime('%Y-%m')}" + data = data | Scrobble.as_dict_by_type( + Scrobble.for_month(user_id, date.year, date.month) + ) + elif date_str == "today" or date_str.count("-") == 2: + next_date = date + timedelta(days=1) + prev_date = date - timedelta(days=1) + data[ + "prev_link" + ] = f"?date={prev_date.strftime('%Y-%m-%d')}" + if date < today: + data[ + "next_link" + ] = f"?date={next_date.strftime('%Y-%m-%d')}" + if date == today: + data["title"] = "Today" + else: + data["title"] = f"{date.strftime('%Y-%m-%d')}" + data[ + "today_link" + ] = f"?date={today.strftime('%Y-%m-%d')}" + data = data | Scrobble.as_dict_by_type( + Scrobble.for_day( + user_id, date.year, date.month, date.day + ) + ) + elif date_str == "this_year" or date_str.count("-") == 0: + next_date = date + relativedelta(years=+1) + prev_date = date + relativedelta(years=-1) + data["next_link"] = "" + if date.year < today.year: + data["title"] = f"{date.strftime('%Y')}" + data["next_link"] = f"?date={next_date.year}" + data["title"] = f"{date.year}" + data["prev_link"] = f"?date={prev_date.year}" + data = data | Scrobble.as_dict_by_type( + Scrobble.for_year(user_id, date.year) + ) + else: + next_date = today - timedelta(days=1) + prev_date = today - timedelta(days=1) + data["title"] = "Today" + data["next_link"] = "" + data["prev_link"] = f"?date={prev_date.strftime('%Y-%m-%d')}" + data = data | Scrobble.as_dict_by_type( + Scrobble.for_day(user_id, date.year, date.month, date.day) + ) + data[ + "today_link" + ] = "" # f"?date={today.strftime('%Y-%m-%d')}" data["active_imports"] = AudioScrobblerTSVImport.objects.filter( processing_started__isnull=False, @@ -139,9 +211,7 @@ class RecentScrobbleList(ListView): return data def get_queryset(self): - return Scrobble.objects.filter( - track__isnull=False, in_progress=False - ).order_by("-timestamp")[:15] + return Scrobble.objects.all().order_by("-timestamp") class ScrobbleLongPlaysView(TemplateView): @@ -453,6 +523,7 @@ def gps_webhook(request): return Response({"scrobble_id": scrobble.id}, status=status.HTTP_200_OK) + @csrf_exempt @api_view(["POST"]) def emacs_webhook(request): @@ -474,9 +545,9 @@ def emacs_webhook(request): if request.user.id: user_id = request.user.id - #scrobble = gpslogger_scrobble_location(data_dict, user_id) + # scrobble = gpslogger_scrobble_location(data_dict, user_id) - #if not scrobble: + # if not scrobble: # return Response({}, status=status.HTTP_200_OK) return Response({"post_data": post_data}, status=status.HTTP_200_OK) diff --git a/vrobbler/templates/scrobbles/_last_scrobbles.html b/vrobbler/templates/scrobbles/_last_scrobbles.html index f326b41..fe50ae8 100644 --- a/vrobbler/templates/scrobbles/_last_scrobbles.html +++ b/vrobbler/templates/scrobbles/_last_scrobbles.html @@ -1,305 +1,82 @@ {% load humanize %} {% load naturalduration %} -
-

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

+
+
+

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

+
- +
{% if Track %} -
-
- - - - - - - - - - - {{Track|length}} - {% for scrobble in Track %} - - - {% if scrobble.track.album.cover_image %} - - {% else %} - - {% endif %} - - - - {% endfor %} - -
TimeAlbumTrackArtist
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.track.album.name}}{{scrobble.track.title}}{{scrobble.track.artist.name}}
-
-
+

Music

+ {% with scrobbles=Track %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} + {% endif %} +
+
+ + {% if Task %} +

Latest tasks

+ {% with scrobbles=Task %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} {% endif %} {% if Video %} -
-
- - - - - - - - - - - {% for scrobble in Video %} - - - {% if scrobble.video.cover_image %} - - {% else %} - - {% endif %} - - - - {% endfor %} - -
TimeCoverTitleSeries
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{% if scrobble.video.tv_series%}S{{scrobble.video.season_number}}E{{scrobble.video.episode_number}} -{%endif %} {{scrobble.video.title}}{% if scrobble.video.tv_series %}{{scrobble.video.tv_series}}{% endif %} -
-
-
- {% endif %} - - {% if SportEvent %} -
-

Latest Sports

-
- - - - - - - - - - - - {% for scrobble in SportEvent %} - - - - - - - - {% endfor %} - -
DateTitleRoundLeagueTime watched
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.sport_event.title}}{{scrobble.sport_event.round.name}}{{scrobble.sport_event.round.season.league}}{{scrobble.elapsed_time|natural_duration}}
-
-
- {% endif %} - - {% if PodcastEpisode %} -
-
- - - - - - - - - - {% for scrobble in PodcastEpisode %} - - - - - - - {% endfor %} - -
DateTitlePodcast
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.timestamp|naturaltime}}{{scrobble.podcast_episode.title}}{{scrobble.podcast_episode.podcast}}
-
-
- {% endif %} - - {% if VideoGame %} -

Video games

-
-
- - - - - - - - - - - - {% for scrobble in VideoGame %} - - - {% if scrobble.media_obj.hltb_cover %} - - {% endif %} - - - - - {% endfor %} - -
DateCoverTitleTime playedPercent complete
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.elapsed_time|natural_duration}}{{scrobble.percent_played}}
-
-
- {% endif %} - - - {% if BoardGame %} -

Board games

-
-
- - - - - - - - - - - {% for scrobble in BoardGame %} - - - - - - - {% endfor %} - -
DateCoverTitleTime played
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.elapsed_time|natural_duration}}
-
-
+

Videos

+ {% with scrobbles=Video %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} {% endif %} {% if WebPage %}

Web pages

-
-
- - - - - - - - - - {% for scrobble in WebPage %} - - - - - - {% endfor %} - -
DateTitleTime browsing
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.elapsed_time|natural_duration}}
-
-
+ {% with scrobbles=WebPage %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} + {% endif %} + + {% if SportEvent %} +

Sports

+ {% with scrobbles=SportEvent %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} + {% endif %} + + {% if PodcastEpisode %} +

Latest podcasts

+ {% with scrobbles=PodcastEpisode %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} + {% endif %} + + {% if VideoGame %} +

Video games

+ {% with scrobbles=VideoGame %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} + {% endif %} + + {% if BoardGame %} +

Board games

+ {% with scrobbles=BoardGame %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} {% endif %} {% if Beer %}

Beers

-
-
- - - - - - - - - - - {% for scrobble in Beer %} - - - - - - - {% endfor %} - -
DateCoverTitleTime drinking
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.elapsed_time|natural_duration}}
-
-
+ {% with scrobbles=Beer %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} {% endif %} {% if Book %}

Books

-
-
- - - - - - - - - - - {% for scrobble in Book %} - - - - - - - {% endfor %} - -
DateCoverTitleTime reading
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.elapsed_time|natural_duration}}
-
-
- {% endif %} - - {% if Task %} -
-
- - - - - - - - - - {% for scrobble in Task %} - - - - - - {% endfor %} - -
DateTitleTime doing
{% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %}{{scrobble.media_obj.title}}{{scrobble.elapsed_time|natural_duration}}
-
-
+ {% with scrobbles=Book %} + {% include "scrobbles/_scrobble_table.html" %} + {% endwith %} {% endif %}
diff --git a/vrobbler/templates/scrobbles/_row.html b/vrobbler/templates/scrobbles/_row.html new file mode 100644 index 0000000..54a1fda --- /dev/null +++ b/vrobbler/templates/scrobbles/_row.html @@ -0,0 +1,7 @@ +{% load humanize %} +{% load naturalduration %} + + {% if scrobble.in_progress %}{{scrobble.media_obj.strings.verb}} now | Finish{% else %}{{scrobble.timestamp|naturaltime}}{% endif %} + {{scrobble.media_obj|truncatechars_html:50}} + {{scrobble.elapsed_time|natural_duration}} + diff --git a/vrobbler/templates/scrobbles/_scrobble_table.html b/vrobbler/templates/scrobbles/_scrobble_table.html new file mode 100644 index 0000000..42f3f3b --- /dev/null +++ b/vrobbler/templates/scrobbles/_scrobble_table.html @@ -0,0 +1,22 @@ +{% load humanize %} +{% load naturalduration %} + +
+
+ + + + + + + + + + {% for scrobble in scrobbles %} + {% include "scrobbles/_row.html" %} + {% endfor %} + +
DateTitleTime
+
+
diff --git a/vrobbler/templates/scrobbles/scrobble_list.html b/vrobbler/templates/scrobbles/scrobble_list.html index 80f941b..db3b8e5 100644 --- a/vrobbler/templates/scrobbles/scrobble_list.html +++ b/vrobbler/templates/scrobbles/scrobble_list.html @@ -49,9 +49,28 @@
-

{% if date %}{{date|naturaltime}}{% else %}Today{% endif %}

+

{% if date %}{{date|naturaltime}}{% else %}{{title}}{% endif %}

{% if user.is_authenticated %} +
+ {% if user.profile.lastfm_username and not user.profile.lastfm_auto_import %} +
+ +
+ {% endif %} + {% if prev_link %} + Previous + {% endif %} + {% if today_link %} + Today + {% endif %} + {% if next_link %} + Next + {% endif %} +
{% if user.profile.lastfm_username and not user.profile.lastfm_auto_import %} @@ -69,11 +88,13 @@