mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-21 22:15:40 +00:00
23f7ba02d6
* feat(player-stats): local listening history tab with heatmap and summaries Record play sessions in library.sqlite when the library index is enabled, add Rust read APIs and Tauri commands for year/day aggregates, and ship the Player stats UI with session clustering, event-driven live refresh, and a notice when some servers are excluded from indexing. * test(player-stats): split play_session repo and expand test coverage Move the repository into play_session/ (completion, cluster, integration tests), add remap/purge/FK coverage in Rust, and cover ingestion gates plus live-refresh hooks on the frontend per spec v0.3. * docs(release): CHANGELOG and credits for player stats (PR #849) * fix(player-stats): satisfy tsc and clippy CI gates Use InternetRadioStation field names in the radio skip test and replace manual month/day range checks with RangeInclusive::contains.
48 lines
1.3 KiB
Rust
48 lines
1.3 KiB
Rust
pub(crate) const MIN_LISTENED_SEC: f64 = 10.0;
|
|
pub(crate) const FULL_COMPLETION_RATIO: f64 = 0.70;
|
|
|
|
pub(crate) fn effective_duration_sec(db_duration_sec: i64, hint: Option<i64>) -> i64 {
|
|
let hint = hint.filter(|d| *d > 0).unwrap_or(0);
|
|
if db_duration_sec > 0 && hint > 0 {
|
|
return db_duration_sec.max(hint);
|
|
}
|
|
if db_duration_sec > 0 {
|
|
return db_duration_sec;
|
|
}
|
|
hint
|
|
}
|
|
|
|
pub(crate) fn completion_from_position(position_max_sec: f64, duration_sec: i64) -> &'static str {
|
|
if duration_sec <= 0 {
|
|
return "partial";
|
|
}
|
|
if position_max_sec / duration_sec as f64 >= FULL_COMPLETION_RATIO {
|
|
"full"
|
|
} else {
|
|
"partial"
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn completion_threshold_at_seventy_percent() {
|
|
assert_eq!(completion_from_position(70.0, 100), "full");
|
|
assert_eq!(completion_from_position(69.0, 100), "partial");
|
|
}
|
|
|
|
#[test]
|
|
fn zero_duration_is_always_partial() {
|
|
assert_eq!(completion_from_position(100.0, 0), "partial");
|
|
}
|
|
|
|
#[test]
|
|
fn effective_duration_prefers_max_of_db_and_hint() {
|
|
assert_eq!(effective_duration_sec(1, Some(300)), 300);
|
|
assert_eq!(effective_duration_sec(200, Some(100)), 200);
|
|
assert_eq!(effective_duration_sec(0, Some(240)), 240);
|
|
}
|
|
}
|