Files
vrobbler/vrobbler/apps/music/aggregators.py

157 lines
4.8 KiB
Python

from datetime import datetime, timedelta
from django.apps import apps
from django.db.models import Count, Q, QuerySet
from django.utils import timezone
from profiles.utils import now_user_timezone
from scrobbles.models import Scrobble
from videos.models import Video
def scrobble_counts(user=None):
now = timezone.now()
user_filter = Q()
if user and user.is_authenticated:
now = now_user_timezone(user.profile)
user_filter = Q(user=user)
start_of_today = datetime.combine(
now.date(), datetime.min.time(), now.tzinfo
)
starting_day_of_current_week = now.date() - timedelta(
days=now.today().isoweekday() % 7
)
starting_day_of_current_month = now.date().replace(day=1)
starting_day_of_current_year = now.date().replace(month=1, day=1)
finished_scrobbles_qs = Scrobble.objects.filter(
user_filter,
played_to_completion=True,
media_type=Scrobble.MediaType.TRACK,
)
data = {}
data["today"] = finished_scrobbles_qs.filter(
timestamp__gte=start_of_today
).count()
data["week"] = finished_scrobbles_qs.filter(
timestamp__gte=starting_day_of_current_week
).count()
data["month"] = finished_scrobbles_qs.filter(
timestamp__gte=starting_day_of_current_month
).count()
data["year"] = finished_scrobbles_qs.filter(
timestamp__gte=starting_day_of_current_year
).count()
data["alltime"] = finished_scrobbles_qs.count()
return data
def week_of_scrobbles(
user=None, start=None, media: str = "tracks"
) -> dict[str, int]:
now = timezone.now()
user_filter = Q()
if user and user.is_authenticated:
now = now_user_timezone(user.profile)
user_filter = Q(user=user)
if not start:
start = datetime.combine(now.date(), datetime.min.time(), now.tzinfo)
scrobble_day_dict = {}
base_qs = Scrobble.objects.filter(user_filter, played_to_completion=True)
media_filter = Q(track__isnull=False)
if media == "movies":
media_filter = Q(video__video_type=Video.VideoType.MOVIE)
if media == "series":
media_filter = Q(video__video_type=Video.VideoType.TV_EPISODE)
for day in range(6, -1, -1):
start_day = start - timedelta(days=day)
end = datetime.combine(start_day, datetime.max.time(), now.tzinfo)
day_of_week = start_day.strftime("%A")
scrobble_day_dict[day_of_week] = base_qs.filter(
media_filter,
timestamp__gte=start_day,
timestamp__lte=end,
played_to_completion=True,
).count()
return scrobble_day_dict
def live_charts(
user: "User",
media_type: str = "Track",
chart_period: str = "all",
limit: int = 15,
) -> QuerySet:
now = timezone.now()
tzinfo = now.tzinfo
now = now.date()
if user.is_authenticated:
now = now_user_timezone(user.profile)
tzinfo = now.tzinfo
seven_days_ago = now - timedelta(days=7)
thirty_days_ago = now - timedelta(days=30)
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_month = now.replace(day=1)
start_day_of_year = now.replace(month=1, day=1)
media_model = apps.get_model(app_label="music", model_name=media_type)
period_queries = {
"today": {"scrobble__timestamp__gte": start_of_today},
"week": {"scrobble__timestamp__gte": start_day_of_week},
"last7": {"scrobble__timestamp__gte": seven_days_ago},
"last30": {"scrobble__timestamp__gte": thirty_days_ago},
"month": {"scrobble__timestamp__gte": start_day_of_month},
"year": {"scrobble__timestamp__gte": start_day_of_year},
"all": {},
}
time_filter = Q()
completion_filter = Q(
scrobble__user=user, scrobble__played_to_completion=True
)
user_filter = Q(scrobble__user=user)
count_field = "scrobble"
if media_type == "Artist":
for period, query_dict in period_queries.items():
period_queries[period] = {
"track__" + k: v for k, v in query_dict.items()
}
completion_filter = Q(
track__scrobble__user=user,
track__scrobble__played_to_completion=True,
)
count_field = "track__scrobble"
user_filter = Q(track__scrobble__user=user)
time_filter = Q(**period_queries[chart_period])
return (
media_model.objects.filter(user_filter, time_filter)
.annotate(
num_scrobbles=Count(
count_field,
filter=completion_filter,
distinct=True,
)
)
.order_by("-num_scrobbles")[:limit]
)
def artist_scrobble_count(artist_id: int, filter: str = "today") -> int:
return Scrobble.objects.filter(track__artist=artist_id).count()