diff --git a/src/network/sonarr_network.rs b/src/network/sonarr_network.rs index 88a505c..d5c7b92 100644 --- a/src/network/sonarr_network.rs +++ b/src/network/sonarr_network.rs @@ -73,8 +73,9 @@ pub enum SonarrEvent { StartTask(Option), TestIndexer(Option), TestAllIndexers, - TriggerAutomaticSeriesSearch(Option), + TriggerAutomaticEpisodeSearch(Option), TriggerAutomaticSeasonSearch(Option<(i64, i64)>), + TriggerAutomaticSeriesSearch(Option), } impl NetworkResource for SonarrEvent { @@ -96,7 +97,8 @@ impl NetworkResource for SonarrEvent { SonarrEvent::GetQueuedEvents | SonarrEvent::StartTask(_) | SonarrEvent::TriggerAutomaticSeriesSearch(_) - | SonarrEvent::TriggerAutomaticSeasonSearch(_) => "/command", + | SonarrEvent::TriggerAutomaticSeasonSearch(_) + | SonarrEvent::TriggerAutomaticEpisodeSearch(_) => "/command", SonarrEvent::GetRootFolders | SonarrEvent::DeleteRootFolder(_) | SonarrEvent::AddRootFolder(_) => "/rootfolder", @@ -244,12 +246,16 @@ impl<'a, 'b> Network<'a, 'b> { .test_all_sonarr_indexers() .await .map(SonarrSerdeable::from), + SonarrEvent::TriggerAutomaticSeasonSearch(params) => self + .trigger_automatic_season_search(params) + .await + .map(SonarrSerdeable::from), SonarrEvent::TriggerAutomaticSeriesSearch(series_id) => self .trigger_automatic_series_search(series_id) .await .map(SonarrSerdeable::from), - SonarrEvent::TriggerAutomaticSeasonSearch(params) => self - .trigger_automatic_season_search(params) + SonarrEvent::TriggerAutomaticEpisodeSearch(episode_id) => self + .trigger_automatic_episode_search(episode_id) .await .map(SonarrSerdeable::from), } @@ -1449,6 +1455,7 @@ impl<'a, 'b> Network<'a, 'b> { let event = SonarrEvent::TriggerAutomaticSeriesSearch(series_id); let (id, _) = self.extract_series_id(series_id).await; info!("Searching indexers for series with ID: {id}"); + let body = SonarrCommandBody { name: "SeriesSearch".to_owned(), series_id: Some(id), @@ -1496,6 +1503,26 @@ impl<'a, 'b> Network<'a, 'b> { .await } + async fn trigger_automatic_episode_search(&mut self, episode_id: Option) -> Result { + let event = SonarrEvent::TriggerAutomaticEpisodeSearch(episode_id); + let id = self.extract_episode_id(episode_id).await; + info!("Searching indexers for episode with ID: {id}"); + + let body = SonarrCommandBody { + name: "EpisodeSearch".to_owned(), + episode_ids: Some(vec![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 ebc24e8..c6f13c1 100644 --- a/src/network/sonarr_network_tests.rs +++ b/src/network/sonarr_network_tests.rs @@ -166,8 +166,9 @@ mod test { #[values( SonarrEvent::GetQueuedEvents, SonarrEvent::StartTask(None), - SonarrEvent::TriggerAutomaticSeriesSearch(None), - SonarrEvent::TriggerAutomaticSeasonSearch(None) + SonarrEvent::TriggerAutomaticEpisodeSearch(None), + SonarrEvent::TriggerAutomaticSeasonSearch(None), + SonarrEvent::TriggerAutomaticSeriesSearch(None) )] event: SonarrEvent, ) { @@ -4234,6 +4235,83 @@ mod test { } } + #[tokio::test] + async fn test_handle_trigger_automatic_episode_search_event() { + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Post, + Some(json!({ + "name": "EpisodeSearch", + "episodeIds": [ 1 ] + })), + Some(json!({})), + None, + SonarrEvent::TriggerAutomaticEpisodeSearch(None), + None, + None, + ) + .await; + let mut season_details_modal = SeasonDetailsModal::default(); + season_details_modal.episodes.set_items(vec![episode()]); + app_arc.lock().await.data.sonarr_data.season_details_modal = Some(season_details_modal); + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + assert!(network + .handle_sonarr_event(SonarrEvent::TriggerAutomaticEpisodeSearch(None)) + .await + .is_ok()); + + async_server.assert_async().await; + } + + #[tokio::test] + async fn test_handle_trigger_automatic_episode_search_event_uses_provided_id() { + let (async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Post, + Some(json!({ + "name": "EpisodeSearch", + "episodeIds": [ 1 ] + })), + Some(json!({})), + None, + SonarrEvent::TriggerAutomaticEpisodeSearch(Some(1)), + None, + None, + ) + .await; + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + assert!(network + .handle_sonarr_event(SonarrEvent::TriggerAutomaticEpisodeSearch(Some(1))) + .await + .is_ok()); + + async_server.assert_async().await; + } + + #[tokio::test] + #[should_panic(expected = "Season details have not been loaded")] + async fn test_handle_trigger_automatic_episode_search_event_empty_season_details_modal_panics() { + let (_async_server, app_arc, _server) = mock_servarr_api( + RequestMethod::Post, + Some(json!({ + "name": "EpisodeSearch", + "episodeIds": [ 1 ] + })), + Some(json!({})), + None, + SonarrEvent::TriggerAutomaticEpisodeSearch(None), + None, + None, + ) + .await; + let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); + + network + .handle_sonarr_event(SonarrEvent::TriggerAutomaticEpisodeSearch(None)) + .await + .unwrap(); + } + #[tokio::test] async fn test_handle_trigger_automatic_season_search_event() { let (async_server, app_arc, _server) = mock_servarr_api(