From 5ed278ec9c7c35770a52a888d1b3ed444a4f7a70 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Sun, 24 Nov 2024 11:34:09 -0700 Subject: [PATCH] feat(network): Support for fetching all Sonarr language profiles --- .../blocklist/blocklist_handler_tests.rs | 7 ++ .../library/library_handler_tests.rs | 3 + .../library/movie_details_handler.rs | 1 + .../library/movie_details_handler_tests.rs | 3 + src/models/servarr_data/sonarr/sonarr_data.rs | 2 + .../servarr_data/sonarr/sonarr_data_tests.rs | 1 + src/models/servarr_models.rs | 2 + src/models/sonarr_models.rs | 89 +++++++++++++++ src/models/sonarr_models_tests.rs | 89 ++++++++++++++- src/network/radarr_network_tests.rs | 41 +++---- src/network/sonarr_network.rs | 28 ++++- src/network/sonarr_network_tests.rs | 105 ++++++++++++------ 12 files changed, 311 insertions(+), 60 deletions(-) diff --git a/src/handlers/radarr_handlers/blocklist/blocklist_handler_tests.rs b/src/handlers/radarr_handlers/blocklist/blocklist_handler_tests.rs index d1b94b8..67d7dbf 100644 --- a/src/handlers/radarr_handlers/blocklist/blocklist_handler_tests.rs +++ b/src/handlers/radarr_handlers/blocklist/blocklist_handler_tests.rs @@ -959,6 +959,7 @@ mod tests { id: 3, source_title: "test 1".to_owned(), languages: vec![Language { + id: 1, name: "telgu".to_owned(), }], quality: QualityWrapper { @@ -967,6 +968,7 @@ mod tests { }, }, custom_formats: Some(vec![Language { + id: 2, name: "nikki".to_owned(), }]), date: DateTime::from(DateTime::parse_from_rfc3339("2024-01-10T07:28:45Z").unwrap()), @@ -979,6 +981,7 @@ mod tests { id: 2, source_title: "test 2".to_owned(), languages: vec![Language { + id: 3, name: "chinese".to_owned(), }], quality: QualityWrapper { @@ -988,9 +991,11 @@ mod tests { }, custom_formats: Some(vec![ Language { + id: 4, name: "alex".to_owned(), }, Language { + id: 5, name: "English".to_owned(), }, ]), @@ -1004,6 +1009,7 @@ mod tests { id: 1, source_title: "test 3".to_owned(), languages: vec![Language { + id: 1, name: "english".to_owned(), }], quality: QualityWrapper { @@ -1012,6 +1018,7 @@ mod tests { }, }, custom_formats: Some(vec![Language { + id: 2, name: "English".to_owned(), }]), date: DateTime::from(DateTime::parse_from_rfc3339("2024-03-10T07:28:45Z").unwrap()), diff --git a/src/handlers/radarr_handlers/library/library_handler_tests.rs b/src/handlers/radarr_handlers/library/library_handler_tests.rs index f50c804..22a4cd1 100644 --- a/src/handlers/radarr_handlers/library/library_handler_tests.rs +++ b/src/handlers/radarr_handlers/library/library_handler_tests.rs @@ -1807,6 +1807,7 @@ mod tests { id: 3, title: "test 1".into(), original_language: Language { + id: 1, name: "English".to_owned(), }, size_on_disk: 1024, @@ -1823,6 +1824,7 @@ mod tests { id: 2, title: "test 2".into(), original_language: Language { + id: 2, name: "Chinese".to_owned(), }, size_on_disk: 2048, @@ -1839,6 +1841,7 @@ mod tests { id: 1, title: "test 3".into(), original_language: Language { + id: 3, name: "Japanese".to_owned(), }, size_on_disk: 512, diff --git a/src/handlers/radarr_handlers/library/movie_details_handler.rs b/src/handlers/radarr_handlers/library/movie_details_handler.rs index 501f304..097599a 100644 --- a/src/handlers/radarr_handlers/library/movie_details_handler.rs +++ b/src/handlers/radarr_handlers/library/movie_details_handler.rs @@ -561,6 +561,7 @@ fn releases_sorting_options() -> Vec> { name: "Language", cmp_fn: Some(|a, b| { let default_language_vec = vec![Language { + id: 1, name: "_".to_owned(), }]; let language_a = &a.languages.as_ref().unwrap_or(&default_language_vec)[0]; diff --git a/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs b/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs index fef7f73..e789ad4 100644 --- a/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs +++ b/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs @@ -1987,6 +1987,7 @@ mod tests { fn test_releases_sorting_options_language() { let expected_cmp_fn: fn(&RadarrRelease, &RadarrRelease) -> Ordering = |a, b| { let default_language_vec = vec![Language { + id: 1, name: "_".to_owned(), }]; let language_a = &a.languages.as_ref().unwrap_or(&default_language_vec)[0]; @@ -2191,6 +2192,7 @@ mod tests { rejected: true, seeders: Some(Number::from(1)), languages: Some(vec![Language { + id: 1, name: "Language A".to_owned(), }]), quality: QualityWrapper { @@ -2209,6 +2211,7 @@ mod tests { rejected: false, seeders: Some(Number::from(2)), languages: Some(vec![Language { + id: 2, name: "Language B".to_owned(), }]), quality: QualityWrapper { diff --git a/src/models/servarr_data/sonarr/sonarr_data.rs b/src/models/servarr_data/sonarr/sonarr_data.rs index ea91074..73278dd 100644 --- a/src/models/servarr_data/sonarr/sonarr_data.rs +++ b/src/models/servarr_data/sonarr/sonarr_data.rs @@ -31,6 +31,7 @@ pub struct SonarrData { pub indexer_settings: Option, pub indexer_test_all_results: Option>, pub indexer_test_error: Option, + pub language_profiles_map: BiMap, pub logs: StatefulList, pub quality_profile_map: BiMap, pub queued_events: StatefulTable, @@ -67,6 +68,7 @@ impl Default for SonarrData { indexer_settings: None, indexer_test_error: None, indexer_test_all_results: None, + language_profiles_map: BiMap::new(), logs: StatefulList::default(), quality_profile_map: BiMap::new(), queued_events: StatefulTable::default(), diff --git a/src/models/servarr_data/sonarr/sonarr_data_tests.rs b/src/models/servarr_data/sonarr/sonarr_data_tests.rs index 593cbf3..11ac35a 100644 --- a/src/models/servarr_data/sonarr/sonarr_data_tests.rs +++ b/src/models/servarr_data/sonarr/sonarr_data_tests.rs @@ -59,6 +59,7 @@ mod tests { assert!(sonarr_data.indexer_settings.is_none()); assert!(sonarr_data.indexer_test_error.is_none()); assert!(sonarr_data.indexer_test_all_results.is_none()); + assert!(sonarr_data.language_profiles_map.is_empty()); assert!(sonarr_data.logs.is_empty()); assert!(sonarr_data.quality_profile_map.is_empty()); assert!(sonarr_data.queued_events.is_empty()); diff --git a/src/models/servarr_models.rs b/src/models/servarr_models.rs index 0089f5f..02134e0 100644 --- a/src/models/servarr_models.rs +++ b/src/models/servarr_models.rs @@ -136,6 +136,8 @@ pub struct IndexerField { #[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)] pub struct Language { + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, pub name: String, } diff --git a/src/models/sonarr_models.rs b/src/models/sonarr_models.rs index caac288..ae10239 100644 --- a/src/models/sonarr_models.rs +++ b/src/models/sonarr_models.rs @@ -22,6 +22,28 @@ use super::{ #[path = "sonarr_models_tests.rs"] mod sonarr_models_tests; +#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct AddSeriesBody { + pub tvdb_id: i64, + pub title: String, + pub root_folder_path: String, + pub quality_profile_id: i64, + pub series_type: SeriesType, + pub season_folder: bool, + pub language_profile_id: i64, + pub tags: Vec, + pub add_options: AddSeriesOptions, +} + +#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct AddSeriesOptions { + pub monitor: SeriesMonitor, + pub search_for_cutoff_unmet_episodes: bool, + pub search_for_missing_episodes: bool, +} + #[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct BlocklistItem { @@ -231,6 +253,71 @@ pub struct Series { pub seasons: Option>, } +#[derive( + Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, +)] +#[serde(rename_all = "camelCase")] +pub enum SeriesMonitor { + Unknown, + #[default] + All, + Future, + Missing, + Existing, + FirstSeason, + LastSeason, + LatestSeason, + Pilot, + Recent, + MonitorSpecials, + UnmonitorSpecials, + None, + Skip, +} + +impl Display for SeriesMonitor { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let series_monitor = match self { + SeriesMonitor::Unknown => "unknown", + SeriesMonitor::All => "all", + SeriesMonitor::Future => "future", + SeriesMonitor::Missing => "missing", + SeriesMonitor::Existing => "existing", + SeriesMonitor::FirstSeason => "firstSeason", + SeriesMonitor::LastSeason => "lastSeason", + SeriesMonitor::LatestSeason => "latestSeason", + SeriesMonitor::Pilot => "pilot", + SeriesMonitor::Recent => "recent", + SeriesMonitor::MonitorSpecials => "monitorSpecials", + SeriesMonitor::UnmonitorSpecials => "unmonitorSpecials", + SeriesMonitor::None => "none", + SeriesMonitor::Skip => "skip", + }; + write!(f, "{series_monitor}") + } +} + +impl<'a> EnumDisplayStyle<'a> for SeriesMonitor { + fn to_display_str(self) -> &'a str { + match self { + SeriesMonitor::Unknown => "Unknown", + SeriesMonitor::All => "All Episodes", + SeriesMonitor::Future => "Future Episodes", + SeriesMonitor::Missing => "Missing Episodes", + SeriesMonitor::Existing => "Existing Episodes", + SeriesMonitor::FirstSeason => "Only First Season", + SeriesMonitor::LastSeason => "Only Last Season", + SeriesMonitor::LatestSeason => "Only Latest Season", + SeriesMonitor::Pilot => "Pilot Episode", + SeriesMonitor::Recent => "Recent Episodes", + SeriesMonitor::MonitorSpecials => "Only Specials", + SeriesMonitor::UnmonitorSpecials => "Not Specials", + SeriesMonitor::None => "None", + SeriesMonitor::Skip => "Skip", + } + } +} + #[derive( Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, ValueEnum, )] @@ -494,6 +581,7 @@ pub enum SonarrSerdeable { IndexerSettings(IndexerSettings), Indexers(Vec), IndexerTestResults(Vec), + LanguageProfiles(Vec), LogResponse(LogResponse), QualityProfiles(Vec), QueueEvents(Vec), @@ -535,6 +623,7 @@ serde_enum_from!( IndexerSettings(IndexerSettings), Indexers(Vec), IndexerTestResults(Vec), + LanguageProfiles(Vec), LogResponse(LogResponse), QualityProfiles(Vec), QueueEvents(Vec), diff --git a/src/models/sonarr_models_tests.rs b/src/models/sonarr_models_tests.rs index 0a6aff3..9171342 100644 --- a/src/models/sonarr_models_tests.rs +++ b/src/models/sonarr_models_tests.rs @@ -6,13 +6,13 @@ mod tests { use crate::models::{ radarr_models::IndexerTestResult, servarr_models::{ - DiskSpace, HostConfig, Indexer, Log, LogResponse, QualityProfile, QueueEvent, RootFolder, - SecurityConfig, Tag, Update, + DiskSpace, HostConfig, Indexer, Language, Log, LogResponse, QualityProfile, QueueEvent, + RootFolder, SecurityConfig, Tag, Update, }, sonarr_models::{ BlocklistItem, BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, - IndexerSettings, Series, SeriesStatus, SeriesType, SonarrHistoryEventType, SonarrHistoryItem, - SonarrRelease, SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus, + IndexerSettings, Series, SeriesMonitor, SeriesStatus, SeriesType, SonarrHistoryEventType, + SonarrHistoryItem, SonarrRelease, SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus, }, EnumDisplayStyle, Serdeable, }; @@ -28,6 +28,66 @@ mod tests { assert_str_eq!(episode.to_string(), "Test Title"); } + #[test] + fn test_series_monitor_display() { + assert_str_eq!(SeriesMonitor::Unknown.to_string(), "unknown"); + assert_str_eq!(SeriesMonitor::All.to_string(), "all"); + assert_str_eq!(SeriesMonitor::Future.to_string(), "future"); + assert_str_eq!(SeriesMonitor::Missing.to_string(), "missing"); + assert_str_eq!(SeriesMonitor::Existing.to_string(), "existing"); + assert_str_eq!(SeriesMonitor::FirstSeason.to_string(), "firstSeason"); + assert_str_eq!(SeriesMonitor::LastSeason.to_string(), "lastSeason"); + assert_str_eq!(SeriesMonitor::LatestSeason.to_string(), "latestSeason"); + assert_str_eq!(SeriesMonitor::Pilot.to_string(), "pilot"); + assert_str_eq!(SeriesMonitor::Recent.to_string(), "recent"); + assert_str_eq!( + SeriesMonitor::MonitorSpecials.to_string(), + "monitorSpecials" + ); + assert_str_eq!( + SeriesMonitor::UnmonitorSpecials.to_string(), + "unmonitorSpecials" + ); + assert_str_eq!(SeriesMonitor::None.to_string(), "none"); + assert_str_eq!(SeriesMonitor::Skip.to_string(), "skip"); + } + + #[test] + fn test_series_monitor_to_display_str() { + assert_str_eq!(SeriesMonitor::Unknown.to_display_str(), "Unknown"); + assert_str_eq!(SeriesMonitor::All.to_display_str(), "All Episodes"); + assert_str_eq!(SeriesMonitor::Future.to_display_str(), "Future Episodes"); + assert_str_eq!(SeriesMonitor::Missing.to_display_str(), "Missing Episodes"); + assert_str_eq!( + SeriesMonitor::Existing.to_display_str(), + "Existing Episodes" + ); + assert_str_eq!( + SeriesMonitor::FirstSeason.to_display_str(), + "Only First Season" + ); + assert_str_eq!( + SeriesMonitor::LastSeason.to_display_str(), + "Only Last Season" + ); + assert_str_eq!( + SeriesMonitor::LatestSeason.to_display_str(), + "Only Latest Season" + ); + assert_str_eq!(SeriesMonitor::Pilot.to_display_str(), "Pilot Episode"); + assert_str_eq!(SeriesMonitor::Recent.to_display_str(), "Recent Episodes"); + assert_str_eq!( + SeriesMonitor::MonitorSpecials.to_display_str(), + "Only Specials" + ); + assert_str_eq!( + SeriesMonitor::UnmonitorSpecials.to_display_str(), + "Not Specials" + ); + assert_str_eq!(SeriesMonitor::None.to_display_str(), "None"); + assert_str_eq!(SeriesMonitor::Skip.to_display_str(), "Skip"); + } + #[test] fn test_series_status_display() { assert_str_eq!(SeriesStatus::Continuing.to_string(), "continuing"); @@ -312,6 +372,27 @@ mod tests { assert_eq!(sonarr_serdeable, SonarrSerdeable::DiskSpaces(disk_spaces)); } + #[test] + fn test_sonarr_serdeable_from_language_profiles() { + let language_profiles = vec![ + Language { + id: 1, + name: "English".to_owned(), + }, + Language { + id: 2, + name: "Japanese".to_owned(), + }, + ]; + + let sonarr_serdeable: SonarrSerdeable = language_profiles.clone().into(); + + assert_eq!( + sonarr_serdeable, + SonarrSerdeable::LanguageProfiles(language_profiles) + ); + } + #[test] fn test_sonarr_serdeable_from_log_response() { let log_response = LogResponse { diff --git a/src/network/radarr_network_tests.rs b/src/network/radarr_network_tests.rs index f695f1a..7d8b442 100644 --- a/src/network/radarr_network_tests.rs +++ b/src/network/radarr_network_tests.rs @@ -34,6 +34,7 @@ mod test { "title": "Test", "tmdbId": 1234, "originalLanguage": { + "id": 1, "name": "English" }, "sizeOnDisk": 3543348019, @@ -499,7 +500,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "HD - 1080p" }} }]); let (async_server, app_arc, _server) = mock_servarr_api( @@ -559,7 +560,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "HD - 1080p" }} }]); let (async_server, app_arc, _server) = mock_servarr_api( @@ -607,7 +608,7 @@ mod test { let add_movie_search_result_json = json!([{ "tmdbId": 1234, "title": "Test", - "originalLanguage": { "name": "English" }, + "originalLanguage": { "id": 1, "name": "English" }, "status": "released", "overview": "New movie blah blah blah", "genres": ["cool", "family", "fun"], @@ -672,7 +673,7 @@ mod test { let add_movie_search_result_json = json!([{ "tmdbId": 1234, "title": "Test", - "originalLanguage": { "name": "English" }, + "originalLanguage": { "id": 1, "name": "English" }, "status": "released", "overview": "New movie blah blah blah", "genres": ["cool", "family", "fun"], @@ -1474,6 +1475,7 @@ mod test { "id": 1, "title": "Test", "originalLanguage": { + "id": 1, "name": "English" }, "sizeOnDisk": 0, @@ -1559,7 +1561,7 @@ mod test { let movie_history_item_json = json!([{ "sourceTitle": "Test", "quality": { "quality": { "name": "HD - 1080p" }}, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "date": "2022-12-30T07:37:56Z", "eventType": "grabbed" }]); @@ -1613,7 +1615,7 @@ mod test { let movie_history_item_json = json!([{ "sourceTitle": "Test", "quality": { "quality": { "name": "HD - 1080p" }}, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "date": "2022-12-30T07:37:56Z", "eventType": "grabbed" }]); @@ -1646,7 +1648,7 @@ mod test { let movie_history_item_json = json!([{ "sourceTitle": "Test", "quality": { "quality": { "name": "HD - 1080p" }}, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "date": "2022-12-30T07:37:56Z", "eventType": "grabbed" }]); @@ -1697,9 +1699,9 @@ mod test { "id": 123, "movieId": 1007, "sourceTitle": "z movie", - "languages": [{"name": "English"}], + "languages": [{"id": 1, "name": "English"}], "quality": {"quality": {"name": "HD - 1080p"}}, - "customFormats": [{"name": "English"}], + "customFormats": [{"id": 1, "name": "English"}], "date": "2024-02-10T07:28:45Z", "protocol": "usenet", "indexer": "DrunkenSlug (Prowlarr)", @@ -1708,7 +1710,7 @@ mod test { "id": 1007, "title": "z movie", "tmdbId": 1234, - "originalLanguage": {"name": "English"}, + "originalLanguage": {"id": 1, "name": "English"}, "sizeOnDisk": 3543348019i64, "status": "Downloaded", "overview": "Blah blah blah", @@ -1733,9 +1735,9 @@ mod test { "id": 456, "movieId": 2001, "sourceTitle": "A Movie", - "languages": [{"name": "English"}], + "languages": [{"id": 1, "name": "English"}], "quality": {"quality": {"name": "HD - 1080p"}}, - "customFormats": [{"name": "English"}], + "customFormats": [{"id": 1, "name": "English"}], "date": "2024-02-10T07:28:45Z", "protocol": "usenet", "indexer": "DrunkenSlug (Prowlarr)", @@ -1744,7 +1746,7 @@ mod test { "id": 2001, "title": "A Movie", "tmdbId": 1234, - "originalLanguage": {"name": "English"}, + "originalLanguage": {"id": 1, "name": "English"}, "sizeOnDisk": 3543348019i64, "status": "Downloaded", "overview": "Blah blah blah", @@ -1841,9 +1843,9 @@ mod test { "id": 123, "movieId": 1007, "sourceTitle": "z movie", - "languages": [{"name": "English"}], + "languages": [{"id": 1, "name": "English"}], "quality": {"quality": {"name": "HD - 1080p"}}, - "customFormats": [{"name": "English"}], + "customFormats": [{"id": 1, "name": "English"}], "date": "2024-02-10T07:28:45Z", "protocol": "usenet", "indexer": "DrunkenSlug (Prowlarr)", @@ -1852,7 +1854,7 @@ mod test { "id": 1007, "title": "z movie", "tmdbId": 1234, - "originalLanguage": {"name": "English"}, + "originalLanguage": {"id": 1, "name": "English"}, "sizeOnDisk": 3543348019i64, "status": "Downloaded", "overview": "Blah blah blah", @@ -1877,9 +1879,9 @@ mod test { "id": 456, "movieId": 2001, "sourceTitle": "A Movie", - "languages": [{"name": "English"}], + "languages": [{"id": 1, "name": "English"}], "quality": {"quality": {"name": "HD - 1080p"}}, - "customFormats": [{"name": "English"}], + "customFormats": [{"id": 1, "name": "English"}], "date": "2024-02-10T07:28:45Z", "protocol": "usenet", "indexer": "DrunkenSlug (Prowlarr)", @@ -1888,7 +1890,7 @@ mod test { "id": 2001, "title": "A Movie", "tmdbId": 1234, - "originalLanguage": {"name": "English"}, + "originalLanguage": {"id": 1, "name": "English"}, "sizeOnDisk": 3543348019i64, "status": "Downloaded", "overview": "Blah blah blah", @@ -5076,6 +5078,7 @@ mod test { fn language() -> Language { Language { + id: 1, name: "English".to_owned(), } } diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index 15a221b..fac78d7 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -14,8 +14,8 @@ use crate::{ }, }, servarr_models::{ - AddRootFolderBody, CommandBody, DiskSpace, HostConfig, Indexer, LogResponse, QualityProfile, - QueueEvent, RootFolder, SecurityConfig, Tag, Update, + AddRootFolderBody, CommandBody, DiskSpace, HostConfig, Indexer, Language, LogResponse, + QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update, }, sonarr_models::{ BlocklistResponse, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode, @@ -56,6 +56,7 @@ pub enum SonarrEvent { GetEpisodeDetails(Option), GetEpisodes(Option), GetEpisodeHistory(Option), + GetLanguageProfiles, GetLogs(Option), GetDiskSpace, GetQualityProfiles, @@ -98,6 +99,7 @@ impl NetworkResource for SonarrEvent { SonarrEvent::GetHistory(_) | SonarrEvent::GetEpisodeHistory(_) => "/history", SonarrEvent::GetHostConfig | SonarrEvent::GetSecurityConfig => "/config/host", SonarrEvent::GetIndexers | SonarrEvent::DeleteIndexer(_) => "/indexer", + SonarrEvent::GetLanguageProfiles => "/languageprofile", SonarrEvent::GetLogs(_) => "/log", SonarrEvent::GetDiskSpace => "/diskspace", SonarrEvent::GetQualityProfiles => "/qualityprofile", @@ -203,6 +205,10 @@ impl<'a, 'b> Network<'a, 'b> { .await .map(SonarrSerdeable::from), SonarrEvent::GetIndexers => self.get_sonarr_indexers().await.map(SonarrSerdeable::from), + SonarrEvent::GetLanguageProfiles => self + .get_sonarr_language_profiles() + .await + .map(SonarrSerdeable::from), SonarrEvent::GetLogs(events) => self .get_sonarr_logs(events) .await @@ -951,6 +957,24 @@ impl<'a, 'b> Network<'a, 'b> { .await } + async fn get_sonarr_language_profiles(&mut self) -> Result> { + info!("Fetching Sonarr language profiles"); + let event = SonarrEvent::GetLanguageProfiles; + + let request_props = self + .request_props_from(event, RequestMethod::Get, None::<()>, None, None) + .await; + + self + .handle_request::<(), Vec>(request_props, |language_profiles_vec, mut app| { + app.data.sonarr_data.language_profiles_map = language_profiles_vec + .into_iter() + .map(|language| (language.id, language.name)) + .collect(); + }) + .await + } + async fn get_sonarr_logs(&mut self, events: Option) -> Result { info!("Fetching Sonarr logs"); let event = SonarrEvent::GetLogs(events); diff --git a/src/network/sonarr_network_tests.rs b/src/network/sonarr_network_tests.rs index b7d0625..f7a0b63 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -104,7 +104,7 @@ mod test { "path": "/nfs/tv/series/season 1/episode 1.mkv", "size": 3543348019, "dateAdded": "2024-02-10T07:28:45Z", - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "quality": { "quality": { "name": "Bluray-1080p" } }, "mediaInfo": { "audioBitrate": 0, @@ -235,6 +235,7 @@ mod test { #[case(SonarrEvent::GetBlocklist, "/blocklist?page=1&pageSize=10000")] #[case(SonarrEvent::GetDiskSpace, "/diskspace")] #[case(SonarrEvent::GetSeriesHistory(None), "/history/series")] + #[case(SonarrEvent::GetLanguageProfiles, "/languageprofile")] #[case(SonarrEvent::GetLogs(Some(500)), "/log")] #[case(SonarrEvent::GetQualityProfiles, "/qualityprofile")] #[case(SonarrEvent::GetStatus, "/system/status")] @@ -1274,7 +1275,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1287,7 +1288,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1366,7 +1367,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1379,7 +1380,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1437,7 +1438,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1450,7 +1451,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1763,7 +1764,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1776,7 +1777,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1893,7 +1894,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -1906,7 +1907,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2023,7 +2024,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2036,7 +2037,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2131,7 +2132,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2144,7 +2145,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -2290,6 +2291,39 @@ mod test { .unwrap(); } + #[tokio::test] + async fn test_handle_get_sonarr_language_profiles_event() { + let language_profiles_json = json!([{ + "id": 2222, + "name": "English" + }]); + let response: Vec = serde_json::from_value(language_profiles_json.clone()).unwrap(); + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Get, + None, + Some(language_profiles_json), + None, + SonarrEvent::GetLanguageProfiles, + None, + None, + ) + .await; + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + if let SonarrSerdeable::LanguageProfiles(language_profiles) = network + .handle_sonarr_event(SonarrEvent::GetLanguageProfiles) + .await + .unwrap() + { + async_server.assert_async().await; + assert_eq!( + app_arc.lock().await.data.sonarr_data.language_profiles_map, + BiMap::from_iter([(2222i64, "English".to_owned())]) + ); + assert_eq!(language_profiles, response); + } + } + #[tokio::test] async fn test_handle_get_sonarr_logs_event() { let expected_logs = vec![ @@ -2560,7 +2594,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }} }]); let (async_server, app_arc, _server) = mock_servarr_api( @@ -2627,7 +2661,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }} }]); let (async_server, app_arc, _server) = mock_servarr_api( @@ -2686,7 +2720,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }} }]); let (_async_server, app_arc, _server) = mock_servarr_api( @@ -2721,7 +2755,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }} }]); let (async_server, app_arc, _server) = mock_servarr_api( @@ -2789,7 +2823,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, "fullSeason": true }, @@ -2805,7 +2839,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, } ]); @@ -2889,7 +2923,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, "fullSeason": true }, @@ -2905,7 +2939,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, } ]); @@ -2975,7 +3009,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, "fullSeason": true }, @@ -2991,7 +3025,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, } ]); @@ -3075,7 +3109,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, "fullSeason": true }, @@ -3091,7 +3125,7 @@ mod test { "rejections": [ "Unknown quality profile", "Release is already mapped" ], "seeders": 2, "leechers": 1, - "languages": [ { "name": "English" } ], + "languages": [ { "id": 1, "name": "English" } ], "quality": { "quality": { "name": "Bluray-1080p" }}, } ]); @@ -3318,7 +3352,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3331,7 +3365,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3440,7 +3474,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3453,7 +3487,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3546,7 +3580,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3559,7 +3593,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3648,7 +3682,7 @@ mod test { "sourceTitle": "z episode", "episodeId": 1007, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -3661,7 +3695,7 @@ mod test { "sourceTitle": "A Episode", "episodeId": 2001, "quality": { "quality": { "name": "Bluray-1080p" } }, - "language": { "name": "English" }, + "language": { "id": 1, "name": "English" }, "date": "2024-02-10T07:28:45Z", "eventType": "grabbed", "data": { @@ -5175,6 +5209,7 @@ mod test { fn language() -> Language { Language { + id: 1, name: "English".to_owned(), } }