feat: Fetch more than 10 downloads when listing Sonarr downloads, and add a --count flag to the CLI to specify how many downloads to fetch

This commit is contained in:
2025-07-13 14:48:15 -06:00
parent ee034c9caf
commit cb4cd93bcd
6 changed files with 84 additions and 26 deletions
+3 -3
View File
@@ -53,7 +53,7 @@ impl App<'_> {
) )
.await; .await;
self self
.dispatch_network_event(SonarrEvent::GetDownloads.into()) .dispatch_network_event(SonarrEvent::GetDownloads(500).into())
.await; .await;
} }
ActiveSonarrBlock::SeasonHistory => { ActiveSonarrBlock::SeasonHistory => {
@@ -108,7 +108,7 @@ impl App<'_> {
} }
ActiveSonarrBlock::Downloads => { ActiveSonarrBlock::Downloads => {
self self
.dispatch_network_event(SonarrEvent::GetDownloads.into()) .dispatch_network_event(SonarrEvent::GetDownloads(500).into())
.await; .await;
} }
ActiveSonarrBlock::Blocklist => { ActiveSonarrBlock::Blocklist => {
@@ -234,7 +234,7 @@ impl App<'_> {
.dispatch_network_event(SonarrEvent::GetRootFolders.into()) .dispatch_network_event(SonarrEvent::GetRootFolders.into())
.await; .await;
self self
.dispatch_network_event(SonarrEvent::GetDownloads.into()) .dispatch_network_event(SonarrEvent::GetDownloads(500).into())
.await; .await;
self self
.dispatch_network_event(SonarrEvent::GetDiskSpace.into()) .dispatch_network_event(SonarrEvent::GetDiskSpace.into())
+8 -8
View File
@@ -107,7 +107,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).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);
@@ -366,7 +366,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::GetDownloads.into() SonarrEvent::GetDownloads(500).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);
@@ -604,7 +604,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).into()
); );
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
@@ -642,7 +642,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).into()
); );
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
@@ -667,7 +667,7 @@ mod tests {
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).into()
); );
assert!(!app.data.sonarr_data.prompt_confirm); assert!(!app.data.sonarr_data.prompt_confirm);
} }
@@ -692,7 +692,7 @@ mod tests {
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).into()
); );
assert!(app.should_refresh); assert!(app.should_refresh);
assert!(!app.data.sonarr_data.prompt_confirm); assert!(!app.data.sonarr_data.prompt_confirm);
@@ -709,7 +709,7 @@ mod tests {
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).into()
); );
assert!(app.is_loading); assert!(app.is_loading);
assert!(app.should_refresh); assert!(app.should_refresh);
@@ -743,7 +743,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
sync_network_rx.recv().await.unwrap(), sync_network_rx.recv().await.unwrap(),
SonarrEvent::GetDownloads.into() SonarrEvent::GetDownloads(500).into()
); );
assert!(app.is_loading); assert!(app.is_loading);
} }
+6 -3
View File
@@ -21,7 +21,10 @@ pub enum SonarrListCommand {
#[command(about = "List all items in the Sonarr blocklist")] #[command(about = "List all items in the Sonarr blocklist")]
Blocklist, Blocklist,
#[command(about = "List all active downloads in Sonarr")] #[command(about = "List all active downloads in Sonarr")]
Downloads, Downloads {
#[arg(long, help = "How many downloads to fetch", default_value_t = 500)]
count: u64,
},
#[command(about = "List disk space details for all provisioned root folders in Sonarr")] #[command(about = "List disk space details for all provisioned root folders in Sonarr")]
DiskSpace, DiskSpace,
#[command(about = "List the episodes for the series with the given ID")] #[command(about = "List the episodes for the series with the given ID")]
@@ -146,10 +149,10 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrListCommand> for SonarrListCommandH
.await?; .await?;
serde_json::to_string_pretty(&resp)? serde_json::to_string_pretty(&resp)?
} }
SonarrListCommand::Downloads => { SonarrListCommand::Downloads { count } => {
let resp = self let resp = self
.network .network
.handle_network_event(SonarrEvent::GetDownloads.into()) .handle_network_event(SonarrEvent::GetDownloads(count).into())
.await?; .await?;
serde_json::to_string_pretty(&resp)? serde_json::to_string_pretty(&resp)?
} }
+48 -2
View File
@@ -28,7 +28,6 @@ mod tests {
#[values( #[values(
"blocklist", "blocklist",
"series", "series",
"downloads",
"disk-space", "disk-space",
"quality-profiles", "quality-profiles",
"indexers", "indexers",
@@ -102,6 +101,28 @@ mod tests {
} }
} }
#[test]
fn test_list_downloads_events_flag_requires_arguments() {
let result =
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "downloads", "--count"]);
assert!(result.is_err());
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
}
#[test]
fn test_list_downloads_default_values() {
let expected_args = SonarrListCommand::Downloads { count: 500 };
let result = Cli::try_parse_from(["managarr", "sonarr", "list", "downloads"]);
assert!(result.is_ok());
if let Some(Command::Sonarr(SonarrCommand::List(downloads_command))) = result.unwrap().command
{
assert_eq!(downloads_command, expected_args);
}
}
#[test] #[test]
fn test_list_history_events_flag_requires_arguments() { fn test_list_history_events_flag_requires_arguments() {
let result = let result =
@@ -287,7 +308,6 @@ mod tests {
#[rstest] #[rstest]
#[case(SonarrListCommand::Blocklist, SonarrEvent::GetBlocklist)] #[case(SonarrListCommand::Blocklist, SonarrEvent::GetBlocklist)]
#[case(SonarrListCommand::Downloads, SonarrEvent::GetDownloads)]
#[case(SonarrListCommand::DiskSpace, SonarrEvent::GetDiskSpace)] #[case(SonarrListCommand::DiskSpace, SonarrEvent::GetDiskSpace)]
#[case(SonarrListCommand::Indexers, SonarrEvent::GetIndexers)] #[case(SonarrListCommand::Indexers, SonarrEvent::GetIndexers)]
#[case(SonarrListCommand::QualityProfiles, SonarrEvent::GetQualityProfiles)] #[case(SonarrListCommand::QualityProfiles, SonarrEvent::GetQualityProfiles)]
@@ -374,6 +394,32 @@ mod tests {
assert!(result.is_ok()); assert!(result.is_ok());
} }
#[tokio::test]
async fn test_handle_list_downloads_command() {
let expected_count = 1000;
let mut mock_network = MockNetworkTrait::new();
mock_network
.expect_handle_network_event()
.with(eq::<NetworkEvent>(
SonarrEvent::GetDownloads(expected_count).into(),
))
.times(1)
.returning(|_| {
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
json!({"testResponse": "response"}),
)))
});
let app_arc = Arc::new(Mutex::new(App::test_default()));
let list_downloads_command = SonarrListCommand::Downloads { count: 1000 };
let result =
SonarrListCommandHandler::with(&app_arc, list_downloads_command, &mut mock_network)
.handle()
.await;
assert!(result.is_ok());
}
#[tokio::test] #[tokio::test]
async fn test_handle_list_history_command() { async fn test_handle_list_history_command() {
let expected_events = 1000; let expected_events = 1000;
+15 -6
View File
@@ -55,7 +55,7 @@ pub enum SonarrEvent {
EditSeries(EditSeriesParams), EditSeries(EditSeriesParams),
GetAllIndexerSettings, GetAllIndexerSettings,
GetBlocklist, GetBlocklist,
GetDownloads, GetDownloads(u64),
GetHistory(u64), GetHistory(u64),
GetHostConfig, GetHostConfig,
GetIndexers, GetIndexers,
@@ -108,7 +108,7 @@ impl NetworkResource for SonarrEvent {
} }
SonarrEvent::GetEpisodeFiles(_) | SonarrEvent::DeleteEpisodeFile(_) => "/episodefile", SonarrEvent::GetEpisodeFiles(_) | SonarrEvent::DeleteEpisodeFile(_) => "/episodefile",
SonarrEvent::GetBlocklist => "/blocklist?page=1&pageSize=10000", SonarrEvent::GetBlocklist => "/blocklist?page=1&pageSize=10000",
SonarrEvent::GetDownloads | SonarrEvent::DeleteDownload(_) => "/queue", SonarrEvent::GetDownloads(_) | SonarrEvent::DeleteDownload(_) => "/queue",
SonarrEvent::GetEpisodes(_) | SonarrEvent::GetEpisodeDetails(_) => "/episode", SonarrEvent::GetEpisodes(_) | SonarrEvent::GetEpisodeDetails(_) => "/episode",
SonarrEvent::GetHistory(_) | SonarrEvent::GetEpisodeHistory(_) => "/history", SonarrEvent::GetHistory(_) | SonarrEvent::GetEpisodeHistory(_) => "/history",
SonarrEvent::GetHostConfig | SonarrEvent::GetSecurityConfig => "/config/host", SonarrEvent::GetHostConfig | SonarrEvent::GetSecurityConfig => "/config/host",
@@ -224,7 +224,10 @@ impl Network<'_, '_> {
.await .await
.map(SonarrSerdeable::from), .map(SonarrSerdeable::from),
SonarrEvent::GetBlocklist => self.get_sonarr_blocklist().await.map(SonarrSerdeable::from), SonarrEvent::GetBlocklist => self.get_sonarr_blocklist().await.map(SonarrSerdeable::from),
SonarrEvent::GetDownloads => self.get_sonarr_downloads().await.map(SonarrSerdeable::from), SonarrEvent::GetDownloads(count) => self
.get_sonarr_downloads(count)
.await
.map(SonarrSerdeable::from),
SonarrEvent::GetEpisodes(series_id) => self SonarrEvent::GetEpisodes(series_id) => self
.get_episodes(series_id) .get_episodes(series_id)
.await .await
@@ -1114,12 +1117,18 @@ impl Network<'_, '_> {
.await .await
} }
async fn get_sonarr_downloads(&mut self) -> Result<DownloadsResponse> { async fn get_sonarr_downloads(&mut self, count: u64) -> Result<DownloadsResponse> {
info!("Fetching Sonarr downloads"); info!("Fetching Sonarr downloads");
let event = SonarrEvent::GetDownloads; let event = SonarrEvent::GetDownloads(count);
let request_props = self let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None) .request_props_from(
event,
RequestMethod::Get,
None::<()>,
None,
Some(format!("pageSize={count}")),
)
.await; .await;
self self
+4 -4
View File
@@ -237,7 +237,7 @@ mod test {
#[rstest] #[rstest]
fn test_resource_queue( fn test_resource_queue(
#[values(SonarrEvent::GetDownloads, SonarrEvent::DeleteDownload(0))] event: SonarrEvent, #[values(SonarrEvent::GetDownloads(0), SonarrEvent::DeleteDownload(0))] event: SonarrEvent,
) { ) {
assert_str_eq!(event.resource(), "/queue"); assert_str_eq!(event.resource(), "/queue");
} }
@@ -1740,16 +1740,16 @@ mod test {
None, None,
Some(downloads_response_json), Some(downloads_response_json),
None, None,
SonarrEvent::GetDownloads, SonarrEvent::GetDownloads(500),
None,
None, None,
Some("pageSize=500"),
) )
.await; .await;
app_arc.lock().await.server_tabs.next(); app_arc.lock().await.server_tabs.next();
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::DownloadsResponse(downloads) = network if let SonarrSerdeable::DownloadsResponse(downloads) = network
.handle_sonarr_event(SonarrEvent::GetDownloads) .handle_sonarr_event(SonarrEvent::GetDownloads(500))
.await .await
.unwrap() .unwrap()
{ {