fix(sonarr): stop marking seasons fully downloaded when no episodes are known

A monitored season rendered in the fully downloaded colour whenever Sonarr returned no statistics for it, and whenever it genuinely had zero known episodes. Both cases compared zero against zero and short circuited to the downloaded style, claiming the user had every episode of a season that was only announced, or that had never been scanned.

Seasons whose statistics are absent now render as indeterminate, matching the series row and the equivalent album and book rows in the other trees, and the downloaded style now requires a positive episode count.
This commit is contained in:
Dark-Alex-17 committed 2026-09-10 15:09:40 -06:00
1 parent c069ed4a9b
commit db8e97a700
2 files changed
+38 -28

No files matched your search

+7 -14
View File
@@ -278,23 +278,13 @@ fn draw_seasons_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
} }
fn decorate_season_row_with_style<'a>(season: &Season, row: Row<'a>) -> Row<'a> { fn decorate_season_row_with_style<'a>(season: &Season, row: Row<'a>) -> Row<'a> {
let SeasonStatistics {
episode_file_count,
episode_count,
next_airing,
..
} = if let Some(stats) = &season.statistics {
stats
} else {
&SeasonStatistics::default()
};
if !season.monitored { if !season.monitored {
row.unmonitored() row.unmonitored()
} else if episode_file_count == episode_count { } else if let Some(stats) = season.statistics.as_ref() {
if stats.episode_file_count == stats.episode_count && stats.episode_count > 0 {
row.downloaded() row.downloaded()
} else if let Some(next_airing_utc) = next_airing.as_ref() { } else if let Some(next_airing) = stats.next_airing.as_ref() {
if next_airing_utc > &Utc::now() { if next_airing > &Utc::now() {
row.unreleased() row.unreleased()
} else { } else {
row.missing() row.missing()
@@ -302,6 +292,9 @@ fn decorate_season_row_with_style<'a>(season: &Season, row: Row<'a>) -> Row<'a>
} else { } else {
row.missing() row.missing()
} }
} else {
row.indeterminate()
}
} }
fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
@@ -62,20 +62,6 @@ mod tests {
assert_eq!(style, row.downloaded()); assert_eq!(style, row.downloaded());
} }
#[test]
fn test_decorate_season_row_with_style_downloaded_when_no_statistics() {
let season = Season {
monitored: true,
statistics: None,
..Season::default()
};
let row = Row::new(vec![Cell::from("test".to_owned())]);
let style = decorate_season_row_with_style(&season, row.clone());
assert_eq!(style, row.downloaded());
}
#[test] #[test]
fn test_decorate_season_row_with_style_unreleased_when_episodes_are_missing_and_next_airing_is_future() fn test_decorate_season_row_with_style_unreleased_when_episodes_are_missing_and_next_airing_is_future()
{ {
@@ -135,6 +121,37 @@ mod tests {
assert_eq!(style, row.missing()); assert_eq!(style, row.missing());
} }
#[test]
fn test_decorate_season_row_with_style_missing_when_episode_count_is_zero() {
let season = Season {
monitored: true,
statistics: Some(SeasonStatistics {
next_airing: Some(Utc::now() - Duration::days(1)),
..SeasonStatistics::default()
}),
..Season::default()
};
let row = Row::new(vec![Cell::from("test".to_owned())]);
let style = decorate_season_row_with_style(&season, row.clone());
assert_eq!(style, row.missing());
}
#[test]
fn test_decorate_season_row_with_style_indeterminate_when_no_statistics() {
let season = Season {
monitored: true,
statistics: None,
..Season::default()
};
let row = Row::new(vec![Cell::from("test".to_owned())]);
let style = decorate_season_row_with_style(&season, row.clone());
assert_eq!(style, row.indeterminate());
}
mod snapshot_tests { mod snapshot_tests {
use crate::models::stateful_table::StatefulTable; use crate::models::stateful_table::StatefulTable;
use crate::ui::ui_test_utils::test_utils::TerminalSize; use crate::ui::ui_test_utils::test_utils::TerminalSize;