[black] Apparently we didn't get it all
Some checks failed
build & deploy / test (push) Successful in 1m41s
build & deploy / deploy (push) Failing after 2m2s

This commit is contained in:
2026-03-13 17:57:39 -04:00
parent 14e32dae12
commit 8ac6ed542f
5 changed files with 150 additions and 50 deletions

View File

@ -16,7 +16,9 @@ def scrobble_counts(user=None):
now = now_user_timezone(user.profile) now = now_user_timezone(user.profile)
user_filter = Q(user=user) user_filter = Q(user=user)
start_of_today = datetime.combine(now.date(), datetime.min.time(), now.tzinfo) start_of_today = datetime.combine(
now.date(), datetime.min.time(), now.tzinfo
)
starting_day_of_current_week = now.date() - timedelta( starting_day_of_current_week = now.date() - timedelta(
days=now.today().isoweekday() % 7 days=now.today().isoweekday() % 7
) )
@ -29,7 +31,9 @@ def scrobble_counts(user=None):
media_type=Scrobble.MediaType.TRACK, media_type=Scrobble.MediaType.TRACK,
) )
data = {} data = {}
data["today"] = finished_scrobbles_qs.filter(timestamp__gte=start_of_today).count() data["today"] = finished_scrobbles_qs.filter(
timestamp__gte=start_of_today
).count()
data["week"] = finished_scrobbles_qs.filter( data["week"] = finished_scrobbles_qs.filter(
timestamp__gte=starting_day_of_current_week timestamp__gte=starting_day_of_current_week
).count() ).count()
@ -43,7 +47,9 @@ def scrobble_counts(user=None):
return data return data
def week_of_scrobbles(user=None, start=None, media: str = "tracks") -> dict[str, int]: def week_of_scrobbles(
user=None, start=None, media: str = "tracks"
) -> dict[str, int]:
now = timezone.now() now = timezone.now()
user_filter = Q() user_filter = Q()
@ -95,7 +101,9 @@ def live_charts(
seven_days_ago = now - timedelta(days=7) seven_days_ago = now - timedelta(days=7)
thirty_days_ago = now - timedelta(days=30) thirty_days_ago = now - timedelta(days=30)
start_of_today = datetime.combine(now, datetime.min.time(), tzinfo) start_of_today = datetime.combine(now, datetime.min.time(), tzinfo)
start_day_of_week = start_of_today - timedelta(days=now.today().isoweekday() % 7) start_day_of_week = start_of_today - timedelta(
days=now.today().isoweekday() % 7
)
start_day_of_month = now.replace(day=1) start_day_of_month = now.replace(day=1)
start_day_of_year = now.replace(month=1, day=1) start_day_of_year = now.replace(month=1, day=1)
@ -112,13 +120,17 @@ def live_charts(
} }
time_filter = Q() time_filter = Q()
completion_filter = Q(scrobble__user=user, scrobble__played_to_completion=True) completion_filter = Q(
scrobble__user=user, scrobble__played_to_completion=True
)
user_filter = Q(scrobble__user=user) user_filter = Q(scrobble__user=user)
count_field = "scrobble" count_field = "scrobble"
if media_type == "Artist": if media_type == "Artist":
for period, query_dict in period_queries.items(): for period, query_dict in period_queries.items():
period_queries[period] = {"track__" + k: v for k, v in query_dict.items()} period_queries[period] = {
"track__" + k: v for k, v in query_dict.items()
}
completion_filter = Q( completion_filter = Q(
track__scrobble__user=user, track__scrobble__user=user,
track__scrobble__played_to_completion=True, track__scrobble__played_to_completion=True,
@ -163,7 +175,9 @@ def live_tv_charts(
seven_days_ago = now - timedelta(days=7) seven_days_ago = now - timedelta(days=7)
thirty_days_ago = now - timedelta(days=30) thirty_days_ago = now - timedelta(days=30)
start_of_today = datetime.combine(now, datetime.min.time(), tzinfo) start_of_today = datetime.combine(now, datetime.min.time(), tzinfo)
start_day_of_week = start_of_today - timedelta(days=now.today().isoweekday() % 7) start_day_of_week = start_of_today - timedelta(
days=now.today().isoweekday() % 7
)
start_day_of_month = now.replace(day=1) start_day_of_month = now.replace(day=1)
start_day_of_year = now.replace(month=1, day=1) start_day_of_year = now.replace(month=1, day=1)
@ -218,7 +232,9 @@ def live_youtube_channel_charts(
seven_days_ago = now - timedelta(days=7) seven_days_ago = now - timedelta(days=7)
thirty_days_ago = now - timedelta(days=30) thirty_days_ago = now - timedelta(days=30)
start_of_today = datetime.combine(now, datetime.min.time(), tzinfo) start_of_today = datetime.combine(now, datetime.min.time(), tzinfo)
start_day_of_week = start_of_today - timedelta(days=now.today().isoweekday() % 7) start_day_of_week = start_of_today - timedelta(
days=now.today().isoweekday() % 7
)
start_day_of_year = now.replace(month=1, day=1) start_day_of_year = now.replace(month=1, day=1)
period_queries = { period_queries = {

View File

@ -39,7 +39,9 @@ class Producer(TimeStampedModel):
class Podcast(TimeStampedModel): class Podcast(TimeStampedModel):
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL) uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
producer = models.ForeignKey(Producer, on_delete=models.DO_NOTHING, **BNULL) producer = models.ForeignKey(
Producer, on_delete=models.DO_NOTHING, **BNULL
)
podcastindex_id = models.CharField(max_length=100, **BNULL) podcastindex_id = models.CharField(max_length=100, **BNULL)
owner = models.CharField(max_length=150, *BNULL) owner = models.CharField(max_length=150, *BNULL)
description = models.TextField(**BNULL) description = models.TextField(**BNULL)
@ -121,7 +123,9 @@ class PodcastEpisode(ScrobblableMixin):
mopidy_uri = models.CharField(max_length=255, **BNULL) mopidy_uri = models.CharField(max_length=255, **BNULL)
def get_absolute_url(self): def get_absolute_url(self):
return reverse("podcasts:podcast_detail", kwargs={"slug": self.podcast.uuid}) return reverse(
"podcasts:podcast_detail", kwargs={"slug": self.podcast.uuid}
)
def __str__(self): def __str__(self):
return f"{self.title}" return f"{self.title}"

View File

@ -56,7 +56,9 @@ def django_form_field_from_type(field_type, required=True):
if type(None) in args: if type(None) in args:
required = False required = False
non_none_type = [arg for arg in args if arg is not type(None)][0] non_none_type = [arg for arg in args if arg is not type(None)][0]
return django_form_field_from_type(non_none_type, required=required) return django_form_field_from_type(
non_none_type, required=required
)
# Determine actual type # Determine actual type
base_type = origin if origin else field_type base_type = origin if origin else field_type
@ -82,7 +84,9 @@ def form_from_dataclass(dataclass):
continue continue
required = f.default is None and f.default_factory is None required = f.default is None and f.default_factory is None
form_fields[f.name] = django_form_field_from_type(f.type, required=required) form_fields[f.name] = django_form_field_from_type(
f.type, required=required
)
if f.name in dataclass._excluded_fields: if f.name in dataclass._excluded_fields:
form_fields[f.name].disabled = True form_fields[f.name].disabled = True
@ -97,7 +101,9 @@ def form_from_dataclass(dataclass):
def clean_notes(self): def clean_notes(self):
notes_str = self.cleaned_data.get("notes", "") notes_str = self.cleaned_data.get("notes", "")
return [line.strip() for line in notes_str.splitlines() if line.strip()] return [
line.strip() for line in notes_str.splitlines() if line.strip()
]
form_cls.clean_notes = clean_notes form_cls.clean_notes = clean_notes
return form_cls return form_cls

View File

@ -163,17 +163,25 @@ class RecentScrobbleList(ListView):
next_date = date + timedelta(weeks=+2) next_date = date + timedelta(weeks=+2)
prev_date = date + timedelta(weeks=-1) prev_date = date + timedelta(weeks=-1)
if date.isocalendar()[1] < today.isocalendar()[1]: if date.isocalendar()[1] < today.isocalendar()[1]:
data["next_link"] = f"?date={next_date.strftime('%Y-W%W')}" data[
"next_link"
] = f"?date={next_date.strftime('%Y-W%W')}"
data["prev_link"] = f"?date={prev_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[
"title"
] = f"Week {date.strftime('%-W')} of {date.year}"
data = data | Scrobble.as_dict_by_type( data = data | Scrobble.as_dict_by_type(
Scrobble.for_week(user_id, date.year, date.isocalendar()[1]) Scrobble.for_week(
user_id, date.year, date.isocalendar()[1]
)
) )
elif date_str == "this_month" or date_str.count("-") == 1: elif date_str == "this_month" or date_str.count("-") == 1:
next_date = date + relativedelta(months=1) next_date = date + relativedelta(months=1)
prev_date = date + relativedelta(months=-1) prev_date = date + relativedelta(months=-1)
if date.month < today.month: if date.month < today.month:
data["next_link"] = f"?date={next_date.strftime('%Y-%m')}" data[
"next_link"
] = f"?date={next_date.strftime('%Y-%m')}"
data["title"] = f"{date.strftime('%B %Y')}" data["title"] = f"{date.strftime('%B %Y')}"
data["prev_link"] = f"?date={prev_date.strftime('%Y-%m')}" data["prev_link"] = f"?date={prev_date.strftime('%Y-%m')}"
data = data | Scrobble.as_dict_by_type( data = data | Scrobble.as_dict_by_type(
@ -182,16 +190,24 @@ class RecentScrobbleList(ListView):
elif date_str == "today" or date_str.count("-") == 2: elif date_str == "today" or date_str.count("-") == 2:
next_date = date + timedelta(days=1) next_date = date + timedelta(days=1)
prev_date = date - timedelta(days=1) prev_date = date - timedelta(days=1)
data["prev_link"] = f"?date={prev_date.strftime('%Y-%m-%d')}" data[
"prev_link"
] = f"?date={prev_date.strftime('%Y-%m-%d')}"
if date < today: if date < today:
data["next_link"] = f"?date={next_date.strftime('%Y-%m-%d')}" data[
"next_link"
] = f"?date={next_date.strftime('%Y-%m-%d')}"
if date == today: if date == today:
data["title"] = "Today" data["title"] = "Today"
else: else:
data["title"] = f"{date.strftime('%Y-%m-%d')}" data["title"] = f"{date.strftime('%Y-%m-%d')}"
data["today_link"] = f"?date={today.strftime('%Y-%m-%d')}" data[
"today_link"
] = f"?date={today.strftime('%Y-%m-%d')}"
data = data | Scrobble.as_dict_by_type( data = data | Scrobble.as_dict_by_type(
Scrobble.for_day(user_id, date.year, date.month, date.day) Scrobble.for_day(
user_id, date.year, date.month, date.day
)
) )
elif date_str == "this_year" or date_str.count("-") == 0: elif date_str == "this_year" or date_str.count("-") == 0:
next_date = date + relativedelta(years=+1) next_date = date + relativedelta(years=+1)
@ -214,7 +230,9 @@ class RecentScrobbleList(ListView):
data = data | Scrobble.as_dict_by_type( data = data | Scrobble.as_dict_by_type(
Scrobble.for_day(user_id, date.year, date.month, date.day) Scrobble.for_day(user_id, date.year, date.month, date.day)
) )
data["today_link"] = "" # f"?date={today.strftime('%Y-%m-%d')}" data[
"today_link"
] = "" # f"?date={today.strftime('%Y-%m-%d')}"
data["active_imports"] = AudioScrobblerTSVImport.objects.filter( data["active_imports"] = AudioScrobblerTSVImport.objects.filter(
processing_started__isnull=False, processing_started__isnull=False,
@ -243,7 +261,9 @@ class ScrobbleLongPlaysView(TemplateView):
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)
context_data["view"] = self.request.GET.get("view", "grid") context_data["view"] = self.request.GET.get("view", "grid")
context_data["in_progress"] = get_long_plays_in_progress(self.request.user) context_data["in_progress"] = get_long_plays_in_progress(
self.request.user
)
context_data["completed"] = get_long_plays_completed(self.request.user) context_data["completed"] = get_long_plays_completed(self.request.user)
return context_data return context_data
@ -320,7 +340,9 @@ class ManualScrobbleView(FormView):
scrobble_fn = MANUAL_SCROBBLE_FNS[key] scrobble_fn = MANUAL_SCROBBLE_FNS[key]
scrobble = eval(scrobble_fn)(item_id, self.request.user.id) scrobble = eval(scrobble_fn)(item_id, self.request.user.id)
return HttpResponseRedirect(scrobble.redirect_url(self.request.user.id)) return HttpResponseRedirect(
scrobble.redirect_url(self.request.user.id)
)
class JsonableResponseMixin: class JsonableResponseMixin:
@ -366,7 +388,9 @@ class AudioScrobblerImportCreateView(
return HttpResponseRedirect(self.request.META.get("HTTP_REFERER")) return HttpResponseRedirect(self.request.META.get("HTTP_REFERER"))
class KoReaderImportCreateView(LoginRequiredMixin, JsonableResponseMixin, CreateView): class KoReaderImportCreateView(
LoginRequiredMixin, JsonableResponseMixin, CreateView
):
model = KoReaderImport model = KoReaderImport
fields = ["sqlite_file"] fields = ["sqlite_file"]
template_name = "scrobbles/upload_form.html" template_name = "scrobbles/upload_form.html"
@ -425,7 +449,9 @@ def web_scrobbler_webhook(request):
playing_state = "started" playing_state = "started"
if request.POST.get("isPlaying") == "false": if request.POST.get("isPlaying") == "false":
playing_state = "stopped" playing_state = "stopped"
scrobble = web_scrobbler_scrobble_media(youtube_id, user_id, status=playing_state) scrobble = web_scrobbler_scrobble_media(
youtube_id, user_id, status=playing_state
)
if not scrobble: if not scrobble:
logger.warning( logger.warning(
"[web_scrobbler_webhook] failed", "[web_scrobbler_webhook] failed",
@ -443,7 +469,9 @@ def web_scrobbler_webhook(request):
"[web_scrobbler_webhook] finished", "[web_scrobbler_webhook] finished",
extra={"scrobble_id": scrobble.id}, extra={"scrobble_id": scrobble.id},
) )
return JsonResponse({"scrobble_id": scrobble.id}, status=status.HTTP_200_OK) return JsonResponse(
{"scrobble_id": scrobble.id}, status=status.HTTP_200_OK
)
@csrf_exempt @csrf_exempt
@ -548,12 +576,18 @@ def import_audioscrobbler_file(request):
scrobbles_created = [] scrobbles_created = []
# tsv_file = request.FILES[0] # tsv_file = request.FILES[0]
file_serializer = serializers.AudioScrobblerTSVImportSerializer(data=request.data) file_serializer = serializers.AudioScrobblerTSVImportSerializer(
data=request.data
)
if file_serializer.is_valid(): if file_serializer.is_valid():
import_file = file_serializer.save() import_file = file_serializer.save()
return Response({"scrobble_ids": scrobbles_created}, status=status.HTTP_200_OK) return Response(
{"scrobble_ids": scrobbles_created}, status=status.HTTP_200_OK
)
else: else:
return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(
file_serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
@permission_classes([IsAuthenticated]) @permission_classes([IsAuthenticated])
@ -730,7 +764,9 @@ class ChartRecordView(TemplateView):
).order_by("rank") ).order_by("rank")
if charts.count() == 0: if charts.count() == 0:
ChartRecord.build(user=self.request.user, model_str=media_type, **kwargs) ChartRecord.build(
user=self.request.user, model_str=media_type, **kwargs
)
charts = ChartRecord.objects.filter( charts = ChartRecord.objects.filter(
media_filter, user=self.request.user, **kwargs media_filter, user=self.request.user, **kwargs
).order_by("rank") ).order_by("rank")
@ -762,7 +798,9 @@ class ChartRecordView(TemplateView):
media_type = self.request.GET.get("media", "Track") media_type = self.request.GET.get("media", "Track")
user = self.request.user user = self.request.user
params = {} params = {}
context_data["chart_type"] = self.request.GET.get("chart_type", "maloja") context_data["chart_type"] = self.request.GET.get(
"chart_type", "maloja"
)
context_data["artist_charts"] = {} context_data["artist_charts"] = {}
if not date: if not date:
@ -800,7 +838,9 @@ class ChartRecordView(TemplateView):
tzinfo = now.tzinfo tzinfo = now.tzinfo
now = now.date() now = now.date()
start_of_today = datetime.combine(now, datetime.min.time(), tzinfo) start_of_today = datetime.combine(now, datetime.min.time(), tzinfo)
start_day_of_week = start_of_today - timedelta(days=now.isoweekday() % 7) start_day_of_week = start_of_today - timedelta(
days=now.isoweekday() % 7
)
start_day_of_month = now.replace(day=1) start_day_of_month = now.replace(day=1)
# TV Series Scrobbles # TV Series Scrobbles
@ -845,25 +885,35 @@ class ChartRecordView(TemplateView):
context_data["tv_show_charts"] = { context_data["tv_show_charts"] = {
"today": list(live_tv_charts(user=user, chart_period="today")), "today": list(live_tv_charts(user=user, chart_period="today")),
"last7": list(live_tv_charts(user=user, chart_period="last7")), "last7": list(live_tv_charts(user=user, chart_period="last7")),
"last30": list(live_tv_charts(user=user, chart_period="last30")), "last30": list(
live_tv_charts(user=user, chart_period="last30")
),
"year": list(live_tv_charts(user=user, chart_period="year")), "year": list(live_tv_charts(user=user, chart_period="year")),
"all": list(live_tv_charts(user=user, chart_period="all")), "all": list(live_tv_charts(user=user, chart_period="all")),
} }
context_data["youtube_channel_charts"] = { context_data["youtube_channel_charts"] = {
"today": list( "today": list(
live_youtube_channel_charts(user=user, chart_period="today") live_youtube_channel_charts(
user=user, chart_period="today"
)
), ),
"last7": list( "last7": list(
live_youtube_channel_charts(user=user, chart_period="last7") live_youtube_channel_charts(
user=user, chart_period="last7"
)
), ),
"last30": list( "last30": list(
live_youtube_channel_charts(user=user, chart_period="last30") live_youtube_channel_charts(
user=user, chart_period="last30"
)
), ),
"year": list( "year": list(
live_youtube_channel_charts(user=user, chart_period="year") live_youtube_channel_charts(user=user, chart_period="year")
), ),
"all": list(live_youtube_channel_charts(user=user, chart_period="all")), "all": list(
live_youtube_channel_charts(user=user, chart_period="all")
),
} }
return context_data return context_data
@ -901,7 +951,9 @@ class ChartRecordView(TemplateView):
params["day"] = day params["day"] = day
month_str = calendar.month_name[month] month_str = calendar.month_name[month]
name = f"Chart for {month_str} {day}, {year}" name = f"Chart for {month_str} {day}, {year}"
in_progress = now.month == month and now.year == year and now.day == day in_progress = (
now.month == month and now.year == year and now.day == day
)
media_filter = self.get_media_filter("Track") media_filter = self.get_media_filter("Track")
track_charts = ChartRecord.objects.filter( track_charts = ChartRecord.objects.filter(
@ -913,13 +965,17 @@ class ChartRecordView(TemplateView):
).order_by("rank") ).order_by("rank")
if track_charts.count() == 0 and not in_progress: if track_charts.count() == 0 and not in_progress:
ChartRecord.build(user=self.request.user, model_str="Track", **params) ChartRecord.build(
user=self.request.user, model_str="Track", **params
)
media_filter = self.get_media_filter("Track") media_filter = self.get_media_filter("Track")
track_charts = ChartRecord.objects.filter( track_charts = ChartRecord.objects.filter(
media_filter, user=self.request.user, **params media_filter, user=self.request.user, **params
).order_by("rank") ).order_by("rank")
if artist_charts.count() == 0 and not in_progress: if artist_charts.count() == 0 and not in_progress:
ChartRecord.build(user=self.request.user, model_str="Artist", **params) ChartRecord.build(
user=self.request.user, model_str="Artist", **params
)
media_filter = self.get_media_filter("Artist") media_filter = self.get_media_filter("Artist")
artist_charts = ChartRecord.objects.filter( artist_charts = ChartRecord.objects.filter(
media_filter, user=self.request.user, **params media_filter, user=self.request.user, **params
@ -940,24 +996,38 @@ class ScrobbleStatusView(LoginRequiredMixin, TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs) data = super().get_context_data(**kwargs)
user_scrobble_qs = Scrobble.objects.filter().order_by("-timestamp") user_scrobble_qs = Scrobble.objects.filter().order_by("-timestamp")
progress_plays = user_scrobble_qs.filter(in_progress=True, is_paused=False) progress_plays = user_scrobble_qs.filter(
in_progress=True, is_paused=False
)
data["listening"] = progress_plays.filter( data["listening"] = progress_plays.filter(
Q(track__isnull=False) | Q(podcast_episode__isnull=False) Q(track__isnull=False) | Q(podcast_episode__isnull=False)
).first() ).first()
data["watching"] = progress_plays.filter(video__isnull=False).first() data["watching"] = progress_plays.filter(video__isnull=False).first()
data["going"] = progress_plays.filter(geo_location__isnull=False).first() data["going"] = progress_plays.filter(
data["playing"] = progress_plays.filter(board_game__isnull=False).first() geo_location__isnull=False
data["sporting"] = progress_plays.filter(sport_event__isnull=False).first() ).first()
data["browsing"] = progress_plays.filter(web_page__isnull=False).first() data["playing"] = progress_plays.filter(
data["participating"] = progress_plays.filter(life_event__isnull=False).first() board_game__isnull=False
).first()
data["sporting"] = progress_plays.filter(
sport_event__isnull=False
).first()
data["browsing"] = progress_plays.filter(
web_page__isnull=False
).first()
data["participating"] = progress_plays.filter(
life_event__isnull=False
).first()
data["working"] = progress_plays.filter(task__isnull=False).first() data["working"] = progress_plays.filter(task__isnull=False).first()
long_plays = user_scrobble_qs.filter( long_plays = user_scrobble_qs.filter(
long_play_complete=False, played_to_completion=True long_play_complete=False, played_to_completion=True
) )
data["reading"] = long_plays.filter(book__isnull=False).first() data["reading"] = long_plays.filter(book__isnull=False).first()
data["sessioning"] = long_plays.filter(video_game__isnull=False).first() data["sessioning"] = long_plays.filter(
video_game__isnull=False
).first()
return data return data
@ -992,7 +1062,9 @@ class ScrobbleDetailView(DetailView):
data[field_name] = original_value data[field_name] = original_value
if data.get("with_people_ids", False): if data.get("with_people_ids", False):
data["with_people_ids"] = [p.id for p in data["with_people_ids"]] data["with_people_ids"] = [
p.id for p in data["with_people_ids"]
]
if data.get("platform_id", False): if data.get("platform_id", False):
data["platform_id"] = data["platform_id"].id data["platform_id"] = data["platform_id"].id

View File

@ -25,7 +25,9 @@ class SeriesDetailView(LoginRequiredMixin, generic.DetailView):
context_data = super().get_context_data(**kwargs) context_data = super().get_context_data(**kwargs)
context_data["scrobbles"] = self.object.scrobbles_for_user(user_id) context_data["scrobbles"] = self.object.scrobbles_for_user(user_id)
next_episode_id = self.object.last_scrobbled_episode(user_id).next_imdb_id or "" next_episode_id = (
self.object.last_scrobbled_episode(user_id).next_imdb_id or ""
)
if self.object.is_episode_playing(user_id): if self.object.is_episode_playing(user_id):
next_episode_id = "" next_episode_id = ""
if next_episode_id: if next_episode_id: