rustfm_scraper/
stats.rs

1use std::collections::HashMap;
2
3use chrono::{Datelike, NaiveDate};
4use num_format::ToFormattedString;
5
6use crate::models::saved_scrobbles::SavedScrobble;
7use crate::utils;
8
9pub struct Stats {
10    average_tracks_per_day: f64,
11    average_tracks_per_week: f64,
12    average_tracks_per_month: f64,
13    average_tracks_per_year: f64,
14
15    best_month: (String, i32),
16}
17
18impl Stats {
19    pub fn new(scrobbles: &[SavedScrobble]) -> Self {
20        Self {
21            average_tracks_per_day: calculate_daily_average(scrobbles),
22            average_tracks_per_week: calculate_weekly_average(scrobbles),
23            average_tracks_per_month: calculate_monthly_average(scrobbles),
24            average_tracks_per_year: calculate_yearly_average(scrobbles),
25
26            best_month: calculate_best_month(scrobbles),
27        }
28    }
29
30    pub fn print(&self) {
31        println!("STATS:\n");
32
33        println!("Average Tracks Per Day:   {}", self.average_tracks_per_day);
34        println!("Average Tracks Per Week:  {}", self.average_tracks_per_week);
35        println!(
36            "Average Tracks Per Month: {}",
37            self.average_tracks_per_month
38        );
39        println!("Average Tracks Per Year:  {}", self.average_tracks_per_year);
40
41        println!(
42            "Best Month: {} ({} scrobbles)",
43            self.best_month.0,
44            self.best_month.1.to_formatted_string(&utils::get_locale())
45        );
46    }
47}
48
49fn calculate_daily_average(scrobbles: &[SavedScrobble]) -> f64 {
50    let mut groups: HashMap<NaiveDate, i32> = HashMap::new();
51
52    scrobbles.iter().for_each(|scrobble| {
53        let group = groups.entry(scrobble.date()).or_insert(0);
54        *group += 1
55    });
56
57    groups.iter().map(|g| g.1).sum::<i32>() as f64 / utils::get_total_days(&scrobbles) as f64
58}
59
60fn calculate_weekly_average(scrobbles: &[SavedScrobble]) -> f64 {
61    let mut groups: HashMap<u32, i32> = HashMap::new();
62
63    scrobbles.iter().for_each(|scrobble| {
64        let group = groups.entry(scrobble.date().iso_week().week()).or_insert(0);
65        *group += 1;
66    });
67
68    groups.iter().map(|g| g.1).sum::<i32>() as f64 / utils::get_total_weeks(&scrobbles) as f64
69}
70
71fn calculate_monthly_average(scrobbles: &[SavedScrobble]) -> f64 {
72    let mut groups: HashMap<u32, i32> = HashMap::new();
73
74    scrobbles.iter().for_each(|scrobble| {
75        let group = groups.entry(scrobble.date().month()).or_insert(0);
76        *group += 1;
77    });
78
79    groups.iter().map(|g| g.1).sum::<i32>() as f64 / utils::get_total_months(&scrobbles) as f64
80}
81
82fn calculate_yearly_average(scrobbles: &[SavedScrobble]) -> f64 {
83    let mut groups: HashMap<i32, i32> = HashMap::new();
84
85    scrobbles.iter().for_each(|scrobble| {
86        let group = groups.entry(scrobble.date().year()).or_insert(0);
87        *group += 1
88    });
89
90    groups.iter().map(|g| g.1).sum::<i32>() as f64 / utils::get_total_years(&scrobbles) as f64
91}
92
93fn calculate_best_month(scrobbles: &[SavedScrobble]) -> (String, i32) {
94    let mut groups: HashMap<String, i32> = HashMap::new();
95
96    scrobbles.iter().for_each(|scrobble| {
97        let group = groups.entry(scrobble.month_year()).or_insert(0);
98        *group += 1
99    });
100
101    let mut group_vec = groups.iter().collect::<Vec<(&String, &i32)>>();
102    group_vec.sort_by(|a, b| a.1.cmp(b.1));
103    group_vec.reverse();
104
105    let best_month = group_vec.get(0).expect("Error retrieving best month");
106
107    (best_month.0.to_string(), *best_month.1)
108}