From 682bc91855b9b13073f19ba26220af12df1543a0 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Fri, 13 Dec 2024 19:44:10 -0700 Subject: [PATCH] fix: Implemented a handful of fixes that are breaking changes between Sonarr v3 and v4 --- README.md | 2 +- .../history/history_handler_tests.rs | 24 ++++--- src/handlers/sonarr_handlers/history/mod.rs | 13 ++-- src/models/sonarr_models.rs | 7 +- src/network/radarr_network.rs | 10 ++- src/network/radarr_network_tests.rs | 6 +- src/network/sonarr_network.rs | 8 +-- src/network/sonarr_network_tests.rs | 72 +++++++++---------- src/ui/radarr_ui/library/mod.rs | 6 +- src/ui/sonarr_ui/downloads/mod.rs | 9 ++- src/ui/sonarr_ui/history/mod.rs | 12 +++- .../sonarr_ui/library/episode_details_ui.rs | 10 ++- src/ui/sonarr_ui/library/season_details_ui.rs | 39 +++++++--- src/ui/sonarr_ui/library/series_details_ui.rs | 10 ++- 14 files changed, 137 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index 260d731..fc91fbc 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,7 @@ with all items tagged `Beta`. ## Servarr Requirements * [Radarr >= 5.3.6.8612](https://radarr.video/docs/api/) -* [Sonarr >= v3](https://sonarr.tv/docs/api/) +* [Sonarr >= v4](https://sonarr.tv/docs/api/) * [Readarr v1](https://readarr.com/docs/api/) * [Lidarr v1](https://lidarr.audio/docs/api/) * [Whisparr >= v3](https://whisparr.com/docs/api/) diff --git a/src/handlers/sonarr_handlers/history/history_handler_tests.rs b/src/handlers/sonarr_handlers/history/history_handler_tests.rs index 67fe9df..c932f20 100644 --- a/src/handlers/sonarr_handlers/history/history_handler_tests.rs +++ b/src/handlers/sonarr_handlers/history/history_handler_tests.rs @@ -240,10 +240,14 @@ mod tests { #[test] fn test_history_sorting_options_language() { let expected_cmp_fn: fn(&SonarrHistoryItem, &SonarrHistoryItem) -> Ordering = |a, b| { - a.language - .name - .to_lowercase() - .cmp(&b.language.name.to_lowercase()) + let default_language = Language { + id: 1, + name: "_".to_owned(), + }; + let language_a = &a.languages.first().unwrap_or(&default_language); + let language_b = &b.languages.first().unwrap_or(&default_language); + + language_a.cmp(language_b) }; let mut expected_history_vec = history_vec(); expected_history_vec.sort_by(expected_cmp_fn); @@ -361,10 +365,10 @@ mod tests { id: 3, source_title: "test 1".into(), event_type: SonarrHistoryEventType::Grabbed, - language: Language { + languages: vec![Language { id: 1, name: "telgu".to_owned(), - }, + }], quality: QualityWrapper { quality: Quality { name: "HD - 1080p".to_owned(), @@ -377,10 +381,10 @@ mod tests { id: 2, source_title: "test 2".into(), event_type: SonarrHistoryEventType::DownloadFolderImported, - language: Language { + languages: vec![Language { id: 3, name: "chinese".to_owned(), - }, + }], quality: QualityWrapper { quality: Quality { name: "SD - 720p".to_owned(), @@ -393,10 +397,10 @@ mod tests { id: 1, source_title: "test 3".into(), event_type: SonarrHistoryEventType::EpisodeFileDeleted, - language: Language { + languages: vec![Language { id: 1, name: "english".to_owned(), - }, + }], quality: QualityWrapper { quality: Quality { name: "HD - 1080p".to_owned(), diff --git a/src/handlers/sonarr_handlers/history/mod.rs b/src/handlers/sonarr_handlers/history/mod.rs index 65ec286..2ad58a6 100644 --- a/src/handlers/sonarr_handlers/history/mod.rs +++ b/src/handlers/sonarr_handlers/history/mod.rs @@ -6,6 +6,7 @@ use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys; use crate::handlers::table_handler::TableHandlingConfig; use crate::handlers::{handle_clear_errors, KeyEventHandler}; use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTORY_BLOCKS}; +use crate::models::servarr_models::Language; use crate::models::sonarr_models::SonarrHistoryItem; use crate::models::stateful_table::SortOption; @@ -142,10 +143,14 @@ pub(in crate::handlers::sonarr_handlers) fn history_sorting_options( SortOption { name: "Language", cmp_fn: Some(|a, b| { - a.language - .name - .to_lowercase() - .cmp(&b.language.name.to_lowercase()) + let default_language = Language { + id: 1, + name: "_".to_owned(), + }; + let language_a = &a.languages.first().unwrap_or(&default_language); + let language_b = &b.languages.first().unwrap_or(&default_language); + + language_a.cmp(language_b) }), }, SortOption { diff --git a/src/models/sonarr_models.rs b/src/models/sonarr_models.rs index e2f5c47..a18acdf 100644 --- a/src/models/sonarr_models.rs +++ b/src/models/sonarr_models.rs @@ -119,7 +119,7 @@ pub struct DownloadRecord { pub output_path: Option, #[serde(default)] pub indexer: String, - pub download_client: String, + pub download_client: Option, } impl Eq for DownloadRecord {} @@ -233,7 +233,7 @@ pub struct EpisodeFile { pub path: String, #[serde(deserialize_with = "super::from_i64")] pub size: i64, - pub language: Language, + pub languages: Vec, pub quality: QualityWrapper, pub date_added: DateTime, pub media_info: Option, @@ -300,6 +300,7 @@ impl Eq for Rating {} #[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Season { + #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(deserialize_with = "super::from_i64")] pub season_number: i64, @@ -587,7 +588,7 @@ pub struct SonarrHistoryItem { #[serde(deserialize_with = "super::from_i64")] pub episode_id: i64, pub quality: QualityWrapper, - pub language: Language, + pub languages: Vec, pub date: DateTime, pub event_type: SonarrHistoryEventType, pub data: SonarrHistoryData, diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index bd074b6..60497af 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -2103,12 +2103,10 @@ impl<'a, 'b> Network<'a, 'b> { .handle_request::(request_props, |test_results, mut app| { if test_results.as_object().is_none() { app.data.radarr_data.indexer_test_errors = Some( - test_results - .as_array() - .unwrap()[0] + test_results.as_array().unwrap()[0] .get("errorMessage") .unwrap() - .to_string() + .to_string(), ); } else { app.data.radarr_data.indexer_test_errors = Some(String::new()); @@ -2254,7 +2252,7 @@ impl<'a, 'b> Network<'a, 'b> { let tags = edit_tags.clone(); let missing_tags_vec = edit_tags .split(',') - .filter(|&tag| !tag.is_empty() && tags_map.get_by_right(tag.trim()).is_none()) + .filter(|&tag| !tag.is_empty() && tags_map.get_by_right(tag.to_lowercase().trim()).is_none()) .collect::>(); for tag in missing_tags_vec { @@ -2273,7 +2271,7 @@ impl<'a, 'b> Network<'a, 'b> { .data .radarr_data .tags_map - .get_by_right(tag.trim()) + .get_by_right(tag.to_lowercase().trim()) .unwrap() }) .collect() diff --git a/src/network/radarr_network_tests.rs b/src/network/radarr_network_tests.rs index a8cf90f..fa2b5a0 100644 --- a/src/network/radarr_network_tests.rs +++ b/src/network/radarr_network_tests.rs @@ -4882,7 +4882,7 @@ mod test { #[tokio::test] async fn test_extract_and_add_radarr_tag_ids_vec() { let app_arc = Arc::new(Mutex::new(App::default())); - let tags = " test,hi ,, usenet ".to_owned(); + let tags = " test,HI ,, usenet ".to_owned(); { let mut app = app_arc.lock().await; app.data.radarr_data.tags_map = BiMap::from_iter([ @@ -4903,7 +4903,7 @@ mod test { async fn test_extract_and_add_radarr_tag_ids_vec_add_missing_tags_first() { let (async_server, app_arc, _server) = mock_servarr_api( RequestMethod::Post, - Some(json!({ "label": "testing" })), + Some(json!({ "label": "TESTING" })), Some(json!({ "id": 3, "label": "testing" })), None, RadarrEvent::GetTags, @@ -4911,7 +4911,7 @@ mod test { None, ) .await; - let tags = "usenet, test, testing".to_owned(); + let tags = "usenet, test, TESTING".to_owned(); { let mut app = app_arc.lock().await; app.data.radarr_data.edit_movie_modal = Some(EditMovieModal { diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index 112486c..2dc10be 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -116,7 +116,7 @@ impl NetworkResource for SonarrEvent { SonarrEvent::GetIndexers | SonarrEvent::DeleteIndexer(_) | SonarrEvent::EditIndexer(_) => { "/indexer" } - SonarrEvent::GetLanguageProfiles => "/languageprofile", + SonarrEvent::GetLanguageProfiles => "/language", SonarrEvent::GetLogs(_) => "/log", SonarrEvent::GetDiskSpace => "/diskspace", SonarrEvent::GetQualityProfiles => "/qualityprofile", @@ -1709,7 +1709,7 @@ impl<'a, 'b> Network<'a, 'b> { Date Added: {}", file.relative_path, file.path, - file.language.name, + file.languages.first().unwrap_or(&Language::default()).name, file.date_added, ); @@ -2730,7 +2730,7 @@ impl<'a, 'b> Network<'a, 'b> { let tags = edit_tags.clone(); let missing_tags_vec = edit_tags .split(',') - .filter(|&tag| !tag.is_empty() && tags_map.get_by_right(tag.trim()).is_none()) + .filter(|&tag| !tag.is_empty() && tags_map.get_by_right(tag.to_lowercase().trim()).is_none()) .collect::>(); for tag in missing_tags_vec { @@ -2749,7 +2749,7 @@ impl<'a, 'b> Network<'a, 'b> { .data .sonarr_data .tags_map - .get_by_right(tag.trim()) + .get_by_right(tag.to_lowercase().trim()) .unwrap() }) .collect() diff --git a/src/network/sonarr_network_tests.rs b/src/network/sonarr_network_tests.rs index 39ebc16..7fb52fb 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -114,7 +114,7 @@ mod test { "path": "/nfs/tv/series/season 1/episode 1.mkv", "size": 3543348019, "dateAdded": "2024-02-10T07:28:45Z", - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "quality": { "quality": { "name": "Bluray-1080p" } }, "mediaInfo": { "audioBitrate": 0, @@ -285,7 +285,7 @@ mod test { #[case(SonarrEvent::HealthCheck, "/health")] #[case(SonarrEvent::GetBlocklist, "/blocklist?page=1&pageSize=10000")] #[case(SonarrEvent::GetDiskSpace, "/diskspace")] - #[case(SonarrEvent::GetLanguageProfiles, "/languageprofile")] + #[case(SonarrEvent::GetLanguageProfiles, "/language")] #[case(SonarrEvent::GetLogs(Some(500)), "/log")] #[case(SonarrEvent::GetQualityProfiles, "/qualityprofile")] #[case(SonarrEvent::GetStatus, "/system/status")] @@ -2791,7 +2791,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2804,7 +2804,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2883,7 +2883,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2896,7 +2896,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2954,7 +2954,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2967,7 +2967,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3396,7 +3396,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3409,7 +3409,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3526,7 +3526,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3539,7 +3539,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3656,7 +3656,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3669,7 +3669,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3764,7 +3764,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3777,7 +3777,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -4447,7 +4447,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -4460,7 +4460,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -4563,7 +4563,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -4576,7 +4576,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -4679,7 +4679,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -4692,7 +4692,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5329,7 +5329,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5342,7 +5342,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5451,7 +5451,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5464,7 +5464,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5557,7 +5557,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5570,7 +5570,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5659,7 +5659,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5672,7 +5672,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "id": 1, "name": "English" }, + "languages": [{ "id": 1, "name": "English" }], "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -7216,7 +7216,7 @@ mod test { #[tokio::test] async fn test_extract_and_add_sonarr_tag_ids_vec() { let app_arc = Arc::new(Mutex::new(App::default())); - let tags = " test,hi ,, usenet ".to_owned(); + let tags = " test,HI ,, usenet ".to_owned(); { let mut app = app_arc.lock().await; app.data.sonarr_data.tags_map = BiMap::from_iter([ @@ -7237,7 +7237,7 @@ mod test { async fn test_extract_and_add_sonarr_tag_ids_vec_add_missing_tags_first() { let (async_server, app_arc, _server) = mock_servarr_api( RequestMethod::Post, - Some(json!({ "label": "testing" })), + Some(json!({ "label": "TESTING" })), Some(json!({ "id": 3, "label": "testing" })), None, SonarrEvent::GetTags, @@ -7245,7 +7245,7 @@ mod test { None, ) .await; - let tags = "usenet, test, testing".to_owned(); + let tags = "usenet, test, TESTING".to_owned(); { let mut app = app_arc.lock().await; app.data.sonarr_data.add_series_modal = Some(AddSeriesModal { @@ -7562,7 +7562,7 @@ mod test { "/nfs/tv/Test show/season 1/", )), indexer: "kickass torrents".to_owned(), - download_client: "transmission".to_owned(), + download_client: Some("transmission".to_owned()), } } @@ -7598,7 +7598,7 @@ mod test { path: "/nfs/tv/series/season 1/episode 1.mkv".to_owned(), size: 3543348019, quality: quality_wrapper(), - language: language(), + languages: vec![language()], date_added: DateTime::from(DateTime::parse_from_rfc3339("2024-02-10T07:28:45Z").unwrap()), media_info: Some(media_info()), } @@ -7624,7 +7624,7 @@ mod test { source_title: "Test source".into(), episode_id: 1, quality: quality_wrapper(), - language: language(), + languages: vec![language()], date: DateTime::from(DateTime::parse_from_rfc3339("2024-02-10T07:28:45Z").unwrap()), event_type: SonarrHistoryEventType::Grabbed, data: history_data(), diff --git a/src/ui/radarr_ui/library/mod.rs b/src/ui/radarr_ui/library/mod.rs index 3ed8db2..3afc071 100644 --- a/src/ui/radarr_ui/library/mod.rs +++ b/src/ui/radarr_ui/library/mod.rs @@ -44,10 +44,8 @@ impl DrawUi for LibraryUi { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { let route = app.get_current_route(); - if !matches!(route, Route::Radarr(_, Some(_))) { - draw_library(f, app, area); - } - + draw_library(f, app, area); + match route { _ if MovieDetailsUi::accepts(route) => MovieDetailsUi::draw(f, app, area), _ if AddMovieUi::accepts(route) => AddMovieUi::draw(f, app, area), diff --git a/src/ui/sonarr_ui/downloads/mod.rs b/src/ui/sonarr_ui/downloads/mod.rs index 3ef77a3..ba3238f 100644 --- a/src/ui/sonarr_ui/downloads/mod.rs +++ b/src/ui/sonarr_ui/downloads/mod.rs @@ -32,7 +32,7 @@ impl DrawUi for DownloadsUi { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { draw_downloads(f, app, area); - + match active_sonarr_block { ActiveSonarrBlock::DeleteDownloadPrompt => { let prompt = format!( @@ -115,7 +115,12 @@ fn draw_downloads(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { .to_string(), ), Cell::from(indexer.to_owned()), - Cell::from(download_client.to_owned()), + Cell::from( + download_client + .as_ref() + .unwrap_or(&String::new()) + .to_owned(), + ), ]) .primary() }; diff --git a/src/ui/sonarr_ui/history/mod.rs b/src/ui/sonarr_ui/history/mod.rs index 0ac32d1..268bfdc 100644 --- a/src/ui/sonarr_ui/history/mod.rs +++ b/src/ui/sonarr_ui/history/mod.rs @@ -40,7 +40,7 @@ impl DrawUi for HistoryUi { fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() { draw_history_table(f, app, area); - + if active_sonarr_block == ActiveSonarrBlock::HistoryItemDetails { draw_history_item_details_popup(f, app); } @@ -64,7 +64,7 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { let history_row_mapping = |history_item: &SonarrHistoryItem| { let SonarrHistoryItem { source_title, - language, + languages, quality, event_type, date, @@ -80,7 +80,13 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { Row::new(vec![ Cell::from(source_title.to_string()), Cell::from(event_type.to_string()), - Cell::from(language.name.to_owned()), + Cell::from( + languages + .iter() + .map(|language| language.name.to_owned()) + .collect::>() + .join(","), + ), Cell::from(quality.quality.name.to_owned()), Cell::from(date.to_string()), ]) diff --git a/src/ui/sonarr_ui/library/episode_details_ui.rs b/src/ui/sonarr_ui/library/episode_details_ui.rs index d9d526b..b3b5f8a 100644 --- a/src/ui/sonarr_ui/library/episode_details_ui.rs +++ b/src/ui/sonarr_ui/library/episode_details_ui.rs @@ -254,7 +254,7 @@ fn draw_episode_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) let history_row_mapping = |history_item: &SonarrHistoryItem| { let SonarrHistoryItem { source_title, - language, + languages, quality, event_type, date, @@ -270,7 +270,13 @@ fn draw_episode_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) Row::new(vec![ Cell::from(source_title.to_string()), Cell::from(event_type.to_string()), - Cell::from(language.name.to_owned()), + Cell::from( + languages + .iter() + .map(|language| language.name.to_owned()) + .collect::>() + .join(","), + ), Cell::from(quality.quality.name.to_owned()), Cell::from(date.to_string()), ]) diff --git a/src/ui/sonarr_ui/library/season_details_ui.rs b/src/ui/sonarr_ui/library/season_details_ui.rs index 97885ec..523d9ba 100644 --- a/src/ui/sonarr_ui/library/season_details_ui.rs +++ b/src/ui/sonarr_ui/library/season_details_ui.rs @@ -4,6 +4,7 @@ use crate::models::sonarr_models::{ DownloadRecord, DownloadStatus, Episode, SonarrHistoryEventType, SonarrHistoryItem, SonarrRelease, }; use crate::models::Route; +use crate::ui::sonarr_ui::library::episode_details_ui::EpisodeDetailsUi; use crate::ui::sonarr_ui::sonarr_ui_utils::{ create_download_failed_history_event_details, create_download_folder_imported_history_event_details, @@ -27,7 +28,6 @@ use ratatui::layout::{Alignment, Constraint, Rect}; use ratatui::prelude::{Line, Style, Stylize, Text}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::Frame; -use crate::ui::sonarr_ui::library::episode_details_ui::EpisodeDetailsUi; #[cfg(test)] #[path = "season_details_ui_tests.rs"] @@ -38,7 +38,8 @@ pub(super) struct SeasonDetailsUi; impl DrawUi for SeasonDetailsUi { fn accepts(route: Route) -> bool { if let Route::Sonarr(active_sonarr_block, _) = route { - return EpisodeDetailsUi::accepts(route) || SEASON_DETAILS_BLOCKS.contains(&active_sonarr_block); + return EpisodeDetailsUi::accepts(route) + || SEASON_DETAILS_BLOCKS.contains(&active_sonarr_block); } false @@ -52,7 +53,15 @@ impl DrawUi for SeasonDetailsUi { let content_area = draw_tabs( f, popup_area, - &format!("Season {} Details", app.data.sonarr_data.seasons.current_selection().season_number), + &format!( + "Season {} Details", + app + .data + .sonarr_data + .seasons + .current_selection() + .season_number + ), &app .data .sonarr_data @@ -113,7 +122,7 @@ impl DrawUi for SeasonDetailsUi { }; draw_popup(f, app, draw_season_details_popup, Size::XLarge); - + if EpisodeDetailsUi::accepts(route) { EpisodeDetailsUi::draw(f, app, _area); } @@ -259,7 +268,7 @@ fn draw_season_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { let history_row_mapping = |history_item: &SonarrHistoryItem| { let SonarrHistoryItem { source_title, - language, + languages, quality, event_type, date, @@ -275,7 +284,13 @@ fn draw_season_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { Row::new(vec![ Cell::from(source_title.to_string()), Cell::from(event_type.to_string()), - Cell::from(language.name.to_owned()), + Cell::from( + languages + .iter() + .map(|language| language.name.to_owned()) + .collect::>() + .join(","), + ), Cell::from(quality.quality.name.to_owned()), Cell::from(date.to_string()), ]) @@ -339,11 +354,13 @@ fn draw_season_releases(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { let (current_selection, is_empty) = if season_details_modal.season_releases.is_empty() { (SonarrRelease::default(), true) } else { - (season_details_modal - .season_releases - .current_selection() - .clone(), - season_details_modal.season_releases.is_empty()) + ( + season_details_modal + .season_releases + .current_selection() + .clone(), + season_details_modal.season_releases.is_empty(), + ) }; let season_release_table_footer = season_details_modal .season_details_tabs diff --git a/src/ui/sonarr_ui/library/series_details_ui.rs b/src/ui/sonarr_ui/library/series_details_ui.rs index 1d18163..ddeee4e 100644 --- a/src/ui/sonarr_ui/library/series_details_ui.rs +++ b/src/ui/sonarr_ui/library/series_details_ui.rs @@ -312,7 +312,7 @@ fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { let history_row_mapping = |history_item: &SonarrHistoryItem| { let SonarrHistoryItem { source_title, - language, + languages, quality, event_type, date, @@ -328,7 +328,13 @@ fn draw_series_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { Row::new(vec![ Cell::from(source_title.to_string()), Cell::from(event_type.to_string()), - Cell::from(language.name.to_owned()), + Cell::from( + languages + .iter() + .map(|language| language.name.to_owned()) + .collect::>() + .join(","), + ), Cell::from(quality.quality.name.to_owned()), Cell::from(date.to_string()), ])