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 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
@ -17,6 +19,14 @@ class TrackDetailView(generic.DetailView):
model = Track
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):
model = Artist
@ -29,6 +39,13 @@ class ArtistDetailView(generic.DetailView):
model = Artist
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):
model = Album

View File

@ -312,7 +312,22 @@ class ChartRecord(TimeStampedModel):
return period
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
def build(cls, user, **kwargs):

View File

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

View File

@ -14,6 +14,9 @@
</div>
<div class="row">
<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">
<h3>Top tracks</h3>
<div class="table-responsive">

View File

@ -1,13 +1,41 @@
{% extends "base_detail.html" %}
{% extends "base_list.html" %}
{% block title %}{{object.title}}{% endblock %}
{% block details %}
<h2>Last scrobbles</h2>
{% for scrobble in object.scrobble_set.all %}
<ul>
<li>{{scrobble.timestamp|date:"d M Y h:m"}} - <img src="{{object.album.cover_image.url}}" width=25 height=25 /> - {{object}}</li>
</ul>
{% endfor %}
{% block lists %}
<div class="row">
{% if track.album.cover_image %}
<p style="width:150px; float:left;"><img src="{{track.album.cover_image.url}}" width=150 height=150 /></p>
{% endif %}
</div>
<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 %}

View File

@ -5,6 +5,30 @@
{% block lists %}
<div class="row">
{% 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="table-responsive">
<table class="table table-striped table-sm">
@ -29,93 +53,96 @@
</table>
</div>
</div>
{% elif "Video" in name %}
{% elif "Series" in name %}
{% endif %}
{% endif %}
{% if artist_charts %}
<h2>Top Artists</h2>
<div class="col-md">
<h2>Top Artists</h2>
<ul class="nav nav-tabs" id="artistTab" role="tablist">
{% for chart_name in artist_charts.keys %}
<li class="nav-item" role="presentation">
<button class="nav-link {% if forloop.first %}active{% endif %}" id="artist-{{chart_name}}-tab" data-bs-toggle="tab" data-bs-target="#artist-{{chart_name}}"
type="button" role="tab" aria-controls="home" aria-selected="true">
{{chart_name}}
</button>
</li>
{% endfor %}
</ul>
<ul class="nav nav-tabs" id="artistTab" role="tablist">
{% for chart_name in artist_charts.keys %}
<li class="nav-item" role="presentation">
<button class="nav-link {% if forloop.first %}active{% endif %}" id="artist-{{chart_name}}-tab" data-bs-toggle="tab" data-bs-target="#artist-{{chart_name}}"
type="button" role="tab" aria-controls="home" aria-selected="true">
{{chart_name}}
</button>
</li>
{% endfor %}
</ul>
<div class="tab-content" id="artistTabContent">
{% for chart_name, artists in artist_charts.items %}
<div class="tab-pane fade {% if forloop.first %}show active{% endif %}" id="artist-{{chart_name}}" role="tabpanel"
aria-labelledby="artist-{[chart}}-tab">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Artist</th>
<th scope="col">Scrobbles</th>
</tr>
</thead>
<tbody>
{% for artist in artists %}
<tr>
<td><a href="{{artist.get_absolute_url}}">{{artist}}</a></td>
<td>{{artist.num_scrobbles}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="tab-content" id="artistTabContent">
{% for chart_name, artists in artist_charts.items %}
<div class="tab-pane fade {% if forloop.first %}show active{% endif %}" id="artist-{{chart_name}}" role="tabpanel"
aria-labelledby="artist-{[chart}}-tab">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Artist</th>
<th scope="col">Scrobbles</th>
</tr>
</thead>
<tbody>
{% for artist in artists %}
<tr>
<td><a href="{{artist.get_absolute_url}}">{{artist}}</a></td>
<td>{{artist.num_scrobbles}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
{% endif %}
</div>
{% endif %}
</div>
<div class="row">
{% if track_charts %}
<h2>Top Tracks</h2>
<div class="col-md">
<h2>Top Tracks</h2>
<ul class="nav nav-tabs" id="artistTab" role="tablist">
{% for chart_name in track_charts.keys %}
<li class="nav-item" role="presentation">
<button class="nav-link {% if forloop.first %}active{% endif %}" id="track-{{chart_name}}-tab" data-bs-toggle="tab" data-bs-target="#track-{{chart_name}}"
type="button" role="tab" aria-controls="home" aria-selected="true">
{{chart_name}}
</button>
</li>
{% endfor %}
</ul>
<ul class="nav nav-tabs" id="artistTab" role="tablist">
{% for chart_name in track_charts.keys %}
<li class="nav-item" role="presentation">
<button class="nav-link {% if forloop.first %}active{% endif %}" id="track-{{chart_name}}-tab" data-bs-toggle="tab" data-bs-target="#track-{{chart_name}}"
type="button" role="tab" aria-controls="home" aria-selected="true">
{{chart_name}}
</button>
</li>
{% endfor %}
</ul>
<div class="tab-content" id="trackTabContent">
{% for chart_name, tracks in track_charts.items %}
<div class="tab-pane fade {% if forloop.first %}show active{% endif %}" id="track-{{chart_name}}" role="tabpanel"
aria-labelledby="track-{[chart_name}}-tab">
<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">Track</th>
<th scope="col">Scrobbles</th>
</tr>
</thead>
<tbody>
{% for track in tracks %}
<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>{{track.num_scrobbles}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="tab-content" id="trackTabContent">
{% for chart_name, tracks in track_charts.items %}
<div class="tab-pane fade {% if forloop.first %}show active{% endif %}" id="track-{{chart_name}}" role="tabpanel"
aria-labelledby="track-{[chart_name}}-tab">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Track</th>
<th scope="col">Artist</th>
<th scope="col">Scrobbles</th>
</tr>
</thead>
<tbody>
{% for track in tracks %}
<tr>
<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>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endif %}
</div>