fix(sonarr): Pass the episode ID alongside all GetEpisodeDetails events when publishing to the networking channel

This commit is contained in:
2024-12-17 23:52:18 -07:00
parent 4fdf9b3df1
commit 30ba1f3317
6 changed files with 54 additions and 73 deletions
+15 -1
View File
@@ -69,7 +69,9 @@ impl<'a> App<'a> {
} }
ActiveSonarrBlock::EpisodeDetails | ActiveSonarrBlock::EpisodeFile => { ActiveSonarrBlock::EpisodeDetails | ActiveSonarrBlock::EpisodeFile => {
self self
.dispatch_network_event(SonarrEvent::GetEpisodeDetails(None).into()) .dispatch_network_event(
SonarrEvent::GetEpisodeDetails(self.extract_episode_id().await).into(),
)
.await; .await;
} }
ActiveSonarrBlock::EpisodeHistory => { ActiveSonarrBlock::EpisodeHistory => {
@@ -242,4 +244,16 @@ impl<'a> App<'a> {
.collect(); .collect();
self.data.sonarr_data.seasons.set_items(seasons); self.data.sonarr_data.seasons.set_items(seasons);
} }
async fn extract_episode_id(&self) -> i64 {
self
.data
.sonarr_data
.season_details_modal
.as_ref()
.expect("Season details have not been loaded")
.episodes
.current_selection()
.id
}
} }
+21 -2
View File
@@ -4,6 +4,7 @@ mod tests {
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::models::servarr_data::sonarr::sonarr_data::sonarr_test_utils::utils::create_test_sonarr_data;
use crate::{ use crate::{
app::App, app::App,
models::{ models::{
@@ -174,6 +175,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_dispatch_by_episode_details_block() { async fn test_dispatch_by_episode_details_block() {
let (mut app, mut sync_network_rx) = construct_app_unit(); let (mut app, mut sync_network_rx) = construct_app_unit();
app.data.sonarr_data = create_test_sonarr_data();
app app
.dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeDetails) .dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeDetails)
@@ -182,7 +184,7 @@ mod tests {
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetEpisodeDetails(None).into() SonarrEvent::GetEpisodeDetails(0).into()
); );
assert!(!app.data.sonarr_data.prompt_confirm); assert!(!app.data.sonarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0); assert_eq!(app.tick_count, 0);
@@ -191,6 +193,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_dispatch_by_episode_file_block() { async fn test_dispatch_by_episode_file_block() {
let (mut app, mut sync_network_rx) = construct_app_unit(); let (mut app, mut sync_network_rx) = construct_app_unit();
app.data.sonarr_data = create_test_sonarr_data();
app app
.dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeFile) .dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeFile)
@@ -199,7 +202,7 @@ mod tests {
assert!(app.is_loading); assert!(app.is_loading);
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetEpisodeDetails(None).into() SonarrEvent::GetEpisodeDetails(0).into()
); );
assert!(!app.data.sonarr_data.prompt_confirm); assert!(!app.data.sonarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0); assert_eq!(app.tick_count, 0);
@@ -727,6 +730,22 @@ mod tests {
); );
} }
#[tokio::test]
async fn test_extract_episode_id() {
let mut app = App::default();
app.data.sonarr_data = create_test_sonarr_data();
assert_eq!(app.extract_episode_id().await, 0);
}
#[tokio::test]
#[should_panic(expected = "Season details have not been loaded")]
async fn test_extract_episode_id_requires_season_details_modal_to_be_some() {
let app = App::default();
assert_eq!(app.extract_episode_id().await, 0);
}
fn construct_app_unit<'a>() -> (App<'a>, mpsc::Receiver<NetworkEvent>) { fn construct_app_unit<'a>() -> (App<'a>, mpsc::Receiver<NetworkEvent>) {
let (sync_network_tx, sync_network_rx) = mpsc::channel::<NetworkEvent>(500); let (sync_network_tx, sync_network_rx) = mpsc::channel::<NetworkEvent>(500);
let mut app = App { let mut app = App {
+1 -1
View File
@@ -83,7 +83,7 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrGetCommand> for SonarrGetCommandHan
SonarrGetCommand::EpisodeDetails { episode_id } => { SonarrGetCommand::EpisodeDetails { episode_id } => {
let resp = self let resp = self
.network .network
.handle_network_event(SonarrEvent::GetEpisodeDetails(Some(episode_id)).into()) .handle_network_event(SonarrEvent::GetEpisodeDetails(episode_id).into())
.await?; .await?;
serde_json::to_string_pretty(&resp)? serde_json::to_string_pretty(&resp)?
} }
+1 -1
View File
@@ -160,7 +160,7 @@ mod tests {
mock_network mock_network
.expect_handle_network_event() .expect_handle_network_event()
.with(eq::<NetworkEvent>( .with(eq::<NetworkEvent>(
SonarrEvent::GetEpisodeDetails(Some(expected_episode_id)).into(), SonarrEvent::GetEpisodeDetails(expected_episode_id).into(),
)) ))
.times(1) .times(1)
.returning(|_| { .returning(|_| {
+6 -7
View File
@@ -59,7 +59,7 @@ pub enum SonarrEvent {
GetHistory(u64), GetHistory(u64),
GetHostConfig, GetHostConfig,
GetIndexers, GetIndexers,
GetEpisodeDetails(Option<i64>), GetEpisodeDetails(i64),
GetEpisodes(Option<i64>), GetEpisodes(Option<i64>),
GetEpisodeFiles(Option<i64>), GetEpisodeFiles(Option<i64>),
GetEpisodeHistory(Option<i64>), GetEpisodeHistory(Option<i64>),
@@ -1305,19 +1305,18 @@ impl<'a, 'b> Network<'a, 'b> {
.await .await
} }
async fn get_episode_details(&mut self, episode_id: Option<i64>) -> Result<Episode> { async fn get_episode_details(&mut self, episode_id: i64) -> Result<Episode> {
info!("Fetching Sonarr episode details"); info!("Fetching Sonarr episode details");
let event = SonarrEvent::GetEpisodeDetails(None); let event = SonarrEvent::GetEpisodeDetails(episode_id);
let id = self.extract_episode_id(episode_id).await;
info!("Fetching episode details for episode with ID: {id}"); info!("Fetching episode details for episode with ID: {episode_id}");
let request_props = self let request_props = self
.request_props_from( .request_props_from(
event, event,
RequestMethod::Get, RequestMethod::Get,
None::<()>, None::<()>,
Some(format!("/{id}")), Some(format!("/{episode_id}")),
None, None,
) )
.await; .await;
@@ -2227,7 +2226,7 @@ impl<'a, 'b> Network<'a, 'b> {
async fn toggle_sonarr_episode_monitoring(&mut self, episode_id: Option<i64>) -> Result<()> { async fn toggle_sonarr_episode_monitoring(&mut self, episode_id: Option<i64>) -> Result<()> {
let event = SonarrEvent::ToggleEpisodeMonitoring(episode_id); let event = SonarrEvent::ToggleEpisodeMonitoring(episode_id);
let detail_event = SonarrEvent::GetEpisodeDetails(None); let detail_event = SonarrEvent::GetEpisodeDetails(0);
let (id, monitored) = if let Some(episode_id) = episode_id { let (id, monitored) = if let Some(episode_id) = episode_id {
info!("Fetching episode details for episode id: {episode_id}"); info!("Fetching episode details for episode id: {episode_id}");
+10 -61
View File
@@ -149,8 +149,7 @@ mod test {
#[rstest] #[rstest]
fn test_resource_episode( fn test_resource_episode(
#[values(SonarrEvent::GetEpisodes(None), SonarrEvent::GetEpisodeDetails(None))] #[values(SonarrEvent::GetEpisodes(None), SonarrEvent::GetEpisodeDetails(0))] event: SonarrEvent,
event: SonarrEvent,
) { ) {
assert_str_eq!(event.resource(), "/episode"); assert_str_eq!(event.resource(), "/episode");
} }
@@ -2651,7 +2650,7 @@ mod test {
None, None,
Some(serde_json::from_str(EPISODE_JSON).unwrap()), Some(serde_json::from_str(EPISODE_JSON).unwrap()),
None, None,
SonarrEvent::GetEpisodeDetails(None), SonarrEvent::GetEpisodeDetails(1),
Some("/1"), Some("/1"),
None, None,
) )
@@ -2669,7 +2668,7 @@ mod test {
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let SonarrSerdeable::Episode(episode) = network if let SonarrSerdeable::Episode(episode) = network
.handle_sonarr_event(SonarrEvent::GetEpisodeDetails(None)) .handle_sonarr_event(SonarrEvent::GetEpisodeDetails(1))
.await .await
.unwrap() .unwrap()
{ {
@@ -2767,7 +2766,7 @@ mod test {
None, None,
Some(serde_json::from_str(EPISODE_JSON).unwrap()), Some(serde_json::from_str(EPISODE_JSON).unwrap()),
None, None,
SonarrEvent::GetEpisodeDetails(None), SonarrEvent::GetEpisodeDetails(1),
Some("/1"), Some("/1"),
None, None,
) )
@@ -2782,7 +2781,7 @@ mod test {
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let SonarrSerdeable::Episode(episode) = network if let SonarrSerdeable::Episode(episode) = network
.handle_sonarr_event(SonarrEvent::GetEpisodeDetails(None)) .handle_sonarr_event(SonarrEvent::GetEpisodeDetails(1))
.await .await
.unwrap() .unwrap()
{ {
@@ -2856,34 +2855,6 @@ mod test {
} }
} }
#[tokio::test]
async fn test_handle_get_episode_details_event_uses_provided_id() {
let response: Episode = serde_json::from_str(EPISODE_JSON).unwrap();
let (async_server, app_arc, _server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(serde_json::from_str(EPISODE_JSON).unwrap()),
None,
SonarrEvent::GetEpisodeDetails(None),
Some("/1"),
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());
if let SonarrSerdeable::Episode(episode) = network
.handle_sonarr_event(SonarrEvent::GetEpisodeDetails(Some(1)))
.await
.unwrap()
{
async_server.assert_async().await;
assert_eq!(episode, response);
}
}
#[tokio::test] #[tokio::test]
async fn test_handle_get_sonarr_episode_history_event() { async fn test_handle_get_sonarr_episode_history_event() {
let history_json = json!({"records": [{ let history_json = json!({"records": [{
@@ -3356,7 +3327,7 @@ mod test {
None, None,
Some(serde_json::from_str(EPISODE_JSON).unwrap()), Some(serde_json::from_str(EPISODE_JSON).unwrap()),
None, None,
SonarrEvent::GetEpisodeDetails(None), SonarrEvent::GetEpisodeDetails(1),
Some("/1"), Some("/1"),
None, None,
) )
@@ -3365,7 +3336,7 @@ mod test {
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let SonarrSerdeable::Episode(episode) = network if let SonarrSerdeable::Episode(episode) = network
.handle_sonarr_event(SonarrEvent::GetEpisodeDetails(Some(1))) .handle_sonarr_event(SonarrEvent::GetEpisodeDetails(1))
.await .await
.unwrap() .unwrap()
{ {
@@ -3374,28 +3345,6 @@ mod test {
} }
} }
#[tokio::test]
#[should_panic(expected = "Season details have not been loaded")]
async fn test_handle_get_episode_details_event_requires_season_details_modal_to_be_some_when_no_parameter_is_passed(
) {
let (_async_server, app_arc, _server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(serde_json::from_str(EPISODE_JSON).unwrap()),
None,
SonarrEvent::GetEpisodeDetails(None),
Some("/1"),
None,
)
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
network
.handle_sonarr_event(SonarrEvent::GetEpisodeDetails(None))
.await
.unwrap();
}
#[tokio::test] #[tokio::test]
#[should_panic(expected = "Season details modal is empty")] #[should_panic(expected = "Season details modal is empty")]
async fn test_handle_get_episode_details_event_requires_season_details_modal_to_be_some_when_in_tui_mode( async fn test_handle_get_episode_details_event_requires_season_details_modal_to_be_some_when_in_tui_mode(
@@ -3405,7 +3354,7 @@ mod test {
None, None,
Some(serde_json::from_str(EPISODE_JSON).unwrap()), Some(serde_json::from_str(EPISODE_JSON).unwrap()),
None, None,
SonarrEvent::GetEpisodeDetails(None), SonarrEvent::GetEpisodeDetails(1),
Some("/1"), Some("/1"),
None, None,
) )
@@ -3413,7 +3362,7 @@ mod test {
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
network network
.handle_sonarr_event(SonarrEvent::GetEpisodeDetails(Some(1))) .handle_sonarr_event(SonarrEvent::GetEpisodeDetails(1))
.await .await
.unwrap(); .unwrap();
} }
@@ -6186,7 +6135,7 @@ mod test {
None, None,
Some(json!(body)), Some(json!(body)),
None, None,
SonarrEvent::GetEpisodeDetails(None), SonarrEvent::GetEpisodeDetails(2),
Some("/2"), Some("/2"),
None, None,
) )