feat(readarr): fetch Readarr authors and expose them on the CLI

Add ReadarrEvent::ListAuthors, mapping to GET /author, and wire it up as
`managarr readarr list authors`.

This is the first Readarr event that touches the library rather than
configuration, so it creates the library/authors module tree mirroring
Lidarr's library/artists layout.

list_authors mirrors Lidarr's list_artists, including the sort-prompt
route guard: a response landing while the user has the sort prompt open
must not clobber their in-progress sort selection. Both directions of
that guard are covered by tests.
This commit is contained in:
Dark-Alex-17 committed 2026-08-26 11:41:42 -06:00
1 parent e1be1df68a
commit 84eba9beac
7 files changed
+232

No files matched your search

+9
View File
@@ -17,6 +17,8 @@ mod list_command_handler_tests;
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
pub enum ReadarrListCommand {
#[command(about = "List all authors in your Readarr library")]
Authors,
#[command(about = "List disk space details for all provisioned root folders in Readarr")]
DiskSpace,
#[command(about = "Fetch Readarr logs")]
@@ -72,6 +74,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, ReadarrListCommand> for ReadarrListComman
async fn handle(self) -> Result<String> {
let result = match self.command {
ReadarrListCommand::Authors => {
let resp = self
.network
.handle_network_event(ReadarrEvent::ListAuthors.into())
.await?;
serde_json::to_string_pretty(&resp)?
}
ReadarrListCommand::DiskSpace => {
let resp = self
.network
@@ -26,6 +26,7 @@ mod tests {
#[rstest]
fn test_list_commands_have_no_arg_requirements(
#[values(
"authors",
"disk-space",
"metadata-profiles",
"quality-profiles",
@@ -87,6 +88,29 @@ mod tests {
network::{MockNetworkTrait, NetworkEvent, readarr_network::ReadarrEvent},
};
#[tokio::test]
async fn test_handle_list_authors_command() {
let mut mock_network = MockNetworkTrait::new();
mock_network
.expect_handle_network_event()
.with(eq::<NetworkEvent>(ReadarrEvent::ListAuthors.into()))
.times(1)
.returning(|_| {
Ok(Serdeable::Readarr(ReadarrSerdeable::Value(
json!({"testResponse": "response"}),
)))
});
let app_arc = Arc::new(Mutex::new(App::test_default()));
let list_authors_command = ReadarrListCommand::Authors;
let result =
ReadarrListCommandHandler::with(&app_arc, list_authors_command, &mut mock_network)
.handle()
.await;
assert_ok!(&result);
}
#[tokio::test]
async fn test_handle_list_disk_space_command() {
let mut mock_network = MockNetworkTrait::new();