aggregators.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from datetime import datetime, timedelta
  2. from typing import List, Optional
  3. import pytz
  4. from django.db.models import Count, Q, Sum
  5. from django.utils import timezone
  6. from music.models import Artist, Track
  7. from scrobbles.models import Scrobble
  8. from videos.models import Video
  9. from vrobbler.apps.profiles.utils import now_user_timezone
  10. NOW = timezone.now()
  11. START_OF_TODAY = datetime.combine(NOW.date(), datetime.min.time(), NOW.tzinfo)
  12. STARTING_DAY_OF_CURRENT_WEEK = NOW.date() - timedelta(
  13. days=NOW.today().isoweekday() % 7
  14. )
  15. STARTING_DAY_OF_CURRENT_MONTH = NOW.date().replace(day=1)
  16. STARTING_DAY_OF_CURRENT_YEAR = NOW.date().replace(month=1, day=1)
  17. def scrobble_counts(user=None):
  18. now = timezone.now()
  19. user_filter = Q()
  20. if user and user.is_authenticated:
  21. now = now_user_timezone(user.profile)
  22. user_filter = Q(user=user)
  23. start_of_today = datetime.combine(
  24. now.date(), datetime.min.time(), now.tzinfo
  25. )
  26. starting_day_of_current_week = now.date() - timedelta(
  27. days=now.today().isoweekday() % 7
  28. )
  29. starting_day_of_current_month = now.date().replace(day=1)
  30. starting_day_of_current_year = now.date().replace(month=1, day=1)
  31. finished_scrobbles_qs = Scrobble.objects.filter(
  32. user_filter, played_to_completion=True
  33. )
  34. data = {}
  35. data['today'] = finished_scrobbles_qs.filter(
  36. timestamp__gte=start_of_today
  37. ).count()
  38. data['week'] = finished_scrobbles_qs.filter(
  39. timestamp__gte=starting_day_of_current_week
  40. ).count()
  41. data['month'] = finished_scrobbles_qs.filter(
  42. timestamp__gte=starting_day_of_current_month
  43. ).count()
  44. data['year'] = finished_scrobbles_qs.filter(
  45. timestamp__gte=starting_day_of_current_year
  46. ).count()
  47. data['alltime'] = finished_scrobbles_qs.count()
  48. return data
  49. def week_of_scrobbles(
  50. user=None, start=None, media: str = 'tracks'
  51. ) -> dict[str, int]:
  52. now = timezone.now()
  53. user_filter = Q()
  54. if user and user.is_authenticated:
  55. now = now_user_timezone(user.profile)
  56. user_filter = Q(user=user)
  57. if not start:
  58. start = datetime.combine(now.date(), datetime.min.time(), now.tzinfo)
  59. scrobble_day_dict = {}
  60. base_qs = Scrobble.objects.filter(user_filter, played_to_completion=True)
  61. media_filter = Q(track__isnull=False)
  62. if media == 'movies':
  63. media_filter = Q(video__video_type=Video.VideoType.MOVIE)
  64. if media == 'series':
  65. media_filter = Q(video__video_type=Video.VideoType.TV_EPISODE)
  66. for day in range(6, -1, -1):
  67. start_day = start - timedelta(days=day)
  68. end = datetime.combine(start_day, datetime.max.time(), now.tzinfo)
  69. day_of_week = start_day.strftime('%A')
  70. scrobble_day_dict[day_of_week] = base_qs.filter(
  71. media_filter,
  72. timestamp__gte=start_day,
  73. timestamp__lte=end,
  74. played_to_completion=True,
  75. ).count()
  76. return scrobble_day_dict
  77. def top_tracks(
  78. user: "User", filter: str = "today", limit: int = 30
  79. ) -> List["Track"]:
  80. now = timezone.now()
  81. if user.is_authenticated:
  82. now = now_user_timezone(user.profile)
  83. start_of_today = datetime.combine(
  84. now.date(), datetime.min.time(), now.tzinfo
  85. )
  86. starting_day_of_current_week = now.date() - timedelta(
  87. days=now.today().isoweekday() % 7
  88. )
  89. starting_day_of_current_month = now.date().replace(day=1)
  90. starting_day_of_current_year = now.date().replace(month=1, day=1)
  91. time_filter = Q()
  92. if filter == "today":
  93. time_filter = Q(scrobble__timestamp__gte=start_of_today)
  94. if filter == "week":
  95. time_filter = Q(scrobble__timestamp__gte=starting_day_of_current_week)
  96. if filter == "month":
  97. time_filter = Q(scrobble__timestamp__gte=starting_day_of_current_month)
  98. if filter == "year":
  99. time_filter = Q(scrobble__timestamp__gte=starting_day_of_current_year)
  100. return (
  101. Track.objects.filter(time_filter)
  102. .annotate(
  103. num_scrobbles=Count(
  104. "scrobble",
  105. filter=Q(scrobble__played_to_completion=True),
  106. distinct=True,
  107. )
  108. )
  109. .order_by("-num_scrobbles")[:limit]
  110. )
  111. def top_artists(
  112. user: "User", filter: str = "today", limit: int = 15
  113. ) -> List["Artist"]:
  114. time_filter = Q(track__scrobble__timestamp__gte=START_OF_TODAY)
  115. if filter == "week":
  116. time_filter = Q(
  117. track__scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_WEEK
  118. )
  119. if filter == "month":
  120. time_filter = Q(
  121. track__scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_MONTH
  122. )
  123. if filter == "year":
  124. time_filter = Q(
  125. track__scrobble__timestamp__gte=STARTING_DAY_OF_CURRENT_YEAR
  126. )
  127. return (
  128. Artist.objects.filter(time_filter)
  129. .annotate(
  130. num_scrobbles=Count(
  131. "track__scrobble",
  132. filter=Q(track__scrobble__played_to_completion=True),
  133. distinct=True,
  134. )
  135. )
  136. .order_by("-num_scrobbles")
  137. )
  138. def artist_scrobble_count(artist_id: int, filter: str = "today") -> int:
  139. return Scrobble.objects.filter(track__artist=artist_id).count()