Fix chart display

This commit is contained in:
2023-02-28 01:58:22 -05:00
parent f76aaf6a9c
commit a99dca246b
6 changed files with 214 additions and 142 deletions

View File

@ -1,6 +1,8 @@
from django.db.models import Count from datetime import timedelta
from django.utils import timezone
from django.views import generic from django.views import generic
from music.models import Track, Artist, Album from music.models import Album, Artist, Track
from scrobbles.models import ChartRecord
from scrobbles.stats import get_scrobble_count_qs from scrobbles.stats import get_scrobble_count_qs
@ -17,6 +19,14 @@ class TrackDetailView(generic.DetailView):
model = Track model = Track
slug_field = 'uuid' slug_field = 'uuid'
def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs)
context_data['charts'] = ChartRecord.objects.filter(
track=self.object, rank__in=[1, 2, 3]
)
return context_data
class ArtistListView(generic.ListView): class ArtistListView(generic.ListView):
model = Artist model = Artist
@ -29,6 +39,13 @@ class ArtistDetailView(generic.DetailView):
model = Artist model = Artist
slug_field = 'uuid' slug_field = 'uuid'
def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs)
context_data['charts'] = ChartRecord.objects.filter(
artist=self.object, rank__in=[1, 2, 3]
)
return context_data
class AlbumListView(generic.ListView): class AlbumListView(generic.ListView):
model = Album model = Album

View File

@ -312,7 +312,22 @@ class ChartRecord(TimeStampedModel):
return period return period
def __str__(self): def __str__(self):
return f"#{self.rank} in {self.period} - {self.media_obj}" title = f"#{self.rank} in {self.period}"
if self.day or self.week:
title = f"#{self.rank} on {self.period}"
return title
def link(self):
get_params = f"?date={self.year}"
if self.week:
get_params = get_params = get_params + f"-W{self.week}"
if self.month:
get_params = get_params = get_params + f"-{self.month}"
if self.day:
get_params = get_params = get_params + f"-{self.day}"
if self.artist:
get_params = get_params + "&media=Artist"
return reverse('scrobbles:charts-home') + get_params
@classmethod @classmethod
def build(cls, user, **kwargs): def build(cls, user, **kwargs):

View File

@ -2,7 +2,6 @@ import calendar
import json import json
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from django.db.models.query import QuerySet
import pytz import pytz
from django.conf import settings from django.conf import settings
@ -10,6 +9,7 @@ from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q from django.db.models import Q
from django.db.models.fields import timezone from django.db.models.fields import timezone
from django.db.models.query import QuerySet
from django.http import FileResponse, HttpResponseRedirect, JsonResponse from django.http import FileResponse, HttpResponseRedirect, JsonResponse
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils import timezone from django.utils import timezone
@ -17,12 +17,7 @@ from django.views.decorators.csrf import csrf_exempt
from django.views.generic import DetailView, FormView, TemplateView from django.views.generic import DetailView, FormView, TemplateView
from django.views.generic.edit import CreateView from django.views.generic.edit import CreateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from music.aggregators import ( from music.aggregators import scrobble_counts, week_of_scrobbles
scrobble_counts,
top_artists,
top_tracks,
week_of_scrobbles,
)
from rest_framework import status from rest_framework import status
from rest_framework.decorators import ( from rest_framework.decorators import (
api_view, api_view,
@ -62,6 +57,8 @@ from scrobbles.tasks import (
) )
from scrobbles.thesportsdb import lookup_event_from_thesportsdb from scrobbles.thesportsdb import lookup_event_from_thesportsdb
from vrobbler.apps.music.aggregators import live_charts
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -406,19 +403,17 @@ class ChartRecordView(TemplateView):
template_name = 'scrobbles/chart_index.html' template_name = 'scrobbles/chart_index.html'
@staticmethod @staticmethod
def get_media_filter(media_type: str = "Track"): def get_media_filter(media_type: str = "") -> Q:
media_filter = Q() filters = {
if media_type == 'Track': "Track": Q(track__isnull=False),
media_filter = Q(track__isnull=False) "Artist": Q(artist__isnull=False),
if media_type == 'Artist': "Series": Q(series__isnull=False),
media_filter = Q(artist__isnull=False) "Video": Q(video__isnull=False),
if media_type == 'Series': "": Q(),
media_filter = Q(series__isnull=False) }
if media_type == 'Video': return filters[media_type]
media_filter = Q(video__isnull=False)
return media_filter
def get_chart_records(self, media_type: str = "Track", **kwargs): def get_chart_records(self, media_type: str = "", **kwargs):
media_filter = self.get_media_filter(media_type) media_filter = self.get_media_filter(media_type)
charts = ChartRecord.objects.filter( charts = ChartRecord.objects.filter(
media_filter, user=self.request.user, **kwargs media_filter, user=self.request.user, **kwargs
@ -434,37 +429,24 @@ class ChartRecordView(TemplateView):
return charts return charts
def get_chart( def get_chart(
self, period: str = "all_time", limit=15, media: str = "Track" self, period: str = "all_time", limit=15, media: str = ""
) -> QuerySet: ) -> QuerySet:
chart = QuerySet()
now = timezone.now() now = timezone.now()
if period == "all_time": params = {}
chart = self.get_chart_records(media_type=media) params['media_type'] = media
if period == "today": if period == "today":
chart = self.get_chart_records( params['day'] = now.day
media_type=media, params['month'] = now.month
day=now.day, params['year'] = now.year
month=now.month,
year=now.year,
)
if period == "week": if period == "week":
chart = self.get_chart_records( params['week'] = now.ioscalendar()[1]
media_type=media, params['year'] = now.year
year=now.year,
week=now.isocalendar()[1],
)
if period == "month": if period == "month":
chart = self.get_chart_records( params['month'] = now.month
media_type=media, params['year'] = now.year
year=now.year,
month=now.month,
)
if period == "year": if period == "year":
chart = self.get_chart_records( params['year'] = now.year
media_type=media, return self.get_chart_records(**params)[:limit]
year=now.year,
)
return chart[:limit]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context_data = super().get_context_data(**kwargs) context_data = super().get_context_data(**kwargs)
@ -475,21 +457,24 @@ class ChartRecordView(TemplateView):
context_data["artist_charts"] = {} context_data["artist_charts"] = {}
if not date: if not date:
artist_params = {'user': user, 'media_type': 'Artist'}
context_data['artist_charts'] = { context_data['artist_charts'] = {
"today": top_artists(user, filter="today")[:30], "today": live_charts(**artist_params, chart_period="today"),
"week": top_artists(user, filter="week")[:30], "week": live_charts(**artist_params, chart_period="week"),
"month": top_artists(user, filter="month")[:30], "month": live_charts(**artist_params, chart_period="month"),
"all": top_artists(user), "all": live_charts(**artist_params),
} }
track_params = {'user': user, 'media_type': 'Track'}
context_data['track_charts'] = { context_data['track_charts'] = {
"today": top_tracks(user, filter="today")[:30], "today": live_charts(**track_params, chart_period="today"),
"week": top_tracks(user, filter="week")[:30], "week": live_charts(**track_params, chart_period="week"),
"month": top_tracks(user, filter="month")[:30], "month": live_charts(**track_params, chart_period="month"),
"all": top_tracks(user), "all": live_charts(**track_params),
} }
return context_data return context_data
# Date provided, lookup past charts, returning nothing if it's now or in the future.
now = timezone.now() now = timezone.now()
year = now.year year = now.year
params = {'year': year} params = {'year': year}
@ -531,7 +516,7 @@ class ChartRecordView(TemplateView):
media_filter, user=self.request.user, **params media_filter, user=self.request.user, **params
).order_by("rank") ).order_by("rank")
if charts.count() == 0: if charts.count() == 0 and not in_progress:
ChartRecord.build( ChartRecord.build(
user=self.request.user, model_str=media_type, **params user=self.request.user, model_str=media_type, **params
) )
@ -539,11 +524,8 @@ class ChartRecordView(TemplateView):
media_filter, user=self.request.user, **params media_filter, user=self.request.user, **params
).order_by("rank") ).order_by("rank")
if in_progress: context_data['media_type'] = media_type
# TODO recalculate
...
context_data['charts'] = charts context_data['charts'] = charts
context_data['name'] = name context_data['name'] = " ".join(["Top", media_type, "for", name])
context_data['in_progress'] = in_progress context_data['in_progress'] = in_progress
return context_data return context_data

View File

@ -14,6 +14,9 @@
</div> </div>
<div class="row"> <div class="row">
<p>{{artist.scrobbles.count}} scrobbles</p> <p>{{artist.scrobbles.count}} scrobbles</p>
{% if charts %}
<p>{% for chart in charts %}<em><a href="{{chart.link}}">{{chart}}</a></em>{% if forloop.last %}{% else %} | {% endif %}{% endfor %}</p>
{% endif %}
<div class="col-md"> <div class="col-md">
<h3>Top tracks</h3> <h3>Top tracks</h3>
<div class="table-responsive"> <div class="table-responsive">

View File

@ -1,13 +1,41 @@
{% extends "base_detail.html" %} {% extends "base_list.html" %}
{% block title %}{{object.title}}{% endblock %} {% block title %}{{object.title}}{% endblock %}
{% block details %} {% block lists %}
<h2>Last scrobbles</h2> <div class="row">
{% for scrobble in object.scrobble_set.all %} {% if track.album.cover_image %}
<ul> <p style="width:150px; float:left;"><img src="{{track.album.cover_image.url}}" width=150 height=150 /></p>
<li>{{scrobble.timestamp|date:"d M Y h:m"}} - <img src="{{object.album.cover_image.url}}" width=25 height=25 /> - {{object}}</li> {% endif %}
</ul> </div>
{% endfor %} <div class="row">
<p>{{object.scrobble_set.count}} scrobbles</p>
{% if charts %}
<p>{% for chart in charts %}<em><a href="{{chart.link}}">{{chart}}</a></em>{% if forloop.last %}{% else %} | {% endif %}{% endfor %}</p>
{% endif %}
<div class="col-md">
<h3>Last scrobbles</h3>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Date</th>
<th scope="col">Track</th>
<th scope="col">Album</th>
</tr>
</thead>
<tbody>
{% for scrobble in object.scrobble_set.all %}
<tr>
<td>{{scrobble.timestamp}}</td>
<td>{{scrobble.track.title}}</td>
<td>{{scrobble.track.album.name}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -5,6 +5,30 @@
{% block lists %} {% block lists %}
<div class="row"> <div class="row">
{% if charts %} {% if charts %}
{% if "Artist" in name %}
<div class="tab-content" id="artistTabContent">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Rank</th>
<th scope="col">Artist</th>
<th scope="col">Scrobbles</th>
</tr>
</thead>
<tbody>
{% for chart in charts %}
<tr>
<td>{{chart.rank}}</td>
<td><a href="{{chart.media_obj.get_absolute_url}}">{{chart.media_obj}}</a></td>
<td>{{chart.count}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% elif media_type == "Track" %}
<div class="tab-content" id="artistTabContent"> <div class="tab-content" id="artistTabContent">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-striped table-sm"> <table class="table table-striped table-sm">
@ -29,9 +53,13 @@
</table> </table>
</div> </div>
</div> </div>
{% elif "Video" in name %}
{% elif "Series" in name %}
{% endif %}
{% endif %} {% endif %}
{% if artist_charts %} {% if artist_charts %}
<div class="col-md">
<h2>Top Artists</h2> <h2>Top Artists</h2>
<ul class="nav nav-tabs" id="artistTab" role="tablist"> <ul class="nav nav-tabs" id="artistTab" role="tablist">
@ -71,10 +99,10 @@
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
</div> </div>
<div class="row">
{% if track_charts %} {% if track_charts %}
<div class="col-md">
<h2>Top Tracks</h2> <h2>Top Tracks</h2>
<ul class="nav nav-tabs" id="artistTab" role="tablist"> <ul class="nav nav-tabs" id="artistTab" role="tablist">
@ -96,18 +124,16 @@
<table class="table table-striped table-sm"> <table class="table table-striped table-sm">
<thead> <thead>
<tr> <tr>
<th scope="col">Rank</th>
<th scope="col">Artist</th>
<th scope="col">Track</th> <th scope="col">Track</th>
<th scope="col">Artist</th>
<th scope="col">Scrobbles</th> <th scope="col">Scrobbles</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for track in tracks %} {% for track in tracks %}
<tr> <tr>
<td>{{track.rank}}</td>
<td><a href="{{track.artist.get_absolute_url}}">{{track.artist}}</a></td>
<td><a href="{{track.get_absolute_url}}">{{track.title}}</a></td> <td><a href="{{track.get_absolute_url}}">{{track.title}}</a></td>
<td><a href="{{track.artist.get_absolute_url}}">{{track.artist}}</a></td>
<td>{{track.num_scrobbles}}</td> <td>{{track.num_scrobbles}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -117,6 +143,7 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div>
{% endif %} {% endif %}
</div> </div>