[trends] Fix bug in mood trend generation
This commit is contained in:
@ -88,7 +88,7 @@ fetching and simple saving.
|
|||||||
*** Metadata sources
|
*** Metadata sources
|
||||||
**** Scraper
|
**** Scraper
|
||||||
|
|
||||||
* Backlog [0/20] :vrobbler:project:personal:
|
* Backlog [1/21] :vrobbler:project:personal:
|
||||||
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :bug:music:scrobbles:
|
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :bug:music:scrobbles:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:ID: 702462cf-d54b-48c6-8a7c-78b8de751deb
|
:ID: 702462cf-d54b-48c6-8a7c-78b8de751deb
|
||||||
@ -590,6 +590,10 @@ We should rename `email_scrobble_board_game` to reflect the fact that it's just
|
|||||||
a helper method to create board game scrobbles given a json blob. It's
|
a helper method to create board game scrobbles given a json blob. It's
|
||||||
independent of the email flow it was originally creatdd for
|
independent of the email flow it was originally creatdd for
|
||||||
|
|
||||||
|
** DONE Fix bug in generating mood trends :trends:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: 8e75abfa-8e70-d85b-00a4-a4813bbce879
|
||||||
|
:END:
|
||||||
* Version 54.4 [2/2]
|
* Version 54.4 [2/2]
|
||||||
** DONE [#A] Remove all-time trends :trends:
|
** DONE [#A] Remove all-time trends :trends:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
from datetime import timedelta
|
|
||||||
|
|
||||||
from django.db.models import Count, Q
|
from django.db.models import Q
|
||||||
from django.db.models.functions import Extract
|
|
||||||
from django.utils import timezone
|
|
||||||
from scrobbles.models import Scrobble
|
from scrobbles.models import Scrobble
|
||||||
|
|
||||||
|
|
||||||
def _mood_scrobbles(user, period="all_time"):
|
def _mood_scrobbles(user, period="last_30"):
|
||||||
from trends.utils import get_date_range
|
from trends.utils import get_date_range
|
||||||
|
|
||||||
start, end = get_date_range(period)
|
start, end = get_date_range(period)
|
||||||
@ -19,17 +16,25 @@ def _mood_scrobbles(user, period="all_time"):
|
|||||||
return Scrobble.objects.filter(filters).select_related("mood")
|
return Scrobble.objects.filter(filters).select_related("mood")
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_quality(raw):
|
||||||
|
try:
|
||||||
|
return int(raw)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _avg_quality(values):
|
def _avg_quality(values):
|
||||||
if not values:
|
nums = [v for v in values if v is not None]
|
||||||
|
if not nums:
|
||||||
return 0.0
|
return 0.0
|
||||||
return round(sum(values) / len(values), 2)
|
return round(sum(nums) / len(nums), 2)
|
||||||
|
|
||||||
|
|
||||||
def compute_mood_trajectory(user, period="all_time"):
|
def compute_mood_trajectory(user, period="last_30"):
|
||||||
scrobbles = _mood_scrobbles(user, period).order_by("timestamp")
|
scrobbles = _mood_scrobbles(user, period).order_by("timestamp")
|
||||||
by_date = defaultdict(list)
|
by_date = defaultdict(list)
|
||||||
for s in scrobbles:
|
for s in scrobbles:
|
||||||
quality = s.log.get("mood_quality")
|
quality = _parse_quality(s.log.get("mood_quality"))
|
||||||
if quality is not None:
|
if quality is not None:
|
||||||
day_key = s.timestamp.strftime("%Y-%m-%d")
|
day_key = s.timestamp.strftime("%Y-%m-%d")
|
||||||
by_date[day_key].append(quality)
|
by_date[day_key].append(quality)
|
||||||
@ -48,13 +53,13 @@ def compute_mood_trajectory(user, period="all_time"):
|
|||||||
return {"trajectory": trajectory}
|
return {"trajectory": trajectory}
|
||||||
|
|
||||||
|
|
||||||
def compute_mood_by_time(user, period="all_time"):
|
def compute_mood_by_time(user, period="last_30"):
|
||||||
scrobbles = _mood_scrobbles(user, period)
|
scrobbles = _mood_scrobbles(user, period)
|
||||||
by_hour = defaultdict(list)
|
by_hour = defaultdict(list)
|
||||||
by_day = defaultdict(list)
|
by_day = defaultdict(list)
|
||||||
|
|
||||||
for s in scrobbles:
|
for s in scrobbles:
|
||||||
quality = s.log.get("mood_quality")
|
quality = _parse_quality(s.log.get("mood_quality"))
|
||||||
if quality is not None and s.timestamp:
|
if quality is not None and s.timestamp:
|
||||||
by_hour[s.timestamp.hour].append(quality)
|
by_hour[s.timestamp.hour].append(quality)
|
||||||
by_day[s.timestamp.isoweekday()].append(quality)
|
by_day[s.timestamp.isoweekday()].append(quality)
|
||||||
@ -94,7 +99,7 @@ def compute_mood_by_time(user, period="all_time"):
|
|||||||
return {"hours": hours, "days": days}
|
return {"hours": hours, "days": days}
|
||||||
|
|
||||||
|
|
||||||
def compute_mood_distribution(user, period="all_time"):
|
def compute_mood_distribution(user, period="last_30"):
|
||||||
scrobbles = _mood_scrobbles(user, period)
|
scrobbles = _mood_scrobbles(user, period)
|
||||||
mood_counts = Counter()
|
mood_counts = Counter()
|
||||||
type_counts = Counter()
|
type_counts = Counter()
|
||||||
@ -120,7 +125,7 @@ def compute_mood_distribution(user, period="all_time"):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def compute_mood_streaks(user, period="all_time"):
|
def compute_mood_streaks(user, period="last_30"):
|
||||||
scrobbles = list(
|
scrobbles = list(
|
||||||
_mood_scrobbles(user, period).order_by("timestamp")
|
_mood_scrobbles(user, period).order_by("timestamp")
|
||||||
)
|
)
|
||||||
@ -169,13 +174,13 @@ def compute_mood_streaks(user, period="all_time"):
|
|||||||
return {"streaks": streaks[:10], "current_streak": current_streak}
|
return {"streaks": streaks[:10], "current_streak": current_streak}
|
||||||
|
|
||||||
|
|
||||||
def compute_mood_weather(user, period="all_time"):
|
def compute_mood_weather(user, period="last_30"):
|
||||||
scrobbles = _mood_scrobbles(user, period)
|
scrobbles = _mood_scrobbles(user, period)
|
||||||
by_condition = defaultdict(list)
|
by_condition = defaultdict(list)
|
||||||
by_temp_range = defaultdict(list)
|
by_temp_range = defaultdict(list)
|
||||||
|
|
||||||
for s in scrobbles:
|
for s in scrobbles:
|
||||||
quality = s.log.get("mood_quality")
|
quality = _parse_quality(s.log.get("mood_quality"))
|
||||||
if quality is None:
|
if quality is None:
|
||||||
continue
|
continue
|
||||||
desc = s.log.get("weather_description")
|
desc = s.log.get("weather_description")
|
||||||
@ -183,7 +188,11 @@ def compute_mood_weather(user, period="all_time"):
|
|||||||
if desc:
|
if desc:
|
||||||
by_condition[desc].append(quality)
|
by_condition[desc].append(quality)
|
||||||
if temp is not None:
|
if temp is not None:
|
||||||
bucket = f"{(int(temp) // 10) * 10}-{(int(temp) // 10) * 10 + 9}F"
|
try:
|
||||||
|
temp_f = float(temp)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
bucket = f"{(int(temp_f) // 10) * 10}-{(int(temp_f) // 10) * 10 + 9}F"
|
||||||
by_temp_range[bucket].append(quality)
|
by_temp_range[bucket].append(quality)
|
||||||
|
|
||||||
conditions = [
|
conditions = [
|
||||||
|
|||||||
Reference in New Issue
Block a user