fix: Modified the Sonarr DownloadRecord so that the episode_id is optional to prevent crashes for weird downloads

This commit is contained in:
2025-03-01 14:50:20 -07:00
parent 58723cf3e8
commit 847de75713
7 changed files with 52 additions and 18 deletions
@@ -191,7 +191,7 @@ pub(in crate::handlers::sonarr_handlers) mod utils {
title: "Test Download Title".to_owned(), title: "Test Download Title".to_owned(),
status: DownloadStatus::Downloading, status: DownloadStatus::Downloading,
id: 1, id: 1,
episode_id: 1, episode_id: Some(Number::from(1i64)),
size: 3543348019f64, size: 3543348019f64,
sizeleft: 1771674009f64, sizeleft: 1771674009f64,
output_path: Some(HorizontallyScrollableText::from( output_path: Some(HorizontallyScrollableText::from(
+1 -2
View File
@@ -112,8 +112,7 @@ pub struct DownloadRecord {
pub status: DownloadStatus, pub status: DownloadStatus,
#[serde(deserialize_with = "super::from_i64")] #[serde(deserialize_with = "super::from_i64")]
pub id: i64, pub id: i64,
#[serde(deserialize_with = "super::from_i64")] pub episode_id: Option<Number>,
pub episode_id: i64,
#[serde(deserialize_with = "super::from_f64")] #[serde(deserialize_with = "super::from_f64")]
pub size: f64, pub size: f64,
#[serde(deserialize_with = "super::from_f64")] #[serde(deserialize_with = "super::from_f64")]
+1 -1
View File
@@ -133,7 +133,7 @@ impl<'a, 'b> Network<'a, 'b> {
} }
} else { } else {
let status = response.status(); let status = response.status();
let whitespace_regex = Regex::new(r"\s+").unwrap(); let whitespace_regex = Regex::new(r"\s+")?;
let response_body = response.text().await.unwrap_or_default(); let response_body = response.text().await.unwrap_or_default();
let error_body = whitespace_regex let error_body = whitespace_regex
.replace_all(&response_body.replace('\n', " "), " ") .replace_all(&response_body.replace('\n', " "), " ")
+11 -5
View File
@@ -1,7 +1,7 @@
use anyhow::Result; use anyhow::Result;
use indoc::formatdoc; use indoc::formatdoc;
use log::{debug, info, warn}; use log::{debug, info, warn};
use serde_json::{json, Value}; use serde_json::{json, Number, Value};
use urlencoding::encode; use urlencoding::encode;
use super::{Network, NetworkEvent, NetworkResource}; use super::{Network, NetworkEvent, NetworkResource};
@@ -2321,10 +2321,16 @@ impl Network<'_, '_> {
fn get_episode_status(has_file: bool, downloads_vec: &[DownloadRecord], episode_id: i64) -> String { fn get_episode_status(has_file: bool, downloads_vec: &[DownloadRecord], episode_id: i64) -> String {
if !has_file { if !has_file {
if let Some(download) = downloads_vec let default_episode_id = Number::from(-1i64);
.iter() if let Some(download) = downloads_vec.iter().find(|&download| {
.find(|&download| download.episode_id == episode_id) download
{ .episode_id
.as_ref()
.unwrap_or(&default_episode_id)
.as_i64()
.unwrap()
== episode_id
}) {
if download.status == DownloadStatus::Downloading { if download.status == DownloadStatus::Downloading {
return "Downloading".to_owned(); return "Downloading".to_owned();
} }
+16 -4
View File
@@ -5438,7 +5438,7 @@ mod test {
#[test] #[test]
fn test_get_episode_status_missing() { fn test_get_episode_status_missing() {
let download_record = DownloadRecord { let download_record = DownloadRecord {
episode_id: 1, episode_id: Some(Number::from(1i64)),
..DownloadRecord::default() ..DownloadRecord::default()
}; };
@@ -5450,13 +5450,25 @@ mod test {
assert_str_eq!(get_episode_status(false, &[download_record], 1), "Missing"); assert_str_eq!(get_episode_status(false, &[download_record], 1), "Missing");
} }
#[test]
fn test_get_episode_status_missing_if_episode_id_is_missing() {
let download_record = DownloadRecord::default();
assert_str_eq!(
get_episode_status(false, &[download_record.clone()], 0),
"Missing"
);
assert_str_eq!(get_episode_status(false, &[download_record], 1), "Missing");
}
#[test] #[test]
fn test_get_episode_status_downloading() { fn test_get_episode_status_downloading() {
assert_str_eq!( assert_str_eq!(
get_episode_status( get_episode_status(
false, false,
&[DownloadRecord { &[DownloadRecord {
episode_id: 1, episode_id: Some(Number::from(1i64)),
status: DownloadStatus::Downloading, status: DownloadStatus::Downloading,
..DownloadRecord::default() ..DownloadRecord::default()
}], }],
@@ -5472,7 +5484,7 @@ mod test {
get_episode_status( get_episode_status(
false, false,
&[DownloadRecord { &[DownloadRecord {
episode_id: 1, episode_id: Some(Number::from(1i64)),
status: DownloadStatus::Completed, status: DownloadStatus::Completed,
..DownloadRecord::default() ..DownloadRecord::default()
}], }],
@@ -5523,7 +5535,7 @@ mod test {
title: "Test Download Title".to_owned(), title: "Test Download Title".to_owned(),
status: DownloadStatus::Downloading, status: DownloadStatus::Downloading,
id: 1, id: 1,
episode_id: 1, episode_id: Some(Number::from(1i64)),
size: 3543348019f64, size: 3543348019f64,
sizeleft: 1771674009f64, sizeleft: 1771674009f64,
output_path: Some(HorizontallyScrollableText::from( output_path: Some(HorizontallyScrollableText::from(
+11 -1
View File
@@ -29,6 +29,7 @@ use ratatui::style::{Style, Stylize};
use ratatui::text::{Line, Span, Text}; use ratatui::text::{Line, Span, Text};
use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use ratatui::Frame; use ratatui::Frame;
use serde_json::Number;
#[cfg(test)] #[cfg(test)]
#[path = "episode_details_ui_tests.rs"] #[path = "episode_details_ui_tests.rs"]
@@ -128,13 +129,22 @@ fn draw_episode_details(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
if let Some(episode_details_modal) = season_details_modal.episode_details_modal.as_ref() { if let Some(episode_details_modal) = season_details_modal.episode_details_modal.as_ref() {
let episode = season_details_modal.episodes.current_selection().clone(); let episode = season_details_modal.episodes.current_selection().clone();
let episode_details = &episode_details_modal.episode_details; let episode_details = &episode_details_modal.episode_details;
let default_episode_id = Number::from(-1i64);
let download = app let download = app
.data .data
.sonarr_data .sonarr_data
.downloads .downloads
.items .items
.iter() .iter()
.find(|&download| download.episode_id == episode.id); .find(|&download| {
download
.episode_id
.as_ref()
.unwrap_or(&default_episode_id)
.as_i64()
.unwrap()
== episode.id
});
let text = Text::from( let text = Text::from(
episode_details episode_details
.items .items
+11 -4
View File
@@ -28,6 +28,7 @@ use ratatui::layout::{Alignment, Constraint, Rect};
use ratatui::prelude::{Line, Style, Stylize, Text}; use ratatui::prelude::{Line, Style, Stylize, Text};
use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
use ratatui::Frame; use ratatui::Frame;
use serde_json::Number;
#[cfg(test)] #[cfg(test)]
#[path = "season_details_ui_tests.rs"] #[path = "season_details_ui_tests.rs"]
@@ -573,10 +574,16 @@ fn decorate_with_row_style<'a>(
row: Row<'a>, row: Row<'a>,
) -> Row<'a> { ) -> Row<'a> {
if !episode.has_file { if !episode.has_file {
if let Some(download) = downloads_vec let default_episode_id = Number::from(-1i64);
.iter() if let Some(download) = downloads_vec.iter().find(|&download| {
.find(|&download| download.episode_id == episode.id) download
{ .episode_id
.as_ref()
.unwrap_or(&default_episode_id)
.as_i64()
.unwrap()
== episode.id
}) {
if download.status == DownloadStatus::Downloading { if download.status == DownloadStatus::Downloading {
return row.downloading(); return row.downloading();
} }