[music] Tracks can have multiple artists
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
import csv
|
||||
import tempfile
|
||||
from scrobbles.models import Scrobble
|
||||
|
||||
from django.db.models import Q
|
||||
from scrobbles.models import Scrobble
|
||||
|
||||
|
||||
def export_scrobbles(start_date=None, end_date=None, format="AS"):
|
||||
|
||||
@ -564,7 +564,7 @@ class ScrobbleQuerySet(models.QuerySet):
|
||||
return self.select_related("user").prefetch_related(
|
||||
"video",
|
||||
"track",
|
||||
"track__artist",
|
||||
"track__artist_fk",
|
||||
"podcast_episode",
|
||||
"podcast_episode__podcast",
|
||||
"sport_event",
|
||||
|
||||
@ -226,7 +226,7 @@ class RecentScrobbleList(ListView):
|
||||
|
||||
# Get user's home scrobble limit (default 20)
|
||||
home_limit = 20
|
||||
if hasattr(user, 'profile') and user.profile.home_scrobble_limit:
|
||||
if hasattr(user, "profile") and user.profile.home_scrobble_limit:
|
||||
home_limit = user.profile.home_scrobble_limit
|
||||
|
||||
today = timezone.localtime(timezone.now())
|
||||
@ -612,9 +612,7 @@ class KoReaderImportCreateView(LoginRequiredMixin, JsonableResponseMixin, Create
|
||||
return HttpResponseRedirect(self.request.META.get("HTTP_REFERER"))
|
||||
|
||||
|
||||
class ScaleCSVImportCreateView(
|
||||
LoginRequiredMixin, JsonableResponseMixin, CreateView
|
||||
):
|
||||
class ScaleCSVImportCreateView(LoginRequiredMixin, JsonableResponseMixin, CreateView):
|
||||
model = ScaleCSVImport
|
||||
fields = ["csv_file"]
|
||||
template_name = "scrobbles/upload_form.html"
|
||||
@ -623,17 +621,13 @@ class ScaleCSVImportCreateView(
|
||||
def form_valid(self, form):
|
||||
self.object = form.save(commit=False)
|
||||
self.object.user = self.request.user
|
||||
self.object.original_filename = (
|
||||
form.cleaned_data["csv_file"].name
|
||||
)
|
||||
self.object.original_filename = form.cleaned_data["csv_file"].name
|
||||
self.object.save()
|
||||
self.object.process()
|
||||
return HttpResponseRedirect(self.request.META.get("HTTP_REFERER"))
|
||||
|
||||
|
||||
class TrailGPXImportCreateView(
|
||||
LoginRequiredMixin, JsonableResponseMixin, CreateView
|
||||
):
|
||||
class TrailGPXImportCreateView(LoginRequiredMixin, JsonableResponseMixin, CreateView):
|
||||
model = TrailGPXImport
|
||||
fields = ["gpx_file"]
|
||||
template_name = "scrobbles/upload_form.html"
|
||||
@ -852,7 +846,9 @@ def scrobble_start(request, uuid):
|
||||
book=media_obj,
|
||||
user_id=user_id,
|
||||
)
|
||||
.filter(Q(long_play_complete=False) | Q(long_play_complete__isnull=True))
|
||||
.filter(
|
||||
Q(long_play_complete=False) | Q(long_play_complete__isnull=True)
|
||||
)
|
||||
.filter(log__page_end__isnull=False)
|
||||
.order_by("-timestamp")
|
||||
.first()
|
||||
@ -1328,6 +1324,7 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
|
||||
def _day_color(self, month_index, day_num, total_days):
|
||||
import colorsys
|
||||
|
||||
hue = (month_index - 1) * 30 / 360
|
||||
lightness = 0.80 + (day_num / total_days) * 0.15
|
||||
r, g, b = colorsys.hls_to_rgb(hue, lightness, 0.5)
|
||||
@ -1355,7 +1352,9 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
if media_type_filter and media_type_filter in self.CALENDAR_MEDIA_TYPES:
|
||||
active_types = [media_type_filter]
|
||||
else:
|
||||
active_types = [t for t in self.CALENDAR_MEDIA_TYPES if t not in self.DEFAULT_EXCLUDE]
|
||||
active_types = [
|
||||
t for t in self.CALENDAR_MEDIA_TYPES if t not in self.DEFAULT_EXCLUDE
|
||||
]
|
||||
|
||||
scrobbles = (
|
||||
Scrobble.objects.filter(
|
||||
@ -1364,12 +1363,23 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
timestamp__date__lte=month_end,
|
||||
media_type__in=active_types,
|
||||
)
|
||||
.select_related("task", "birding_location", "food", "trail", "video_game", "book", "mood", "video", "board_game")
|
||||
.select_related(
|
||||
"task",
|
||||
"birding_location",
|
||||
"food",
|
||||
"trail",
|
||||
"video_game",
|
||||
"book",
|
||||
"mood",
|
||||
"video",
|
||||
"board_game",
|
||||
)
|
||||
.order_by("timestamp")
|
||||
)
|
||||
|
||||
from django.db.models import Count, Q
|
||||
from django.db.models.functions import TruncDate
|
||||
|
||||
total_by_day = dict(
|
||||
Scrobble.objects.filter(
|
||||
user=self.request.user,
|
||||
@ -1377,7 +1387,11 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
timestamp__date__lte=month_end,
|
||||
)
|
||||
.exclude(Q(media_type="GeoLocation") & Q(geo_location__title__isnull=True))
|
||||
.annotate(local_date=TruncDate("timestamp", tzinfo=timezone.get_current_timezone()))
|
||||
.annotate(
|
||||
local_date=TruncDate(
|
||||
"timestamp", tzinfo=timezone.get_current_timezone()
|
||||
)
|
||||
)
|
||||
.values("local_date")
|
||||
.annotate(count=Count("id"))
|
||||
.values_list("local_date", "count")
|
||||
@ -1403,17 +1417,27 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
{
|
||||
"uuid": scrobble.uuid,
|
||||
"emoji": self.MEDIA_EMOJI.get(scrobble.media_type, "📌"),
|
||||
"title": str(scrobble.media_obj) if scrobble.media_obj else scrobble.media_type,
|
||||
"title": (
|
||||
str(scrobble.media_obj)
|
||||
if scrobble.media_obj
|
||||
else scrobble.media_type
|
||||
),
|
||||
"media_type": scrobble.media_type,
|
||||
}
|
||||
)
|
||||
calendar_days.append({
|
||||
"day": day_num,
|
||||
"scrobbles": day_scrobbles,
|
||||
"total_count": total_by_day.get(datetime(year, month, day_num).date(), 0),
|
||||
"is_today": year == today.year and month == today.month and day_num == today.day,
|
||||
"color": self._day_color(month, day_num, total_days),
|
||||
})
|
||||
calendar_days.append(
|
||||
{
|
||||
"day": day_num,
|
||||
"scrobbles": day_scrobbles,
|
||||
"total_count": total_by_day.get(
|
||||
datetime(year, month, day_num).date(), 0
|
||||
),
|
||||
"is_today": year == today.year
|
||||
and month == today.month
|
||||
and day_num == today.day,
|
||||
"color": self._day_color(month, day_num, total_days),
|
||||
}
|
||||
)
|
||||
|
||||
ctx.update(
|
||||
{
|
||||
@ -1430,7 +1454,10 @@ class ScrobbleCalendarView(LoginRequiredMixin, TemplateView):
|
||||
"day_names": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||
"month_color": month_color,
|
||||
"active_filter": media_type_filter or "",
|
||||
"media_types": [{"name": mt, "emoji": self.MEDIA_EMOJI.get(mt, "📌")} for mt in self.CALENDAR_MEDIA_TYPES],
|
||||
"media_types": [
|
||||
{"name": mt, "emoji": self.MEDIA_EMOJI.get(mt, "📌")}
|
||||
for mt in self.CALENDAR_MEDIA_TYPES
|
||||
],
|
||||
}
|
||||
)
|
||||
return ctx
|
||||
@ -1441,7 +1468,7 @@ class ScrobbleSearchView(LoginRequiredMixin, TemplateView):
|
||||
|
||||
MEDIA_FIELDS = {
|
||||
"Video": ["video__title", "video__overview"],
|
||||
"Track": ["track__title", "track__artist__name", "track__album__name"],
|
||||
"Track": ["track__title", "track__artists__name", "track__album__name"],
|
||||
"PodcastEpisode": ["podcast_episode__title", None],
|
||||
"Book": ["book__title", "book__summary"],
|
||||
"Paper": ["paper__title", None],
|
||||
|
||||
Reference in New Issue
Block a user