diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index f812859..88a505c 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -74,6 +74,7 @@ pub enum SonarrEvent { TestIndexer(Option), TestAllIndexers, TriggerAutomaticSeriesSearch(Option), + TriggerAutomaticSeasonSearch(Option<(i64, i64)>), } impl NetworkResource for SonarrEvent { @@ -94,7 +95,8 @@ impl NetworkResource for SonarrEvent { SonarrEvent::GetQualityProfiles => "/qualityprofile", SonarrEvent::GetQueuedEvents | SonarrEvent::StartTask(_) - | SonarrEvent::TriggerAutomaticSeriesSearch(_) => "/command", + | SonarrEvent::TriggerAutomaticSeriesSearch(_) + | SonarrEvent::TriggerAutomaticSeasonSearch(_) => "/command", SonarrEvent::GetRootFolders | SonarrEvent::DeleteRootFolder(_) | SonarrEvent::AddRootFolder(_) => "/rootfolder", @@ -246,6 +248,10 @@ impl<'a, 'b> Network<'a, 'b> { .trigger_automatic_series_search(series_id) .await .map(SonarrSerdeable::from), + SonarrEvent::TriggerAutomaticSeasonSearch(params) => self + .trigger_automatic_season_search(params) + .await + .map(SonarrSerdeable::from), } } @@ -1458,6 +1464,38 @@ impl<'a, 'b> Network<'a, 'b> { .await } + async fn trigger_automatic_season_search( + &mut self, + series_season_id_tuple: Option<(i64, i64)>, + ) -> Result { + let event = SonarrEvent::TriggerAutomaticSeasonSearch(series_season_id_tuple); + let (series_id, season_number) = + if let Some((series_id, season_number)) = series_season_id_tuple { + (Some(series_id), Some(season_number)) + } else { + (None, None) + }; + + let (series_id, _) = self.extract_series_id(series_id).await; + let (season_number, _) = self.extract_season_number(season_number).await; + info!("Searching indexers for series with ID: {series_id} and season number: {season_number}"); + + let body = SonarrCommandBody { + name: "SeasonSearch".to_owned(), + season_number: Some(season_number), + series_id: Some(series_id), + ..SonarrCommandBody::default() + }; + + let request_props = self + .request_props_from(event, RequestMethod::Post, Some(body), None, None) + .await; + + self + .handle_request::(request_props, |_, _| ()) + .await + } + async fn extract_series_id(&mut self, series_id: Option) -> (i64, String) { let series_id = if let Some(id) = series_id { id diff --git a/src/network/sonarr_network_tests.rs b/src/network/sonarr_network_tests.rs index e65dd1a..ebc24e8 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -166,7 +166,8 @@ mod test { #[values( SonarrEvent::GetQueuedEvents, SonarrEvent::StartTask(None), - SonarrEvent::TriggerAutomaticSeriesSearch(None) + SonarrEvent::TriggerAutomaticSeriesSearch(None), + SonarrEvent::TriggerAutomaticSeasonSearch(None) )] event: SonarrEvent, ) { @@ -4233,6 +4234,132 @@ mod test { } } + #[tokio::test] + async fn test_handle_trigger_automatic_season_search_event() { + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Post, + Some(json!({ + "name": "SeasonSearch", + "seriesId": 1, + "seasonNumber": 1 + })), + Some(json!({})), + None, + SonarrEvent::TriggerAutomaticSeasonSearch(None), + None, + None, + ) + .await; + app_arc + .lock() + .await + .data + .sonarr_data + .series + .set_items(vec![series()]); + app_arc + .lock() + .await + .data + .sonarr_data + .seasons + .set_items(vec![season()]); + app_arc.lock().await.data.sonarr_data.season_details_modal = + Some(SeasonDetailsModal::default()); + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + assert!(network + .handle_sonarr_event(SonarrEvent::TriggerAutomaticSeasonSearch(None)) + .await + .is_ok()); + + async_server.assert_async().await; + } + + #[tokio::test] + async fn test_handle_trigger_automatic_season_search_event_uses_provided_series_id_and_season_number( + ) { + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Post, + Some(json!({ + "name": "SeasonSearch", + "seriesId": 2, + "seasonNumber": 2 + })), + Some(json!({})), + None, + SonarrEvent::TriggerAutomaticSeasonSearch(None), + None, + None, + ) + .await; + app_arc + .lock() + .await + .data + .sonarr_data + .series + .set_items(vec![series()]); + app_arc + .lock() + .await + .data + .sonarr_data + .seasons + .set_items(vec![season()]); + app_arc.lock().await.data.sonarr_data.season_details_modal = + Some(SeasonDetailsModal::default()); + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + assert!(network + .handle_sonarr_event(SonarrEvent::TriggerAutomaticSeasonSearch(Some((2, 2)))) + .await + .is_ok()); + + async_server.assert_async().await; + } + + #[tokio::test] + async fn test_handle_trigger_automatic_season_search_event_filtered_series_and_filtered_seasons() + { + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Post, + Some(json!({ + "name": "SeasonSearch", + "seriesId": 1, + "seasonNumber": 1 + })), + Some(json!({})), + None, + SonarrEvent::TriggerAutomaticSeasonSearch(None), + None, + None, + ) + .await; + let mut filtered_series = StatefulTable::default(); + filtered_series.set_filtered_items(vec![Series { + id: 1, + ..Series::default() + }]); + app_arc.lock().await.data.sonarr_data.series = filtered_series; + let mut filtered_seasons = StatefulTable::default(); + filtered_seasons.set_filtered_items(vec![Season { + season_number: 1, + ..Season::default() + }]); + app_arc.lock().await.data.sonarr_data.seasons = filtered_seasons; + app_arc.lock().await.data.sonarr_data.season_details_modal = + Some(SeasonDetailsModal::default()); + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + assert!(network + .handle_sonarr_event(SonarrEvent::TriggerAutomaticSeasonSearch(None)) + .await + .is_ok()); + + async_server.assert_async().await; + } + #[tokio::test] async fn test_handle_trigger_automatic_series_search_event() { let (async_server, app_arc, _server) = mock_servarr_api(