feat: Full support for adding a root folder in Lidarr from both the CLI and TUI

This commit is contained in:
2026-01-14 09:06:27 -07:00
parent d2217509f2
commit 8abcf44866
31 changed files with 3495 additions and 461 deletions
+55 -4
View File
@@ -5,11 +5,12 @@ use clap::{ArgAction, Subcommand, arg};
use tokio::sync::Mutex;
use super::LidarrCommand;
use crate::models::servarr_models::AddRootFolderBody;
use crate::{
app::App,
cli::{CliCommandHandler, Command},
models::lidarr_models::{AddArtistBody, AddArtistOptions, MonitorType, NewItemMonitorType},
models::lidarr_models::{
AddArtistBody, AddArtistOptions, AddLidarrRootFolderBody, MonitorType, NewItemMonitorType,
},
network::{NetworkTrait, lidarr_network::LidarrEvent},
};
@@ -78,8 +79,43 @@ pub enum LidarrAddCommand {
},
#[command(about = "Add a new root folder")]
RootFolder {
#[arg(long, help = "The name of the root folder", required = true)]
name: String,
#[arg(long, help = "The path of the new root folder", required = true)]
root_folder_path: String,
#[arg(
long,
help = "The ID of the default quality profile for artists in this root folder",
required = true
)]
quality_profile_id: i64,
#[arg(
long,
help = "The ID of the default metadata profile for artists in this root folder",
required = true
)]
metadata_profile_id: i64,
#[arg(
long,
help = "The default monitor option for artists in this root folder",
value_enum,
default_value_t = MonitorType::default()
)]
monitor: MonitorType,
#[arg(
long,
help = "The default monitor new items option for artists in this root folder",
value_enum,
default_value_t = NewItemMonitorType::default()
)]
monitor_new_items: NewItemMonitorType,
#[arg(
long,
help = "Default tag IDs for artists in this root folder",
value_parser,
action = ArgAction::Append
)]
tag: Vec<i64>,
},
#[command(about = "Add new tag")]
Tag {
@@ -148,9 +184,24 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrAddCommand> for LidarrAddCommandHan
.await?;
serde_json::to_string_pretty(&resp)?
}
LidarrAddCommand::RootFolder { root_folder_path } => {
let add_root_folder_body = AddRootFolderBody {
LidarrAddCommand::RootFolder {
name,
root_folder_path,
quality_profile_id,
metadata_profile_id,
monitor,
monitor_new_items,
tag: tags,
} => {
let add_root_folder_body = AddLidarrRootFolderBody {
name,
path: root_folder_path,
default_quality_profile_id: quality_profile_id,
default_metadata_profile_id: metadata_profile_id,
default_monitor_option: monitor,
default_new_item_monitor_option: monitor_new_items,
default_tags: tags,
tag_input_string: None,
};
let resp = self
.network
+28 -3
View File
@@ -42,7 +42,13 @@ mod tests {
#[test]
fn test_add_root_folder_success() {
let expected_args = LidarrAddCommand::RootFolder {
name: "Music".to_owned(),
root_folder_path: "/nfs/test".to_owned(),
quality_profile_id: 1,
metadata_profile_id: 1,
monitor: MonitorType::All,
monitor_new_items: NewItemMonitorType::All,
tag: vec![],
};
let result = Cli::try_parse_from([
@@ -50,8 +56,14 @@ mod tests {
"lidarr",
"add",
"root-folder",
"--name",
"Music",
"--root-folder-path",
"/nfs/test",
"--quality-profile-id",
"1",
"--metadata-profile-id",
"1",
]);
assert_ok!(&result);
@@ -416,9 +428,9 @@ mod tests {
use crate::cli::lidarr::add_command_handler::{LidarrAddCommand, LidarrAddCommandHandler};
use crate::models::Serdeable;
use crate::models::lidarr_models::{
AddArtistBody, AddArtistOptions, LidarrSerdeable, MonitorType, NewItemMonitorType,
AddArtistBody, AddArtistOptions, AddLidarrRootFolderBody, LidarrSerdeable, MonitorType,
NewItemMonitorType,
};
use crate::models::servarr_models::AddRootFolderBody;
use crate::network::lidarr_network::LidarrEvent;
use crate::{
app::App,
@@ -428,8 +440,15 @@ mod tests {
#[tokio::test]
async fn test_handle_add_root_folder_command() {
let expected_root_folder_path = "/nfs/test".to_owned();
let expected_add_root_folder_body = AddRootFolderBody {
let expected_add_root_folder_body = AddLidarrRootFolderBody {
name: "Music".to_owned(),
path: expected_root_folder_path.clone(),
default_quality_profile_id: 1,
default_metadata_profile_id: 1,
default_monitor_option: MonitorType::All,
default_new_item_monitor_option: NewItemMonitorType::All,
default_tags: vec![1, 2],
tag_input_string: None,
};
let mut mock_network = MockNetworkTrait::new();
mock_network
@@ -445,7 +464,13 @@ mod tests {
});
let app_arc = Arc::new(Mutex::new(App::test_default()));
let add_root_folder_command = LidarrAddCommand::RootFolder {
name: "Music".to_owned(),
root_folder_path: expected_root_folder_path,
quality_profile_id: 1,
metadata_profile_id: 1,
monitor: MonitorType::All,
monitor_new_items: NewItemMonitorType::All,
tag: vec![1, 2],
};
let result =