|
@@ -4,12 +4,13 @@ import logging
|
|
|
from datetime import datetime, timedelta
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
|
|
+from django.shortcuts import redirect
|
|
|
import pendulum
|
|
|
import pytz
|
|
|
from django.apps import apps
|
|
|
from django.contrib import messages
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
|
-from django.db.models import Count, Q
|
|
|
+from django.db.models import Count, Q, Max
|
|
|
from django.db.models.query import QuerySet
|
|
|
from django.http import FileResponse, HttpResponseRedirect, JsonResponse
|
|
|
from django.urls import reverse_lazy
|
|
@@ -75,12 +76,17 @@ class ScrobbleableListView(ListView):
|
|
|
user_filter = Q(scrobble__user=self.request.user)
|
|
|
|
|
|
queryset = (
|
|
|
- queryset.filter(user_filter).annotate(
|
|
|
- scrobble_count=Count("scrobble")
|
|
|
- ).filter(scrobble_count__gt=0).order_by("-scrobble_count")
|
|
|
+ queryset.filter(user_filter)
|
|
|
+ .annotate(
|
|
|
+ scrobble_count=Count("scrobble", distinct=True),
|
|
|
+ last_scrobble=Max("scrobble__timestamp"),
|
|
|
+ )
|
|
|
+ .filter(scrobble_count__gt=0)
|
|
|
+ .order_by("-last_scrobble")
|
|
|
)
|
|
|
return queryset
|
|
|
|
|
|
+
|
|
|
class ScrobbleableDetailView(DetailView):
|
|
|
model = None
|
|
|
slug_field = "uuid"
|
|
@@ -926,3 +932,57 @@ class ScrobbleStatusView(LoginRequiredMixin, TemplateView):
|
|
|
).first()
|
|
|
|
|
|
return data
|
|
|
+
|
|
|
+
|
|
|
+class ScrobbleDetailView(DetailView):
|
|
|
+ model = Scrobble
|
|
|
+ slug_field = "uuid"
|
|
|
+ slug_url_kwarg = "uuid"
|
|
|
+
|
|
|
+ def get_form_class(self):
|
|
|
+ return self.object.media_obj.logdata_cls.form()
|
|
|
+
|
|
|
+ def get_form(self):
|
|
|
+ FormClass = self.get_form_class()
|
|
|
+
|
|
|
+ log = self.object.log or {}
|
|
|
+ initial_notes = log.get("notes", [])
|
|
|
+ if isinstance(initial_notes, list):
|
|
|
+ notes_str = "\n".join(initial_notes)
|
|
|
+ notes_str_fixed = notes_str.encode("utf-8").decode(
|
|
|
+ "unicode_escape"
|
|
|
+ )
|
|
|
+ log["notes"] = notes_str_fixed
|
|
|
+
|
|
|
+ return FormClass(initial=log)
|
|
|
+
|
|
|
+ def post(self, request, *args, **kwargs):
|
|
|
+ self.object = self.get_object()
|
|
|
+ FormClass = self.get_form_class()
|
|
|
+ form = FormClass(request.POST)
|
|
|
+
|
|
|
+ if form.is_valid():
|
|
|
+ data = form.cleaned_data.copy()
|
|
|
+
|
|
|
+ for field_name, field in form.fields.items():
|
|
|
+ if field.disabled:
|
|
|
+ original_value = (self.object.log or {}).get(field_name)
|
|
|
+ data[field_name] = original_value
|
|
|
+
|
|
|
+ if "with_people_ids" in data:
|
|
|
+ data["with_people_ids"] = [
|
|
|
+ p.id for p in data["with_people_ids"]
|
|
|
+ ]
|
|
|
+
|
|
|
+ self.object.log = data
|
|
|
+ self.object.save(update_fields=["log"])
|
|
|
+ return redirect(self.object.get_absolute_url())
|
|
|
+
|
|
|
+ context = self.get_context_data(log_form=form)
|
|
|
+ return self.render_to_response(context)
|
|
|
+
|
|
|
+ def get_context_data(self, **kwargs):
|
|
|
+ context = super().get_context_data(**kwargs)
|
|
|
+ if "log_form" not in context:
|
|
|
+ context["log_form"] = self.get_form()
|
|
|
+ return context
|