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
+4 -3
View File
@@ -3,9 +3,10 @@ use log::info;
use super::{NetworkEvent, NetworkResource};
use crate::models::lidarr_models::{
AddArtistBody, DeleteParams, EditArtistParams, LidarrSerdeable, MetadataProfile,
AddArtistBody, AddLidarrRootFolderBody, DeleteParams, EditArtistParams, LidarrSerdeable,
MetadataProfile,
};
use crate::models::servarr_models::{AddRootFolderBody, QualityProfile, Tag};
use crate::models::servarr_models::{QualityProfile, Tag};
use crate::network::{Network, RequestMethod};
mod downloads;
@@ -25,7 +26,7 @@ pub mod lidarr_network_test_utils;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum LidarrEvent {
AddArtist(AddArtistBody),
AddRootFolder(AddRootFolderBody),
AddRootFolder(AddLidarrRootFolderBody),
AddTag(String),
DeleteAlbum(DeleteParams),
DeleteArtist(DeleteParams),
@@ -1,21 +1,80 @@
#[cfg(test)]
mod tests {
use crate::models::lidarr_models::LidarrSerdeable;
use crate::models::servarr_models::{AddRootFolderBody, RootFolder};
use crate::models::lidarr_models::{
AddLidarrRootFolderBody, LidarrSerdeable, MonitorType, NewItemMonitorType,
};
use crate::models::servarr_models::RootFolder;
use crate::network::lidarr_network::LidarrEvent;
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::root_folder;
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
use bimap::BiMap;
use pretty_assertions::assert_eq;
use serde_json::json;
#[tokio::test]
async fn test_handle_add_lidarr_root_folder_event() {
let expected_add_root_folder_body = AddRootFolderBody {
let expected_add_root_folder_body = AddLidarrRootFolderBody {
name: "Music".to_owned(),
path: "/nfs/test".to_owned(),
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![],
tag_input_string: Some("usenet, testing".to_owned()),
};
let (mock, app, _server) = MockServarrApi::post()
.with_request_body(json!({
"path": "/nfs/test"
"name": "Music",
"path": "/nfs/test",
"defaultQualityProfileId": 1,
"defaultMetadataProfileId": 1,
"defaultMonitorOption": "all",
"defaultNewItemMonitorOption": "all",
"defaultTags": [1, 2]
}))
.returns(json!({}))
.build_for(LidarrEvent::AddRootFolder(
expected_add_root_folder_body.clone(),
))
.await;
app.lock().await.data.lidarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app);
assert_ok!(
network
.handle_lidarr_event(LidarrEvent::AddRootFolder(expected_add_root_folder_body))
.await
);
mock.assert_async().await;
assert_none!(app.lock().await.data.lidarr_data.add_root_folder_modal);
}
#[tokio::test]
async fn test_handle_add_lidarr_root_folder_event_does_not_overwrite_default_tags_vec_when_tag_input_string_is_none()
{
let expected_add_root_folder_body = AddLidarrRootFolderBody {
name: "Music".to_owned(),
path: "/nfs/test".to_owned(),
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 (mock, app, _server) = MockServarrApi::post()
.with_request_body(json!({
"name": "Music",
"path": "/nfs/test",
"defaultQualityProfileId": 1,
"defaultMetadataProfileId": 1,
"defaultMonitorOption": "all",
"defaultNewItemMonitorOption": "all",
"defaultTags": [1, 2]
}))
.returns(json!({}))
.build_for(LidarrEvent::AddRootFolder(
@@ -25,15 +84,14 @@ mod tests {
app.lock().await.server_tabs.set_index(2);
let mut network = test_network(&app);
assert!(
assert_ok!(
network
.handle_lidarr_event(LidarrEvent::AddRootFolder(expected_add_root_folder_body))
.await
.is_ok()
);
mock.assert_async().await;
assert!(app.lock().await.data.lidarr_data.edit_root_folder.is_none());
assert_none!(app.lock().await.data.lidarr_data.add_root_folder_modal);
}
#[tokio::test]
@@ -1,4 +1,5 @@
use crate::models::servarr_models::{AddRootFolderBody, RootFolder};
use crate::models::lidarr_models::AddLidarrRootFolderBody;
use crate::models::servarr_models::RootFolder;
use crate::network::lidarr_network::LidarrEvent;
use crate::network::{Network, RequestMethod};
use anyhow::Result;
@@ -12,10 +13,14 @@ mod lidarr_root_folders_network_tests;
impl Network<'_, '_> {
pub(in crate::network::lidarr_network) async fn add_lidarr_root_folder(
&mut self,
add_root_folder_body: AddRootFolderBody,
mut add_root_folder_body: AddLidarrRootFolderBody,
) -> Result<Value> {
info!("Adding new root folder to Lidarr");
let event = LidarrEvent::AddRootFolder(AddRootFolderBody::default());
if let Some(tag_input_str) = add_root_folder_body.tag_input_string.as_ref() {
let tag_ids_vec = self.extract_and_add_lidarr_tag_ids_vec(tag_input_str).await;
add_root_folder_body.default_tags = tag_ids_vec;
}
let event = LidarrEvent::AddRootFolder(AddLidarrRootFolderBody::default());
debug!("Add root folder body: {add_root_folder_body:?}");
@@ -30,7 +35,7 @@ impl Network<'_, '_> {
.await;
self
.handle_request::<AddRootFolderBody, Value>(request_props, |_, _| ())
.handle_request::<AddLidarrRootFolderBody, Value>(request_props, |_, _| ())
.await
}