feat: Bulk added CLI support for tracks and album functionalities in Lidarr
This commit is contained in:
@@ -6,8 +6,8 @@ use crate::app::context_clues::{
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::models::Route;
|
use crate::models::Route;
|
||||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||||
ADD_ARTIST_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
|
ADD_ARTIST_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS,
|
||||||
EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
ActiveLidarrBlock, EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -92,6 +92,55 @@ pub static MANUAL_ARTIST_SEARCH_CONTEXT_CLUES: [ContextClue; 7] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub static ALBUM_DETAILS_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "episode details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, "delete episode"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static ALBUM_HISTORY_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static MANUAL_ALBUM_SEARCH_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
pub(in crate::app) struct LidarrContextClueProvider;
|
pub(in crate::app) struct LidarrContextClueProvider;
|
||||||
|
|
||||||
impl ContextClueProvider for LidarrContextClueProvider {
|
impl ContextClueProvider for LidarrContextClueProvider {
|
||||||
@@ -106,6 +155,14 @@ impl ContextClueProvider for LidarrContextClueProvider {
|
|||||||
.lidarr_data
|
.lidarr_data
|
||||||
.artist_info_tabs
|
.artist_info_tabs
|
||||||
.get_active_route_contextual_help(),
|
.get_active_route_contextual_help(),
|
||||||
|
_ if ALBUM_DETAILS_BLOCKS.contains(&active_lidarr_block) => app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_details_tabs
|
||||||
|
.get_active_route_contextual_help(),
|
||||||
ActiveLidarrBlock::AddArtistSearchInput
|
ActiveLidarrBlock::AddArtistSearchInput
|
||||||
| ActiveLidarrBlock::AddArtistEmptySearchResults
|
| ActiveLidarrBlock::AddArtistEmptySearchResults
|
||||||
| ActiveLidarrBlock::TestAllIndexers
|
| ActiveLidarrBlock::TestAllIndexers
|
||||||
|
|||||||
@@ -7,14 +7,16 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::lidarr::lidarr_context_clues::{
|
use crate::app::lidarr::lidarr_context_clues::{
|
||||||
ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES, ARTIST_DETAILS_CONTEXT_CLUES,
|
ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES, ALBUM_DETAILS_CONTEXT_CLUES,
|
||||||
ARTIST_HISTORY_CONTEXT_CLUES, ARTISTS_CONTEXT_CLUES, LidarrContextClueProvider,
|
ALBUM_HISTORY_CONTEXT_CLUES, ARTIST_DETAILS_CONTEXT_CLUES, ARTIST_HISTORY_CONTEXT_CLUES,
|
||||||
|
ARTISTS_CONTEXT_CLUES, LidarrContextClueProvider, MANUAL_ALBUM_SEARCH_CONTEXT_CLUES,
|
||||||
MANUAL_ARTIST_SEARCH_CONTEXT_CLUES,
|
MANUAL_ARTIST_SEARCH_CONTEXT_CLUES,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||||
ADD_ROOT_FOLDER_BLOCKS, ActiveLidarrBlock, EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS,
|
ADD_ROOT_FOLDER_BLOCKS, ActiveLidarrBlock, EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS,
|
||||||
INDEXER_SETTINGS_BLOCKS, LidarrData,
|
INDEXER_SETTINGS_BLOCKS, LidarrData,
|
||||||
};
|
};
|
||||||
|
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
@@ -236,6 +238,123 @@ mod tests {
|
|||||||
assert_none!(manual_artist_search_context_clues_iter.next());
|
assert_none!(manual_artist_search_context_clues_iter.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_details_context_clues() {
|
||||||
|
let mut album_details_context_clues_iter = ALBUM_DETAILS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.submit, "episode details")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_details_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.delete, "delete episode")
|
||||||
|
);
|
||||||
|
assert_none!(album_details_context_clues_iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_history_context_clues() {
|
||||||
|
let mut album_history_context_clues_iter = ALBUM_HISTORY_CONTEXT_CLUES.iter();
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
album_history_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, "cancel filter/close")
|
||||||
|
);
|
||||||
|
assert_none!(album_history_context_clues_iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_manual_album_search_context_clues() {
|
||||||
|
let mut manual_album_search_context_clues_iter = MANUAL_ALBUM_SEARCH_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_album_search_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_album_search_context_clues_iter.next(),
|
||||||
|
&(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc
|
||||||
|
)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_album_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc)
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_album_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.submit, "details")
|
||||||
|
);
|
||||||
|
assert_some_eq_x!(
|
||||||
|
manual_album_search_context_clues_iter.next(),
|
||||||
|
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
|
||||||
|
);
|
||||||
|
assert_none!(manual_album_search_context_clues_iter.next());
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(0, ActiveLidarrBlock::ArtistDetails, &ARTIST_DETAILS_CONTEXT_CLUES)]
|
#[case(0, ActiveLidarrBlock::ArtistDetails, &ARTIST_DETAILS_CONTEXT_CLUES)]
|
||||||
#[case(1, ActiveLidarrBlock::ArtistHistory, &ARTIST_HISTORY_CONTEXT_CLUES)]
|
#[case(1, ActiveLidarrBlock::ArtistHistory, &ARTIST_HISTORY_CONTEXT_CLUES)]
|
||||||
@@ -255,6 +374,30 @@ mod tests {
|
|||||||
assert_some_eq_x!(context_clues, expected_context_clues);
|
assert_some_eq_x!(context_clues, expected_context_clues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(0, ActiveLidarrBlock::AlbumDetails, &ALBUM_DETAILS_CONTEXT_CLUES)]
|
||||||
|
#[case(1, ActiveLidarrBlock::AlbumHistory, &ALBUM_HISTORY_CONTEXT_CLUES)]
|
||||||
|
#[case(2, ActiveLidarrBlock::ManualAlbumSearch, &MANUAL_ALBUM_SEARCH_CONTEXT_CLUES)]
|
||||||
|
fn test_lidarr_context_clue_provider_album_details_tabs(
|
||||||
|
#[case] index: usize,
|
||||||
|
#[case] active_lidarr_block: ActiveLidarrBlock,
|
||||||
|
#[case] expected_context_clues: &[ContextClue],
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
let mut album_details_modal = AlbumDetailsModal::default();
|
||||||
|
album_details_modal.album_details_tabs.set_index(index);
|
||||||
|
let lidarr_data = LidarrData {
|
||||||
|
album_details_modal: Some(album_details_modal),
|
||||||
|
..LidarrData::default()
|
||||||
|
};
|
||||||
|
app.data.lidarr_data = lidarr_data;
|
||||||
|
app.push_navigation_stack(active_lidarr_block.into());
|
||||||
|
|
||||||
|
let context_clues = LidarrContextClueProvider::get_context_clues(&mut app);
|
||||||
|
|
||||||
|
assert_some_eq_x!(context_clues, expected_context_clues);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lidarr_context_clue_provider_artists_block() {
|
fn test_lidarr_context_clue_provider_artists_block() {
|
||||||
let mut app = App::test_default();
|
let mut app = App::test_default();
|
||||||
@@ -362,7 +505,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sonarr_context_clue_provider_system_tasks_clues() {
|
fn test_lidarr_context_clue_provider_system_tasks_clues() {
|
||||||
let mut app = App::test_default();
|
let mut app = App::test_default();
|
||||||
|
|
||||||
app.push_navigation_stack(ActiveLidarrBlock::SystemTasks.into());
|
app.push_navigation_stack(ActiveLidarrBlock::SystemTasks.into());
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::lidarr_models::{Artist, LidarrRelease};
|
use crate::models::lidarr_models::{Album, Artist, LidarrRelease};
|
||||||
use crate::models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock;
|
use crate::models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock;
|
||||||
use crate::models::servarr_models::Indexer;
|
use crate::models::servarr_models::Indexer;
|
||||||
use crate::network::NetworkEvent;
|
use crate::network::NetworkEvent;
|
||||||
@@ -120,6 +120,42 @@ mod tests {
|
|||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_album_details_block() {
|
||||||
|
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.data.lidarr_data.prompt_confirm = true;
|
||||||
|
app.network_tx = Some(tx);
|
||||||
|
app.data.lidarr_data.artists.set_items(vec![Artist {
|
||||||
|
id: 1,
|
||||||
|
..Artist::default()
|
||||||
|
}]);
|
||||||
|
app.data.lidarr_data.albums.set_items(vec![Album {
|
||||||
|
id: 1,
|
||||||
|
..Album::default()
|
||||||
|
}]);
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_lidarr_block(&ActiveLidarrBlock::AlbumDetails)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
rx.recv().await.unwrap(),
|
||||||
|
LidarrEvent::GetTracks(1, 1).into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx.recv().await.unwrap(),
|
||||||
|
LidarrEvent::GetTrackFiles(1).into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rx.recv().await.unwrap(),
|
||||||
|
LidarrEvent::GetDownloads(500).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_downloads_block() {
|
async fn test_dispatch_by_downloads_block() {
|
||||||
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
|
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
|
||||||
|
|||||||
@@ -54,6 +54,19 @@ impl App<'_> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ActiveLidarrBlock::AlbumDetails => {
|
||||||
|
let artist_id = self.extract_artist_id().await;
|
||||||
|
let album_id = self.extract_album_id().await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(LidarrEvent::GetTracks(artist_id, album_id).into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(LidarrEvent::GetTrackFiles(album_id).into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(LidarrEvent::GetDownloads(500).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
ActiveLidarrBlock::AddArtistSearchResults => {
|
ActiveLidarrBlock::AddArtistSearchResults => {
|
||||||
self
|
self
|
||||||
.dispatch_network_event(
|
.dispatch_network_event(
|
||||||
@@ -134,6 +147,10 @@ impl App<'_> {
|
|||||||
self.data.lidarr_data.artists.current_selection().id
|
self.data.lidarr_data.artists.current_selection().id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn extract_album_id(&self) -> i64 {
|
||||||
|
self.data.lidarr_data.albums.current_selection().id
|
||||||
|
}
|
||||||
|
|
||||||
async fn extract_lidarr_indexer_id(&self) -> i64 {
|
async fn extract_lidarr_indexer_id(&self) -> i64 {
|
||||||
self.data.lidarr_data.indexers.current_selection().id
|
self.data.lidarr_data.indexers.current_selection().id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,11 @@ pub enum LidarrDeleteCommand {
|
|||||||
#[arg(long, help = "Add a list exclusion for this album")]
|
#[arg(long, help = "Add a list exclusion for this album")]
|
||||||
add_list_exclusion: bool,
|
add_list_exclusion: bool,
|
||||||
},
|
},
|
||||||
|
#[command(about = "Delete the specified track file from disk")]
|
||||||
|
TrackFile {
|
||||||
|
#[arg(long, help = "The ID of the track file to delete", required = true)]
|
||||||
|
track_file_id: i64,
|
||||||
|
},
|
||||||
#[command(about = "Delete an artist from your Lidarr library")]
|
#[command(about = "Delete an artist from your Lidarr library")]
|
||||||
Artist {
|
Artist {
|
||||||
#[arg(long, help = "The ID of the artist to delete", required = true)]
|
#[arg(long, help = "The ID of the artist to delete", required = true)]
|
||||||
@@ -102,6 +107,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrDeleteCommand> for LidarrDeleteComm
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
LidarrDeleteCommand::TrackFile { track_file_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(LidarrEvent::DeleteTrackFile(track_file_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
LidarrDeleteCommand::Artist {
|
LidarrDeleteCommand::Artist {
|
||||||
artist_id,
|
artist_id,
|
||||||
delete_files_from_disk,
|
delete_files_from_disk,
|
||||||
|
|||||||
@@ -86,6 +86,40 @@ mod tests {
|
|||||||
assert_eq!(delete_command, expected_args);
|
assert_eq!(delete_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_track_file_requires_arguments() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "lidarr", "delete", "track-file"]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_track_file_success() {
|
||||||
|
let expected_args = LidarrDeleteCommand::TrackFile { track_file_id: 1 };
|
||||||
|
|
||||||
|
let result = Cli::try_parse_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"delete",
|
||||||
|
"track-file",
|
||||||
|
"--track-file-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
|
||||||
|
let Some(Command::Lidarr(LidarrCommand::Delete(delete_command))) = result.unwrap().command
|
||||||
|
else {
|
||||||
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(delete_command, expected_args);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_artist_requires_arguments() {
|
fn test_delete_artist_requires_arguments() {
|
||||||
let result = Cli::command().try_get_matches_from(["managarr", "lidarr", "delete", "artist"]);
|
let result = Cli::command().try_get_matches_from(["managarr", "lidarr", "delete", "artist"]);
|
||||||
@@ -327,6 +361,32 @@ mod tests {
|
|||||||
assert_ok!(&result);
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_delete_track_file_command() {
|
||||||
|
let expected_track_file_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
LidarrEvent::DeleteTrackFile(expected_track_file_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let delete_track_file_command = LidarrDeleteCommand::TrackFile { track_file_id: 1 };
|
||||||
|
|
||||||
|
let result =
|
||||||
|
LidarrDeleteCommandHandler::with(&app_arc, delete_track_file_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_delete_artist_command() {
|
async fn test_handle_delete_artist_command() {
|
||||||
let expected_delete_artist_params = DeleteParams {
|
let expected_delete_artist_params = DeleteParams {
|
||||||
|
|||||||
@@ -27,6 +27,23 @@ pub enum LidarrListCommand {
|
|||||||
)]
|
)]
|
||||||
artist_id: i64,
|
artist_id: i64,
|
||||||
},
|
},
|
||||||
|
#[command(
|
||||||
|
about = "Fetch all history events for the given album corresponding to the artist with the given ID."
|
||||||
|
)]
|
||||||
|
AlbumHistory {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr artist ID of the artist whose history you wish to fetch and list",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
artist_id: i64,
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr album ID to fetch history events for",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
album_id: i64,
|
||||||
|
},
|
||||||
#[command(about = "Fetch all history events for the artist with the given ID")]
|
#[command(about = "Fetch all history events for the artist with the given ID")]
|
||||||
ArtistHistory {
|
ArtistHistory {
|
||||||
#[arg(
|
#[arg(
|
||||||
@@ -72,6 +89,32 @@ pub enum LidarrListCommand {
|
|||||||
Tags,
|
Tags,
|
||||||
#[command(about = "List all Lidarr tasks")]
|
#[command(about = "List all Lidarr tasks")]
|
||||||
Tasks,
|
Tasks,
|
||||||
|
#[command(
|
||||||
|
about = "List the tracks for the album that corresponds to the artist with the given ID"
|
||||||
|
)]
|
||||||
|
Tracks {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr artist ID of the artist whose tracks you wish to fetch",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
artist_id: i64,
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr album ID whose tracks you wish to fetch",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
album_id: i64,
|
||||||
|
},
|
||||||
|
#[command(about = "List the track files for the album with the given ID")]
|
||||||
|
TrackFiles {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr ID of the album whose track files you wish to fetch",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
album_id: i64,
|
||||||
|
},
|
||||||
#[command(about = "List all Lidarr updates")]
|
#[command(about = "List all Lidarr updates")]
|
||||||
Updates,
|
Updates,
|
||||||
}
|
}
|
||||||
@@ -110,6 +153,16 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrListCommand> for LidarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
LidarrListCommand::AlbumHistory {
|
||||||
|
artist_id,
|
||||||
|
album_id,
|
||||||
|
} => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(LidarrEvent::GetAlbumHistory(artist_id, album_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
LidarrListCommand::ArtistHistory { artist_id } => {
|
LidarrListCommand::ArtistHistory { artist_id } => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
@@ -204,6 +257,23 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrListCommand> for LidarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
LidarrListCommand::Tracks {
|
||||||
|
artist_id,
|
||||||
|
album_id,
|
||||||
|
} => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(LidarrEvent::GetTracks(artist_id, album_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
|
LidarrListCommand::TrackFiles { album_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(LidarrEvent::GetTrackFiles(album_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
LidarrListCommand::Updates => {
|
LidarrListCommand::Updates => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
|
|||||||
@@ -69,6 +69,58 @@ mod tests {
|
|||||||
assert_eq!(album_command, expected_args);
|
assert_eq!(album_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_history_requires_artist_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"album-history",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_history_requires_album_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"album-history",
|
||||||
|
"--artist-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_history_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"album-history",
|
||||||
|
"--artist-id",
|
||||||
|
"1",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_artist_history_requires_artist_id() {
|
fn test_list_artist_history_requires_artist_id() {
|
||||||
let result =
|
let result =
|
||||||
@@ -172,6 +224,101 @@ mod tests {
|
|||||||
};
|
};
|
||||||
assert_eq!(logs_command, expected_args);
|
assert_eq!(logs_command, expected_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_tracks_requires_artist_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"tracks",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_tracks_requires_album_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"tracks",
|
||||||
|
"--artist-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_tracks_success() {
|
||||||
|
let expected_args = LidarrListCommand::Tracks {
|
||||||
|
artist_id: 1,
|
||||||
|
album_id: 1,
|
||||||
|
};
|
||||||
|
let result = Cli::try_parse_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"tracks",
|
||||||
|
"--artist-id",
|
||||||
|
"1",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
|
||||||
|
let Some(Command::Lidarr(LidarrCommand::List(tracks_command))) = result.unwrap().command
|
||||||
|
else {
|
||||||
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(tracks_command, expected_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_track_files_requires_album_id() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "lidarr", "list", "track-files"]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_track_files_success() {
|
||||||
|
let expected_args = LidarrListCommand::TrackFiles { album_id: 1 };
|
||||||
|
let result = Cli::try_parse_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"list",
|
||||||
|
"track-files",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
|
||||||
|
let Some(Command::Lidarr(LidarrCommand::List(track_files_command))) = result.unwrap().command
|
||||||
|
else {
|
||||||
|
panic!("Unexpected command type");
|
||||||
|
};
|
||||||
|
assert_eq!(track_files_command, expected_args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod handler {
|
mod handler {
|
||||||
@@ -248,6 +395,36 @@ mod tests {
|
|||||||
assert_ok!(&result);
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_list_album_history_command() {
|
||||||
|
let expected_artist_id = 1;
|
||||||
|
let expected_album_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
LidarrEvent::GetAlbumHistory(expected_artist_id, expected_album_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let list_album_history_command = LidarrListCommand::AlbumHistory {
|
||||||
|
artist_id: 1,
|
||||||
|
album_id: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result =
|
||||||
|
LidarrListCommandHandler::with(&app_arc, list_album_history_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_list_artist_history_command() {
|
async fn test_handle_list_artist_history_command() {
|
||||||
let expected_artist_id = 1;
|
let expected_artist_id = 1;
|
||||||
@@ -353,5 +530,60 @@ mod tests {
|
|||||||
|
|
||||||
assert_ok!(&result);
|
assert_ok!(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_list_tracks_command() {
|
||||||
|
let expected_artist_id = 1;
|
||||||
|
let expected_album_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
LidarrEvent::GetTracks(expected_artist_id, expected_album_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let list_tracks_command = LidarrListCommand::Tracks {
|
||||||
|
artist_id: 1,
|
||||||
|
album_id: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = LidarrListCommandHandler::with(&app_arc, list_tracks_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_list_track_files_command() {
|
||||||
|
let expected_album_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
LidarrEvent::GetTrackFiles(expected_album_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let list_track_files_command = LidarrListCommand::TrackFiles { album_id: 1 };
|
||||||
|
|
||||||
|
let result =
|
||||||
|
LidarrListCommandHandler::with(&app_arc, list_track_files_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,19 @@ mod manual_search_command_handler_tests;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
|
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
|
||||||
pub enum LidarrManualSearchCommand {
|
pub enum LidarrManualSearchCommand {
|
||||||
|
#[command(
|
||||||
|
about = "Trigger a manual search of releases for the given album corresponding to the artist with the given ID"
|
||||||
|
)]
|
||||||
|
Album {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr ID of the artist whose releases you wish to fetch and list",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
artist_id: i64,
|
||||||
|
#[arg(long, help = "The Lidarr album ID to search for", required = true)]
|
||||||
|
album_id: i64,
|
||||||
|
},
|
||||||
#[command(
|
#[command(
|
||||||
about = "Trigger a manual search of discography releases for the given artist corresponding to the artist with the given ID."
|
about = "Trigger a manual search of discography releases for the given artist corresponding to the artist with the given ID."
|
||||||
)]
|
)]
|
||||||
@@ -59,6 +72,27 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrManualSearchCommand>
|
|||||||
|
|
||||||
async fn handle(self) -> Result<String> {
|
async fn handle(self) -> Result<String> {
|
||||||
let result = match self.command {
|
let result = match self.command {
|
||||||
|
LidarrManualSearchCommand::Album {
|
||||||
|
artist_id,
|
||||||
|
album_id,
|
||||||
|
} => {
|
||||||
|
println!("Searching for album releases. This may take a minute...");
|
||||||
|
match self
|
||||||
|
.network
|
||||||
|
.handle_network_event(LidarrEvent::GetAlbumReleases(artist_id, album_id).into())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Releases(releases_vec))) => {
|
||||||
|
let albums_vec: Vec<LidarrRelease> = releases_vec
|
||||||
|
.into_iter()
|
||||||
|
.filter(|release| !release.discography)
|
||||||
|
.collect();
|
||||||
|
serde_json::to_string_pretty(&albums_vec)?
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
_ => serde_json::to_string_pretty(&json!({"message": "Failed to parse response"}))?,
|
||||||
|
}
|
||||||
|
}
|
||||||
LidarrManualSearchCommand::Discography { artist_id } => {
|
LidarrManualSearchCommand::Discography { artist_id } => {
|
||||||
println!("Searching for artist discography releases. This may take a minute...");
|
println!("Searching for artist discography releases. This may take a minute...");
|
||||||
match self
|
match self
|
||||||
|
|||||||
@@ -23,6 +23,58 @@ mod tests {
|
|||||||
use clap::error::ErrorKind;
|
use clap::error::ErrorKind;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_manual_album_search_requires_artist_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"manual-search",
|
||||||
|
"album",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_manual_album_search_requires_album_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"manual-search",
|
||||||
|
"album",
|
||||||
|
"--artist-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_manual_album_search_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"manual-search",
|
||||||
|
"album",
|
||||||
|
"--artist-id",
|
||||||
|
"1",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_manual_discography_search_requires_artist_id() {
|
fn test_manual_discography_search_requires_artist_id() {
|
||||||
let result =
|
let result =
|
||||||
@@ -65,6 +117,39 @@ mod tests {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_manual_album_search_command() {
|
||||||
|
let expected_artist_id = 1;
|
||||||
|
let expected_album_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
LidarrEvent::GetAlbumReleases(expected_artist_id, expected_album_id).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let manual_album_search_command = LidarrManualSearchCommand::Album {
|
||||||
|
artist_id: 1,
|
||||||
|
album_id: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = LidarrManualSearchCommandHandler::with(
|
||||||
|
&app_arc,
|
||||||
|
manual_album_search_command,
|
||||||
|
&mut mock_network,
|
||||||
|
)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_manual_discography_search_command() {
|
async fn test_manual_discography_search_command() {
|
||||||
let expected_artist_id = 1;
|
let expected_artist_id = 1;
|
||||||
|
|||||||
@@ -18,6 +18,15 @@ mod trigger_automatic_search_command_handler_tests;
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
|
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
|
||||||
pub enum LidarrTriggerAutomaticSearchCommand {
|
pub enum LidarrTriggerAutomaticSearchCommand {
|
||||||
|
#[command(about = "Trigger an automatic search for the album with the specified ID")]
|
||||||
|
Album {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Lidarr ID of the album you want to trigger an automatic search for",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
album_id: i64,
|
||||||
|
},
|
||||||
#[command(about = "Trigger an automatic search for the artist with the specified ID")]
|
#[command(about = "Trigger an automatic search for the artist with the specified ID")]
|
||||||
Artist {
|
Artist {
|
||||||
#[arg(
|
#[arg(
|
||||||
@@ -58,6 +67,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrTriggerAutomaticSearchCommand>
|
|||||||
|
|
||||||
async fn handle(self) -> Result<String> {
|
async fn handle(self) -> Result<String> {
|
||||||
let result = match self.command {
|
let result = match self.command {
|
||||||
|
LidarrTriggerAutomaticSearchCommand::Album { album_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(LidarrEvent::TriggerAutomaticAlbumSearch(album_id).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
LidarrTriggerAutomaticSearchCommand::Artist { artist_id } => {
|
LidarrTriggerAutomaticSearchCommand::Artist { artist_id } => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
|
|||||||
@@ -28,6 +28,36 @@ mod tests {
|
|||||||
use clap::error::ErrorKind;
|
use clap::error::ErrorKind;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trigger_automatic_album_search_requires_album_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"trigger-automatic-search",
|
||||||
|
"album",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_err!(&result);
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trigger_automatic_album_search_with_album_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"lidarr",
|
||||||
|
"trigger-automatic-search",
|
||||||
|
"album",
|
||||||
|
"--album-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_trigger_automatic_artist_search_requires_artist_id() {
|
fn test_trigger_automatic_artist_search_requires_artist_id() {
|
||||||
let result = Cli::command().try_get_matches_from([
|
let result = Cli::command().try_get_matches_from([
|
||||||
@@ -75,6 +105,35 @@ mod tests {
|
|||||||
network::{MockNetworkTrait, NetworkEvent, lidarr_network::LidarrEvent},
|
network::{MockNetworkTrait, NetworkEvent, lidarr_network::LidarrEvent},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_trigger_automatic_album_search_command() {
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
LidarrEvent::TriggerAutomaticAlbumSearch(1).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Lidarr(LidarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||||
|
let trigger_automatic_search_command =
|
||||||
|
LidarrTriggerAutomaticSearchCommand::Album { album_id: 1 };
|
||||||
|
|
||||||
|
let result = LidarrTriggerAutomaticSearchCommandHandler::with(
|
||||||
|
&app_arc,
|
||||||
|
trigger_automatic_search_command,
|
||||||
|
&mut mock_network,
|
||||||
|
)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert_ok!(&result);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_trigger_automatic_artist_search_command() {
|
async fn test_handle_trigger_automatic_artist_search_command() {
|
||||||
let mut mock_network = MockNetworkTrait::new();
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
|||||||
@@ -256,6 +256,8 @@ pub struct LidarrCommandBody {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub artist_id: Option<i64>,
|
pub artist_id: Option<i64>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub album_ids: Option<Vec<i64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||||
@@ -495,6 +497,67 @@ pub struct LidarrReleaseDownloadBody {
|
|||||||
pub indexer_id: i64,
|
pub indexer_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct TrackFile {
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub id: i64,
|
||||||
|
pub path: String,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub size: i64,
|
||||||
|
pub quality: QualityWrapper,
|
||||||
|
pub date_added: DateTime<Utc>,
|
||||||
|
pub media_info: Option<MediaInfo>,
|
||||||
|
pub audio_tags: Option<AudioTags>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct MediaInfo {
|
||||||
|
pub audio_bitrate: Option<String>,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub audio_channels: i64,
|
||||||
|
pub audio_codec: Option<String>,
|
||||||
|
pub audio_bits: Option<String>,
|
||||||
|
pub audio_sample_rate: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct AudioTags {
|
||||||
|
pub title: String,
|
||||||
|
pub artist_title: String,
|
||||||
|
pub album_title: String,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub disc_number: i64,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub disc_count: i64,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub year: i64,
|
||||||
|
pub duration: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Track {
|
||||||
|
pub id: i64,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub artist_id: i64,
|
||||||
|
pub foreign_track_id: String,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub track_file_id: i64,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub album_id: i64,
|
||||||
|
pub explicit: bool,
|
||||||
|
pub track_number: String,
|
||||||
|
pub title: String,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub duration: i64,
|
||||||
|
pub has_file: bool,
|
||||||
|
pub ratings: Ratings,
|
||||||
|
}
|
||||||
|
|
||||||
impl From<LidarrSerdeable> for Serdeable {
|
impl From<LidarrSerdeable> for Serdeable {
|
||||||
fn from(value: LidarrSerdeable) -> Serdeable {
|
fn from(value: LidarrSerdeable) -> Serdeable {
|
||||||
Serdeable::Lidarr(value)
|
Serdeable::Lidarr(value)
|
||||||
@@ -527,6 +590,9 @@ serde_enum_from!(
|
|||||||
Tag(Tag),
|
Tag(Tag),
|
||||||
Tags(Vec<Tag>),
|
Tags(Vec<Tag>),
|
||||||
Tasks(Vec<LidarrTask>),
|
Tasks(Vec<LidarrTask>),
|
||||||
|
Track(Track),
|
||||||
|
Tracks(Vec<Track>),
|
||||||
|
TrackFiles(Vec<TrackFile>),
|
||||||
Updates(Vec<Update>),
|
Updates(Vec<Update>),
|
||||||
Value(Value),
|
Value(Value),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ mod tests {
|
|||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::models::lidarr_models::{
|
use crate::models::lidarr_models::{
|
||||||
AddArtistSearchResult, Album, DownloadRecord, DownloadStatus, DownloadsResponse,
|
AddArtistSearchResult, Album, AudioTags, DownloadRecord, DownloadStatus, DownloadsResponse,
|
||||||
LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper, LidarrRelease, LidarrTask,
|
LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper, LidarrRelease, LidarrTask,
|
||||||
Member, MetadataProfile, MonitorType, NewItemMonitorType, SystemStatus,
|
MediaInfo, Member, MetadataProfile, MonitorType, NewItemMonitorType, SystemStatus, Track,
|
||||||
|
TrackFile,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_models::{
|
use crate::models::servarr_models::{
|
||||||
DiskSpace, HostConfig, Indexer, IndexerSettings, IndexerTestResult, Log, LogResponse,
|
DiskSpace, HostConfig, Indexer, IndexerSettings, IndexerTestResult, Log, LogResponse,
|
||||||
@@ -577,6 +578,50 @@ mod tests {
|
|||||||
assert_eq!(lidarr_serdeable, LidarrSerdeable::Updates(updates));
|
assert_eq!(lidarr_serdeable, LidarrSerdeable::Updates(updates));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lidarr_serdeable_from_track_file() {
|
||||||
|
let track_files = vec![TrackFile {
|
||||||
|
id: 1,
|
||||||
|
media_info: Some(MediaInfo {
|
||||||
|
audio_channels: 2,
|
||||||
|
..MediaInfo::default()
|
||||||
|
}),
|
||||||
|
audio_tags: Some(AudioTags {
|
||||||
|
disc_number: 1,
|
||||||
|
..AudioTags::default()
|
||||||
|
}),
|
||||||
|
..TrackFile::default()
|
||||||
|
}];
|
||||||
|
|
||||||
|
let lidarr_serdeable: LidarrSerdeable = track_files.clone().into();
|
||||||
|
|
||||||
|
assert_eq!(lidarr_serdeable, LidarrSerdeable::TrackFiles(track_files));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lidarr_serdeable_from_track() {
|
||||||
|
let track = Track {
|
||||||
|
id: 1,
|
||||||
|
..Track::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let lidarr_serdeable: LidarrSerdeable = track.clone().into();
|
||||||
|
|
||||||
|
assert_eq!(lidarr_serdeable, LidarrSerdeable::Track(track));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lidarr_serdeable_from_tracks() {
|
||||||
|
let tracks = vec![Track {
|
||||||
|
id: 1,
|
||||||
|
..Track::default()
|
||||||
|
}];
|
||||||
|
|
||||||
|
let lidarr_serdeable: LidarrSerdeable = tracks.clone().into();
|
||||||
|
|
||||||
|
assert_eq!(lidarr_serdeable, LidarrSerdeable::Tracks(tracks));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_artist_status_display() {
|
fn test_artist_status_display() {
|
||||||
assert_str_eq!(ArtistStatus::Continuing.to_string(), "continuing");
|
assert_str_eq!(ArtistStatus::Continuing.to_string(), "continuing");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use serde_json::Number;
|
use serde_json::Number;
|
||||||
|
|
||||||
use super::modals::{AddArtistModal, AddRootFolderModal, EditArtistModal};
|
use super::modals::{AddArtistModal, AddRootFolderModal, AlbumDetailsModal, EditArtistModal};
|
||||||
use crate::app::context_clues::{
|
use crate::app::context_clues::{
|
||||||
DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||||
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||||
@@ -39,6 +39,7 @@ use {
|
|||||||
crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{
|
crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{
|
||||||
torrent_release, usenet_release,
|
torrent_release, usenet_release,
|
||||||
},
|
},
|
||||||
|
crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{track, track_file},
|
||||||
crate::network::servarr_test_utils::diskspace,
|
crate::network::servarr_test_utils::diskspace,
|
||||||
crate::network::servarr_test_utils::indexer_test_result,
|
crate::network::servarr_test_utils::indexer_test_result,
|
||||||
crate::network::servarr_test_utils::queued_event,
|
crate::network::servarr_test_utils::queued_event,
|
||||||
@@ -58,6 +59,7 @@ pub struct LidarrData<'a> {
|
|||||||
pub add_root_folder_modal: Option<AddRootFolderModal>,
|
pub add_root_folder_modal: Option<AddRootFolderModal>,
|
||||||
pub add_searched_artists: Option<StatefulTable<AddArtistSearchResult>>,
|
pub add_searched_artists: Option<StatefulTable<AddArtistSearchResult>>,
|
||||||
pub albums: StatefulTable<Album>,
|
pub albums: StatefulTable<Album>,
|
||||||
|
pub album_details_modal: Option<AlbumDetailsModal>,
|
||||||
pub artist_history: StatefulTable<LidarrHistoryItem>,
|
pub artist_history: StatefulTable<LidarrHistoryItem>,
|
||||||
pub artist_info_tabs: TabState,
|
pub artist_info_tabs: TabState,
|
||||||
pub artists: StatefulTable<Artist>,
|
pub artists: StatefulTable<Artist>,
|
||||||
@@ -143,6 +145,7 @@ impl<'a> Default for LidarrData<'a> {
|
|||||||
add_root_folder_modal: None,
|
add_root_folder_modal: None,
|
||||||
add_searched_artists: None,
|
add_searched_artists: None,
|
||||||
albums: StatefulTable::default(),
|
albums: StatefulTable::default(),
|
||||||
|
album_details_modal: None,
|
||||||
artist_history: StatefulTable::default(),
|
artist_history: StatefulTable::default(),
|
||||||
artists: StatefulTable::default(),
|
artists: StatefulTable::default(),
|
||||||
delete_files: false,
|
delete_files: false,
|
||||||
@@ -289,6 +292,27 @@ impl LidarrData<'_> {
|
|||||||
.metadata_profile_list
|
.metadata_profile_list
|
||||||
.set_items(vec![metadata_profile().name]);
|
.set_items(vec![metadata_profile().name]);
|
||||||
|
|
||||||
|
let mut album_details_modal = AlbumDetailsModal::default();
|
||||||
|
album_details_modal.tracks.set_items(vec![track()]);
|
||||||
|
album_details_modal.tracks.search = Some("album search".into());
|
||||||
|
album_details_modal
|
||||||
|
.track_files
|
||||||
|
.set_items(vec![track_file()]);
|
||||||
|
album_details_modal
|
||||||
|
.album_history
|
||||||
|
.set_items(vec![lidarr_history_item()]);
|
||||||
|
album_details_modal.album_history.search = Some("album history search".into());
|
||||||
|
album_details_modal.album_history.filter = Some("album history filter".into());
|
||||||
|
album_details_modal
|
||||||
|
.album_history
|
||||||
|
.sorting(vec![sort_option!(id)]);
|
||||||
|
album_details_modal
|
||||||
|
.album_releases
|
||||||
|
.set_items(vec![torrent_release(), usenet_release()]);
|
||||||
|
album_details_modal
|
||||||
|
.album_releases
|
||||||
|
.sorting(vec![sort_option!(indexer_id)]);
|
||||||
|
|
||||||
let edit_indexer_modal = EditIndexerModal {
|
let edit_indexer_modal = EditIndexerModal {
|
||||||
name: "DrunkenSlug".into(),
|
name: "DrunkenSlug".into(),
|
||||||
enable_rss: Some(true),
|
enable_rss: Some(true),
|
||||||
@@ -305,6 +329,7 @@ impl LidarrData<'_> {
|
|||||||
indexer_test_all_results.set_items(vec![indexer_test_result()]);
|
indexer_test_all_results.set_items(vec![indexer_test_result()]);
|
||||||
|
|
||||||
let mut lidarr_data = LidarrData {
|
let mut lidarr_data = LidarrData {
|
||||||
|
album_details_modal: Some(album_details_modal),
|
||||||
delete_files: true,
|
delete_files: true,
|
||||||
disk_space_vec: vec![diskspace()],
|
disk_space_vec: vec![diskspace()],
|
||||||
quality_profile_map: quality_profile_map(),
|
quality_profile_map: quality_profile_map(),
|
||||||
@@ -376,9 +401,6 @@ pub enum ActiveLidarrBlock {
|
|||||||
ArtistHistoryDetails,
|
ArtistHistoryDetails,
|
||||||
ArtistHistorySortPrompt,
|
ArtistHistorySortPrompt,
|
||||||
ArtistsSortPrompt,
|
ArtistsSortPrompt,
|
||||||
ManualArtistSearch,
|
|
||||||
ManualArtistSearchConfirmPrompt,
|
|
||||||
ManualArtistSearchSortPrompt,
|
|
||||||
AddArtistAlreadyInLibrary,
|
AddArtistAlreadyInLibrary,
|
||||||
AddArtistConfirmPrompt,
|
AddArtistConfirmPrompt,
|
||||||
AddArtistEmptySearchResults,
|
AddArtistEmptySearchResults,
|
||||||
@@ -400,7 +422,12 @@ pub enum ActiveLidarrBlock {
|
|||||||
AddRootFolderSelectQualityProfile,
|
AddRootFolderSelectQualityProfile,
|
||||||
AddRootFolderSelectMetadataProfile,
|
AddRootFolderSelectMetadataProfile,
|
||||||
AddRootFolderTagsInput,
|
AddRootFolderTagsInput,
|
||||||
|
AlbumDetails,
|
||||||
|
AlbumHistory,
|
||||||
|
AlbumHistoryDetails,
|
||||||
|
AlbumHistorySortPrompt,
|
||||||
AllIndexerSettingsPrompt,
|
AllIndexerSettingsPrompt,
|
||||||
|
AutomaticallySearchAlbumPrompt,
|
||||||
AutomaticallySearchArtistPrompt,
|
AutomaticallySearchArtistPrompt,
|
||||||
DeleteAlbumPrompt,
|
DeleteAlbumPrompt,
|
||||||
DeleteAlbumConfirmPrompt,
|
DeleteAlbumConfirmPrompt,
|
||||||
@@ -410,6 +437,7 @@ pub enum ActiveLidarrBlock {
|
|||||||
DeleteArtistConfirmPrompt,
|
DeleteArtistConfirmPrompt,
|
||||||
DeleteArtistToggleDeleteFile,
|
DeleteArtistToggleDeleteFile,
|
||||||
DeleteArtistToggleAddListExclusion,
|
DeleteArtistToggleAddListExclusion,
|
||||||
|
DeleteTrackFilePrompt,
|
||||||
DeleteDownloadPrompt,
|
DeleteDownloadPrompt,
|
||||||
DeleteRootFolderPrompt,
|
DeleteRootFolderPrompt,
|
||||||
Downloads,
|
Downloads,
|
||||||
@@ -433,6 +461,8 @@ pub enum ActiveLidarrBlock {
|
|||||||
EditIndexerPriorityInput,
|
EditIndexerPriorityInput,
|
||||||
EditIndexerTagsInput,
|
EditIndexerTagsInput,
|
||||||
DeleteIndexerPrompt,
|
DeleteIndexerPrompt,
|
||||||
|
FilterAlbumHistory,
|
||||||
|
FilterAlbumHistoryError,
|
||||||
FilterArtists,
|
FilterArtists,
|
||||||
FilterArtistsError,
|
FilterArtistsError,
|
||||||
FilterHistory,
|
FilterHistory,
|
||||||
@@ -448,9 +478,17 @@ pub enum ActiveLidarrBlock {
|
|||||||
IndexerSettingsMinimumAgeInput,
|
IndexerSettingsMinimumAgeInput,
|
||||||
IndexerSettingsRetentionInput,
|
IndexerSettingsRetentionInput,
|
||||||
IndexerSettingsRssSyncIntervalInput,
|
IndexerSettingsRssSyncIntervalInput,
|
||||||
|
ManualAlbumSearch,
|
||||||
|
ManualAlbumSearchConfirmPrompt,
|
||||||
|
ManualAlbumSearchSortPrompt,
|
||||||
|
ManualArtistSearch,
|
||||||
|
ManualArtistSearchConfirmPrompt,
|
||||||
|
ManualArtistSearchSortPrompt,
|
||||||
TestAllIndexers,
|
TestAllIndexers,
|
||||||
TestIndexer,
|
TestIndexer,
|
||||||
RootFolders,
|
RootFolders,
|
||||||
|
SearchAlbumHistory,
|
||||||
|
SearchAlbumHistoryError,
|
||||||
SearchAlbums,
|
SearchAlbums,
|
||||||
SearchAlbumsError,
|
SearchAlbumsError,
|
||||||
SearchArtists,
|
SearchArtists,
|
||||||
@@ -459,6 +497,8 @@ pub enum ActiveLidarrBlock {
|
|||||||
SearchHistoryError,
|
SearchHistoryError,
|
||||||
SearchArtistHistory,
|
SearchArtistHistory,
|
||||||
SearchArtistHistoryError,
|
SearchArtistHistoryError,
|
||||||
|
SearchTracks,
|
||||||
|
SearchTracksError,
|
||||||
System,
|
System,
|
||||||
SystemLogs,
|
SystemLogs,
|
||||||
SystemQueuedEvents,
|
SystemQueuedEvents,
|
||||||
@@ -498,6 +538,24 @@ pub static ARTIST_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
|
|||||||
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
|
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub static ALBUM_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
|
||||||
|
ActiveLidarrBlock::AlbumDetails,
|
||||||
|
ActiveLidarrBlock::AlbumHistory,
|
||||||
|
ActiveLidarrBlock::SearchTracks,
|
||||||
|
ActiveLidarrBlock::SearchTracksError,
|
||||||
|
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt,
|
||||||
|
ActiveLidarrBlock::SearchAlbumHistory,
|
||||||
|
ActiveLidarrBlock::SearchAlbumHistoryError,
|
||||||
|
ActiveLidarrBlock::FilterAlbumHistory,
|
||||||
|
ActiveLidarrBlock::FilterAlbumHistoryError,
|
||||||
|
ActiveLidarrBlock::AlbumHistorySortPrompt,
|
||||||
|
ActiveLidarrBlock::AlbumHistoryDetails,
|
||||||
|
ActiveLidarrBlock::ManualAlbumSearch,
|
||||||
|
ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt,
|
||||||
|
ActiveLidarrBlock::ManualAlbumSearchSortPrompt,
|
||||||
|
ActiveLidarrBlock::DeleteTrackFilePrompt,
|
||||||
|
];
|
||||||
|
|
||||||
pub static DOWNLOADS_BLOCKS: [ActiveLidarrBlock; 3] = [
|
pub static DOWNLOADS_BLOCKS: [ActiveLidarrBlock; 3] = [
|
||||||
ActiveLidarrBlock::Downloads,
|
ActiveLidarrBlock::Downloads,
|
||||||
ActiveLidarrBlock::DeleteDownloadPrompt,
|
ActiveLidarrBlock::DeleteDownloadPrompt,
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ mod tests {
|
|||||||
};
|
};
|
||||||
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
|
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
|
||||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ARTIST_DETAILS_BLOCKS,
|
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS,
|
||||||
DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_BLOCKS, DELETE_ARTIST_BLOCKS,
|
ARTIST_DETAILS_BLOCKS, DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_BLOCKS,
|
||||||
DELETE_ARTIST_SELECTION_BLOCKS, DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS,
|
DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS, DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS,
|
||||||
EDIT_ARTIST_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS, EDIT_INDEXER_NZB_SELECTION_BLOCKS,
|
EDIT_ARTIST_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS, EDIT_INDEXER_NZB_SELECTION_BLOCKS,
|
||||||
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||||
INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS, ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS, ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
||||||
@@ -145,6 +145,7 @@ mod tests {
|
|||||||
assert!(!lidarr_data.add_import_list_exclusion);
|
assert!(!lidarr_data.add_import_list_exclusion);
|
||||||
assert_none!(lidarr_data.add_searched_artists);
|
assert_none!(lidarr_data.add_searched_artists);
|
||||||
assert_is_empty!(lidarr_data.albums);
|
assert_is_empty!(lidarr_data.albums);
|
||||||
|
assert_none!(lidarr_data.album_details_modal);
|
||||||
assert_is_empty!(lidarr_data.artists);
|
assert_is_empty!(lidarr_data.artists);
|
||||||
assert_is_empty!(lidarr_data.artist_history);
|
assert_is_empty!(lidarr_data.artist_history);
|
||||||
assert!(!lidarr_data.delete_files);
|
assert!(!lidarr_data.delete_files);
|
||||||
@@ -304,6 +305,26 @@ mod tests {
|
|||||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::UpdateAndScanArtistPrompt));
|
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::UpdateAndScanArtistPrompt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_details_blocks_contents() {
|
||||||
|
assert_eq!(ALBUM_DETAILS_BLOCKS.len(), 15);
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::AlbumDetails));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::AlbumHistory));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::SearchTracks));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::SearchTracksError));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::AutomaticallySearchAlbumPrompt));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::SearchAlbumHistory));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::SearchAlbumHistoryError));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::FilterAlbumHistory));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::FilterAlbumHistoryError));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::AlbumHistorySortPrompt));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::AlbumHistoryDetails));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::ManualAlbumSearch));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::ManualAlbumSearchSortPrompt));
|
||||||
|
assert!(ALBUM_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::DeleteTrackFilePrompt));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_downloads_blocks_contains_expected_blocks() {
|
fn test_downloads_blocks_contains_expected_blocks() {
|
||||||
assert_eq!(DOWNLOADS_BLOCKS.len(), 3);
|
assert_eq!(DOWNLOADS_BLOCKS.len(), 3);
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
use strum::IntoEnumIterator;
|
use super::lidarr_data::{ActiveLidarrBlock, LidarrData};
|
||||||
|
use crate::app::lidarr::lidarr_context_clues::{
|
||||||
use super::lidarr_data::LidarrData;
|
ALBUM_DETAILS_CONTEXT_CLUES, ALBUM_HISTORY_CONTEXT_CLUES, MANUAL_ALBUM_SEARCH_CONTEXT_CLUES,
|
||||||
|
};
|
||||||
|
use crate::models::lidarr_models::{LidarrHistoryItem, LidarrRelease, Track, TrackFile};
|
||||||
use crate::models::servarr_data::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_models::Indexer;
|
use crate::models::servarr_models::Indexer;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
HorizontallyScrollableText,
|
HorizontallyScrollableText, TabRoute, TabState,
|
||||||
lidarr_models::{MonitorType, NewItemMonitorType},
|
lidarr_models::{MonitorType, NewItemMonitorType},
|
||||||
servarr_models::RootFolder,
|
servarr_models::RootFolder,
|
||||||
stateful_list::StatefulList,
|
stateful_list::StatefulList,
|
||||||
};
|
};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "modals_tests.rs"]
|
#[path = "modals_tests.rs"]
|
||||||
@@ -217,3 +221,45 @@ impl From<&LidarrData<'_>> for AddRootFolderModal {
|
|||||||
add_root_folder_modal
|
add_root_folder_modal
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(test, derive(Debug))]
|
||||||
|
pub struct AlbumDetailsModal {
|
||||||
|
pub tracks: StatefulTable<Track>,
|
||||||
|
pub track_files: StatefulTable<TrackFile>,
|
||||||
|
// pub track_details_modal: Option<EpisodeDetailsModal>,
|
||||||
|
pub album_history: StatefulTable<LidarrHistoryItem>,
|
||||||
|
pub album_releases: StatefulTable<LidarrRelease>,
|
||||||
|
pub album_details_tabs: TabState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AlbumDetailsModal {
|
||||||
|
fn default() -> AlbumDetailsModal {
|
||||||
|
AlbumDetailsModal {
|
||||||
|
tracks: StatefulTable::default(),
|
||||||
|
// TODO episode_details_modal: None,
|
||||||
|
track_files: StatefulTable::default(),
|
||||||
|
album_releases: StatefulTable::default(),
|
||||||
|
album_history: StatefulTable::default(),
|
||||||
|
album_details_tabs: TabState::new(vec![
|
||||||
|
TabRoute {
|
||||||
|
title: "Tracks".to_string(),
|
||||||
|
route: ActiveLidarrBlock::AlbumDetails.into(),
|
||||||
|
contextual_help: Some(&ALBUM_DETAILS_CONTEXT_CLUES),
|
||||||
|
config: None,
|
||||||
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "History".to_string(),
|
||||||
|
route: ActiveLidarrBlock::AlbumHistory.into(),
|
||||||
|
contextual_help: Some(&ALBUM_HISTORY_CONTEXT_CLUES),
|
||||||
|
config: None,
|
||||||
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "Manual Search".to_string(),
|
||||||
|
route: ActiveLidarrBlock::ManualAlbumSearch.into(),
|
||||||
|
contextual_help: Some(&MANUAL_ALBUM_SEARCH_CONTEXT_CLUES),
|
||||||
|
config: None,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::app::lidarr::lidarr_context_clues::{
|
||||||
|
ALBUM_DETAILS_CONTEXT_CLUES, ALBUM_HISTORY_CONTEXT_CLUES, MANUAL_ALBUM_SEARCH_CONTEXT_CLUES,
|
||||||
|
};
|
||||||
use crate::models::lidarr_models::{Artist, MonitorType, NewItemMonitorType};
|
use crate::models::lidarr_models::{Artist, MonitorType, NewItemMonitorType};
|
||||||
use crate::models::servarr_data::lidarr::lidarr_data::LidarrData;
|
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, LidarrData};
|
||||||
use crate::models::servarr_data::lidarr::modals::{AddArtistModal, EditArtistModal};
|
use crate::models::servarr_data::lidarr::modals::{
|
||||||
|
AddArtistModal, AlbumDetailsModal, EditArtistModal,
|
||||||
|
};
|
||||||
use crate::models::servarr_data::modals::EditIndexerModal;
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
use crate::models::servarr_models::{Indexer, IndexerField, RootFolder};
|
use crate::models::servarr_models::{Indexer, IndexerField, RootFolder};
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
@@ -208,4 +213,80 @@ mod tests {
|
|||||||
assert_str_eq!(edit_indexer_modal.api_key.text, "1234");
|
assert_str_eq!(edit_indexer_modal.api_key.text, "1234");
|
||||||
assert!(edit_indexer_modal.seed_ratio.text.is_empty());
|
assert!(edit_indexer_modal.seed_ratio.text.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_album_details_modal_default() {
|
||||||
|
let album_details_modal = AlbumDetailsModal::default();
|
||||||
|
|
||||||
|
assert!(album_details_modal.tracks.is_empty());
|
||||||
|
// assert!(album_details_modal.track_details_modal.is_none());
|
||||||
|
assert!(album_details_modal.track_files.is_empty());
|
||||||
|
assert!(album_details_modal.album_releases.is_empty());
|
||||||
|
assert!(album_details_modal.album_history.is_empty());
|
||||||
|
|
||||||
|
assert_eq!(album_details_modal.album_details_tabs.tabs.len(), 3);
|
||||||
|
|
||||||
|
assert_str_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[0].title,
|
||||||
|
"Tracks"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[0].route,
|
||||||
|
ActiveLidarrBlock::AlbumDetails.into()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[0]
|
||||||
|
.contextual_help
|
||||||
|
.is_some()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[0]
|
||||||
|
.contextual_help
|
||||||
|
.unwrap(),
|
||||||
|
&ALBUM_DETAILS_CONTEXT_CLUES
|
||||||
|
);
|
||||||
|
assert_eq!(album_details_modal.album_details_tabs.tabs[0].config, None);
|
||||||
|
|
||||||
|
assert_str_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[1].title,
|
||||||
|
"History"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[1].route,
|
||||||
|
ActiveLidarrBlock::AlbumHistory.into()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[1]
|
||||||
|
.contextual_help
|
||||||
|
.is_some()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[1]
|
||||||
|
.contextual_help
|
||||||
|
.unwrap(),
|
||||||
|
&ALBUM_HISTORY_CONTEXT_CLUES
|
||||||
|
);
|
||||||
|
assert_eq!(album_details_modal.album_details_tabs.tabs[1].config, None);
|
||||||
|
|
||||||
|
assert_str_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[2].title,
|
||||||
|
"Manual Search"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[2].route,
|
||||||
|
ActiveLidarrBlock::ManualAlbumSearch.into()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[2]
|
||||||
|
.contextual_help
|
||||||
|
.is_some()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
album_details_modal.album_details_tabs.tabs[2]
|
||||||
|
.contextual_help
|
||||||
|
.unwrap(),
|
||||||
|
&MANUAL_ALBUM_SEARCH_CONTEXT_CLUES
|
||||||
|
);
|
||||||
|
assert_eq!(album_details_modal.album_details_tabs.tabs[2].config, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::lidarr_models::{Album, DeleteParams, LidarrSerdeable};
|
use crate::models::lidarr_models::{
|
||||||
|
Album, DeleteParams, LidarrHistoryItem, LidarrRelease, LidarrSerdeable,
|
||||||
|
};
|
||||||
|
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
|
||||||
|
use crate::models::stateful_table::SortOption;
|
||||||
use crate::network::lidarr_network::LidarrEvent;
|
use crate::network::lidarr_network::LidarrEvent;
|
||||||
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::ALBUM_JSON;
|
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{
|
||||||
|
ALBUM_JSON, lidarr_history_item, torrent_release,
|
||||||
|
};
|
||||||
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
|
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
|
||||||
use mockito::Matcher;
|
use mockito::Matcher;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -128,4 +135,397 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(album, expected_album);
|
assert_eq!(album, expected_album);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_lidarr_album_history_event(
|
||||||
|
#[values(true, false)] use_custom_sorting: bool,
|
||||||
|
) {
|
||||||
|
let history_json = json!([{
|
||||||
|
"id": 123,
|
||||||
|
"sourceTitle": "z album",
|
||||||
|
"albumId": 1007,
|
||||||
|
"artistId": 1007,
|
||||||
|
"quality": { "quality": { "name": "Lossless" } },
|
||||||
|
"date": "2023-01-01T00:00:00Z",
|
||||||
|
"eventType": "grabbed",
|
||||||
|
"data": {
|
||||||
|
"droppedPath": "/nfs/nzbget/completed/music/Something/cool.mp3",
|
||||||
|
"importedPath": "/nfs/music/Something/Album 1/Cool.mp3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 456,
|
||||||
|
"sourceTitle": "An Album",
|
||||||
|
"albumId": 2001,
|
||||||
|
"artistId": 2001,
|
||||||
|
"quality": { "quality": { "name": "Lossless" } },
|
||||||
|
"date": "2023-01-01T00:00:00Z",
|
||||||
|
"eventType": "grabbed",
|
||||||
|
"data": {
|
||||||
|
"droppedPath": "/nfs/nzbget/completed/music/Something/cool.mp3",
|
||||||
|
"importedPath": "/nfs/music/Something/Album 1/Cool.mp3"
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
let response: Vec<LidarrHistoryItem> = serde_json::from_value(history_json.clone()).unwrap();
|
||||||
|
let mut expected_history_items = vec![
|
||||||
|
LidarrHistoryItem {
|
||||||
|
id: 123,
|
||||||
|
artist_id: 1007,
|
||||||
|
album_id: 1007,
|
||||||
|
source_title: "z album".into(),
|
||||||
|
..lidarr_history_item()
|
||||||
|
},
|
||||||
|
LidarrHistoryItem {
|
||||||
|
id: 456,
|
||||||
|
artist_id: 2001,
|
||||||
|
album_id: 2001,
|
||||||
|
source_title: "An Album".into(),
|
||||||
|
..lidarr_history_item()
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let (mock, app, _server) = MockServarrApi::get()
|
||||||
|
.returns(history_json)
|
||||||
|
.query("artistId=1&albumId=1")
|
||||||
|
.build_for(LidarrEvent::GetAlbumHistory(1, 1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
if use_custom_sorting {
|
||||||
|
let cmp_fn = |a: &LidarrHistoryItem, b: &LidarrHistoryItem| {
|
||||||
|
a.source_title
|
||||||
|
.text
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.source_title.text.to_lowercase())
|
||||||
|
};
|
||||||
|
expected_history_items.sort_by(cmp_fn);
|
||||||
|
|
||||||
|
let history_sort_option = SortOption {
|
||||||
|
name: "Source Title",
|
||||||
|
cmp_fn: Some(cmp_fn),
|
||||||
|
};
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.sorting(vec![history_sort_option]);
|
||||||
|
}
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.sort_asc = true;
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
let LidarrSerdeable::LidarrHistoryItems(history) = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetAlbumHistory(1, 1))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("Expected LidarrHistoryItems")
|
||||||
|
};
|
||||||
|
mock.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.items,
|
||||||
|
expected_history_items
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.sort_asc
|
||||||
|
);
|
||||||
|
assert_eq!(history, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_lidarr_album_history_event_empty_album_details_modal() {
|
||||||
|
let history_json = json!([{
|
||||||
|
"id": 123,
|
||||||
|
"sourceTitle": "z album",
|
||||||
|
"albumId": 1007,
|
||||||
|
"artistId": 1007,
|
||||||
|
"quality": { "quality": { "name": "Lossless" } },
|
||||||
|
"date": "2023-01-01T00:00:00Z",
|
||||||
|
"eventType": "grabbed",
|
||||||
|
"data": {
|
||||||
|
"droppedPath": "/nfs/nzbget/completed/music/Something/cool.mp3",
|
||||||
|
"importedPath": "/nfs/music/Something/Album 1/Cool.mp3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 456,
|
||||||
|
"sourceTitle": "An Album",
|
||||||
|
"albumId": 2001,
|
||||||
|
"artistId": 2001,
|
||||||
|
"quality": { "quality": { "name": "Lossless" } },
|
||||||
|
"date": "2023-01-01T00:00:00Z",
|
||||||
|
"eventType": "grabbed",
|
||||||
|
"data": {
|
||||||
|
"droppedPath": "/nfs/nzbget/completed/music/Something/cool.mp3",
|
||||||
|
"importedPath": "/nfs/music/Something/Album 1/Cool.mp3"
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
let response: Vec<LidarrHistoryItem> = serde_json::from_value(history_json.clone()).unwrap();
|
||||||
|
let expected_history_items = vec![
|
||||||
|
LidarrHistoryItem {
|
||||||
|
id: 123,
|
||||||
|
artist_id: 1007,
|
||||||
|
album_id: 1007,
|
||||||
|
source_title: "z album".into(),
|
||||||
|
..lidarr_history_item()
|
||||||
|
},
|
||||||
|
LidarrHistoryItem {
|
||||||
|
id: 456,
|
||||||
|
artist_id: 2001,
|
||||||
|
album_id: 2001,
|
||||||
|
source_title: "An Album".into(),
|
||||||
|
..lidarr_history_item()
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let (mock, app, _server) = MockServarrApi::get()
|
||||||
|
.returns(history_json)
|
||||||
|
.query("artistId=1&albumId=1")
|
||||||
|
.build_for(LidarrEvent::GetAlbumHistory(1, 1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
let LidarrSerdeable::LidarrHistoryItems(history) = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetAlbumHistory(1, 1))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("Expected LidarrHistoryItems")
|
||||||
|
};
|
||||||
|
mock.assert_async().await;
|
||||||
|
let app = app.lock().await;
|
||||||
|
assert_some!(&app.data.lidarr_data.album_details_modal);
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.items,
|
||||||
|
expected_history_items
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.sort_asc
|
||||||
|
);
|
||||||
|
assert_eq!(history, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_album_releases_event() {
|
||||||
|
let release_json = json!([
|
||||||
|
{
|
||||||
|
"guid": "1234",
|
||||||
|
"protocol": "torrent",
|
||||||
|
"age": 1,
|
||||||
|
"title": "Test Release",
|
||||||
|
"indexer": "kickass torrents",
|
||||||
|
"indexerId": 2,
|
||||||
|
"artistName": "Alex",
|
||||||
|
"albumTitle": "Something",
|
||||||
|
"size": 1234,
|
||||||
|
"rejected": true,
|
||||||
|
"rejections": [ "Unknown quality profile", "Release is already mapped" ],
|
||||||
|
"seeders": 2,
|
||||||
|
"leechers": 1,
|
||||||
|
"quality": { "quality": { "name": "Lossless" }},
|
||||||
|
"discography": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "4567",
|
||||||
|
"protocol": "torrent",
|
||||||
|
"age": 1,
|
||||||
|
"title": "Test Release",
|
||||||
|
"indexer": "kickass torrents",
|
||||||
|
"indexerId": 2,
|
||||||
|
"artistName": "Alex",
|
||||||
|
"albumTitle": "Something",
|
||||||
|
"size": 1234,
|
||||||
|
"rejected": true,
|
||||||
|
"rejections": [ "Unknown quality profile", "Release is already mapped" ],
|
||||||
|
"seeders": 2,
|
||||||
|
"leechers": 1,
|
||||||
|
"quality": { "quality": { "name": "Lossless" }},
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
let expected_filtered_lidarr_release = LidarrRelease {
|
||||||
|
guid: "4567".to_owned(),
|
||||||
|
..torrent_release()
|
||||||
|
};
|
||||||
|
let expected_raw_lidarr_releases = vec![
|
||||||
|
LidarrRelease {
|
||||||
|
discography: true,
|
||||||
|
..torrent_release()
|
||||||
|
},
|
||||||
|
LidarrRelease {
|
||||||
|
guid: "4567".to_owned(),
|
||||||
|
..torrent_release()
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let (mock, app, _server) = MockServarrApi::get()
|
||||||
|
.returns(release_json)
|
||||||
|
.query("artistId=1&albumId=1")
|
||||||
|
.build_for(LidarrEvent::GetAlbumReleases(1, 1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
let LidarrSerdeable::Releases(releases_vec) = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetAlbumReleases(1, 1))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("Expected Releases")
|
||||||
|
};
|
||||||
|
|
||||||
|
mock.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_releases
|
||||||
|
.items,
|
||||||
|
vec![expected_filtered_lidarr_release]
|
||||||
|
);
|
||||||
|
assert_eq!(releases_vec, expected_raw_lidarr_releases);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_album_releases_event_empty_album_details_modal() {
|
||||||
|
let release_json = json!([
|
||||||
|
{
|
||||||
|
"guid": "1234",
|
||||||
|
"protocol": "torrent",
|
||||||
|
"age": 1,
|
||||||
|
"title": "Test Release",
|
||||||
|
"indexer": "kickass torrents",
|
||||||
|
"indexerId": 2,
|
||||||
|
"artistName": "Alex",
|
||||||
|
"albumTitle": "Something",
|
||||||
|
"size": 1234,
|
||||||
|
"rejected": true,
|
||||||
|
"rejections": [ "Unknown quality profile", "Release is already mapped" ],
|
||||||
|
"seeders": 2,
|
||||||
|
"leechers": 1,
|
||||||
|
"quality": { "quality": { "name": "Lossless" }},
|
||||||
|
"discography": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"guid": "4567",
|
||||||
|
"protocol": "torrent",
|
||||||
|
"age": 1,
|
||||||
|
"title": "Test Release",
|
||||||
|
"indexer": "kickass torrents",
|
||||||
|
"indexerId": 2,
|
||||||
|
"artistName": "Alex",
|
||||||
|
"albumTitle": "Something",
|
||||||
|
"size": 1234,
|
||||||
|
"rejected": true,
|
||||||
|
"rejections": [ "Unknown quality profile", "Release is already mapped" ],
|
||||||
|
"seeders": 2,
|
||||||
|
"leechers": 1,
|
||||||
|
"quality": { "quality": { "name": "Lossless" }},
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
let expected_lidarr_release = LidarrRelease {
|
||||||
|
guid: "4567".to_owned(),
|
||||||
|
..torrent_release()
|
||||||
|
};
|
||||||
|
let (mock, app, _server) = MockServarrApi::get()
|
||||||
|
.returns(release_json)
|
||||||
|
.query("artistId=1&albumId=1")
|
||||||
|
.build_for(LidarrEvent::GetAlbumReleases(1, 1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
assert_ok!(
|
||||||
|
network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetAlbumReleases(1, 1))
|
||||||
|
.await
|
||||||
|
);
|
||||||
|
|
||||||
|
mock.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.album_releases
|
||||||
|
.items,
|
||||||
|
vec![expected_lidarr_release]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_trigger_automatic_album_search_event() {
|
||||||
|
let (mock, app, _server) = MockServarrApi::post()
|
||||||
|
.with_request_body(json!({
|
||||||
|
"name": "AlbumSearch",
|
||||||
|
"albumIds": [1]
|
||||||
|
}))
|
||||||
|
.returns(json!({}))
|
||||||
|
.build_for(LidarrEvent::TriggerAutomaticAlbumSearch(1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
network
|
||||||
|
.handle_lidarr_event(LidarrEvent::TriggerAutomaticAlbumSearch(1))
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
);
|
||||||
|
|
||||||
|
mock.assert_async().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::models::lidarr_models::{Album, DeleteParams};
|
use crate::models::lidarr_models::{
|
||||||
|
Album, DeleteParams, LidarrCommandBody, LidarrHistoryItem, LidarrRelease,
|
||||||
|
};
|
||||||
|
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
|
||||||
use crate::network::lidarr_network::LidarrEvent;
|
use crate::network::lidarr_network::LidarrEvent;
|
||||||
use crate::network::{Network, RequestMethod};
|
use crate::network::{Network, RequestMethod};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -57,6 +60,88 @@ impl Network<'_, '_> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(in crate::network::lidarr_network) async fn get_lidarr_album_history(
|
||||||
|
&mut self,
|
||||||
|
artist_id: i64,
|
||||||
|
album_id: i64,
|
||||||
|
) -> Result<Vec<LidarrHistoryItem>> {
|
||||||
|
let event = LidarrEvent::GetAlbumHistory(artist_id, album_id);
|
||||||
|
info!("Fetching history for artist with ID: {artist_id} and album with ID: {album_id}");
|
||||||
|
|
||||||
|
let params = format!("artistId={artist_id}&albumId={album_id}");
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(event, RequestMethod::Get, None::<()>, None, Some(params))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), Vec<LidarrHistoryItem>>(request_props, |history_items, mut app| {
|
||||||
|
if app.data.lidarr_data.album_details_modal.is_none() {
|
||||||
|
app.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut history_vec = history_items;
|
||||||
|
history_vec.sort_by(|a, b| a.id.cmp(&b.id));
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.set_items(history_vec);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.album_history
|
||||||
|
.apply_sorting_toggle(false);
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::network::lidarr_network) async fn get_album_releases(
|
||||||
|
&mut self,
|
||||||
|
artist_id: i64,
|
||||||
|
album_id: i64,
|
||||||
|
) -> Result<Vec<LidarrRelease>> {
|
||||||
|
let event = LidarrEvent::GetAlbumReleases(artist_id, album_id);
|
||||||
|
info!("Fetching releases for artist with ID: {artist_id} and album with ID: {album_id}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
event,
|
||||||
|
RequestMethod::Get,
|
||||||
|
None::<()>,
|
||||||
|
None,
|
||||||
|
Some(format!("artistId={artist_id}&albumId={album_id}")),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), Vec<LidarrRelease>>(request_props, |release_vec, mut app| {
|
||||||
|
if app.data.lidarr_data.album_details_modal.is_none() {
|
||||||
|
app.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let album_releases_vec = release_vec
|
||||||
|
.into_iter()
|
||||||
|
.filter(|release| !release.discography)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.album_releases
|
||||||
|
.set_items(album_releases_vec);
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub(in crate::network::lidarr_network) async fn delete_album(
|
pub(in crate::network::lidarr_network) async fn delete_album(
|
||||||
&mut self,
|
&mut self,
|
||||||
delete_album_params: DeleteParams,
|
delete_album_params: DeleteParams,
|
||||||
@@ -150,4 +235,26 @@ impl Network<'_, '_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(in crate::network::lidarr_network) async fn trigger_automatic_album_search(
|
||||||
|
&mut self,
|
||||||
|
album_id: i64,
|
||||||
|
) -> Result<Value> {
|
||||||
|
let event = LidarrEvent::TriggerAutomaticAlbumSearch(album_id);
|
||||||
|
info!("Searching indexers for album with ID: {album_id}");
|
||||||
|
|
||||||
|
let body = LidarrCommandBody {
|
||||||
|
name: "AlbumSearch".to_owned(),
|
||||||
|
album_ids: Some(vec![album_id]),
|
||||||
|
..LidarrCommandBody::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(event, RequestMethod::Post, Some(body), None, None)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<LidarrCommandBody, Value>(request_props, |_, _| ())
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use serde_json::Value;
|
|||||||
|
|
||||||
mod albums;
|
mod albums;
|
||||||
mod artists;
|
mod artists;
|
||||||
|
mod tracks;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "lidarr_library_network_tests.rs"]
|
#[path = "lidarr_library_network_tests.rs"]
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::models::lidarr_models::LidarrSerdeable;
|
||||||
|
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
|
||||||
|
use crate::network::lidarr_network::LidarrEvent;
|
||||||
|
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{track, track_file};
|
||||||
|
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use serde_json::json;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_delete_lidarr_track_file_event() {
|
||||||
|
let (async_server, app_arc, _server) = MockServarrApi::delete()
|
||||||
|
.path("/1")
|
||||||
|
.build_for(LidarrEvent::DeleteTrackFile(1))
|
||||||
|
.await;
|
||||||
|
app_arc.lock().await.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
app_arc.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app_arc);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
network
|
||||||
|
.handle_lidarr_event(LidarrEvent::DeleteTrackFile(1))
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
);
|
||||||
|
|
||||||
|
async_server.assert_async().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_tracks_event() {
|
||||||
|
let expected_tracks = vec![track()];
|
||||||
|
let (mock, app, _server) = MockServarrApi::get()
|
||||||
|
.query("artistId=1&albumId=1")
|
||||||
|
.returns(json!([track()]))
|
||||||
|
.build_for(LidarrEvent::GetTracks(1, 1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
let result = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetTracks(1, 1))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
mock.assert_async().await;
|
||||||
|
|
||||||
|
let LidarrSerdeable::Tracks(tracks) = result.unwrap() else {
|
||||||
|
panic!("Expected Tracks variant")
|
||||||
|
};
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.tracks
|
||||||
|
.items,
|
||||||
|
expected_tracks
|
||||||
|
);
|
||||||
|
assert_eq!(tracks, expected_tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_tracks_event_empty_album_details_modal() {
|
||||||
|
let expected_tracks = vec![track()];
|
||||||
|
let (mock, app, _server) = MockServarrApi::get()
|
||||||
|
.query("artistId=1&albumId=1")
|
||||||
|
.returns(json!([track()]))
|
||||||
|
.build_for(LidarrEvent::GetTracks(1, 1))
|
||||||
|
.await;
|
||||||
|
app.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app);
|
||||||
|
|
||||||
|
let result = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetTracks(1, 1))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
mock.assert_async().await;
|
||||||
|
|
||||||
|
let LidarrSerdeable::Tracks(tracks) = result.unwrap() else {
|
||||||
|
panic!("Expected Tracks variant")
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.tracks
|
||||||
|
.items,
|
||||||
|
expected_tracks
|
||||||
|
);
|
||||||
|
assert_eq!(tracks, expected_tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_track_files_event() {
|
||||||
|
let (async_server, app_arc, _server) = MockServarrApi::get()
|
||||||
|
.returns(json!([track_file()]))
|
||||||
|
.query("albumId=1")
|
||||||
|
.build_for(LidarrEvent::GetTrackFiles(1))
|
||||||
|
.await;
|
||||||
|
app_arc.lock().await.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
app_arc.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app_arc);
|
||||||
|
|
||||||
|
let LidarrSerdeable::TrackFiles(track_files) = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetTrackFiles(1))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("Expected TrackFiles")
|
||||||
|
};
|
||||||
|
async_server.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app_arc
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.track_files
|
||||||
|
.items,
|
||||||
|
vec![track_file()]
|
||||||
|
);
|
||||||
|
assert_eq!(track_files, vec![track_file()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_track_files_event_empty_album_details_modal() {
|
||||||
|
let (async_server, app_arc, _server) = MockServarrApi::get()
|
||||||
|
.returns(json!([track_file()]))
|
||||||
|
.query("albumId=1")
|
||||||
|
.build_for(LidarrEvent::GetTrackFiles(1))
|
||||||
|
.await;
|
||||||
|
app_arc.lock().await.server_tabs.set_index(2);
|
||||||
|
let mut network = test_network(&app_arc);
|
||||||
|
|
||||||
|
let LidarrSerdeable::TrackFiles(track_files) = network
|
||||||
|
.handle_lidarr_event(LidarrEvent::GetTrackFiles(1))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
else {
|
||||||
|
panic!("Expected TrackFiles")
|
||||||
|
};
|
||||||
|
async_server.assert_async().await;
|
||||||
|
let app = app_arc.lock().await;
|
||||||
|
assert_some!(&app.data.lidarr_data.album_details_modal);
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.track_files
|
||||||
|
.items,
|
||||||
|
vec![track_file()]
|
||||||
|
);
|
||||||
|
assert_eq!(track_files, vec![track_file()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
use crate::models::lidarr_models::{Track, TrackFile};
|
||||||
|
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
|
||||||
|
use crate::network::lidarr_network::LidarrEvent;
|
||||||
|
use crate::network::{Network, RequestMethod};
|
||||||
|
use anyhow::Result;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "lidarr_tracks_network_tests.rs"]
|
||||||
|
mod lidarr_tracks_network_tests;
|
||||||
|
|
||||||
|
impl Network<'_, '_> {
|
||||||
|
pub(in crate::network::lidarr_network) async fn delete_lidarr_track_file(
|
||||||
|
&mut self,
|
||||||
|
track_file_id: i64,
|
||||||
|
) -> Result<()> {
|
||||||
|
let event = LidarrEvent::DeleteTrackFile(track_file_id);
|
||||||
|
info!("Deleting Lidarr track file for track file with id: {track_file_id}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
event,
|
||||||
|
RequestMethod::Delete,
|
||||||
|
None::<()>,
|
||||||
|
Some(format!("/{track_file_id}")),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), ()>(request_props, |_, _| ())
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::network::lidarr_network) async fn get_tracks(
|
||||||
|
&mut self,
|
||||||
|
artist_id: i64,
|
||||||
|
album_id: i64,
|
||||||
|
) -> Result<Vec<Track>> {
|
||||||
|
let event = LidarrEvent::GetTracks(artist_id, album_id);
|
||||||
|
info!("Fetching tracks for Lidarr artist with ID: {artist_id} and album with ID: {album_id}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
event,
|
||||||
|
RequestMethod::Get,
|
||||||
|
None::<()>,
|
||||||
|
None,
|
||||||
|
Some(format!("artistId={artist_id}&albumId={album_id}")),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), Vec<Track>>(request_props, |mut track_vec, mut app| {
|
||||||
|
track_vec.sort_by(|a, b| a.id.cmp(&b.id));
|
||||||
|
if app.data.lidarr_data.album_details_modal.is_none() {
|
||||||
|
app.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tracks
|
||||||
|
.set_items(track_vec);
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::network::lidarr_network) async fn get_track_files(
|
||||||
|
&mut self,
|
||||||
|
album_id: i64,
|
||||||
|
) -> Result<Vec<TrackFile>> {
|
||||||
|
let event = LidarrEvent::GetTrackFiles(album_id);
|
||||||
|
info!("Fetching tracks files for Lidarr album with ID: {album_id}");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.request_props_from(
|
||||||
|
event,
|
||||||
|
RequestMethod::Get,
|
||||||
|
None::<()>,
|
||||||
|
None,
|
||||||
|
Some(format!("albumId={album_id}")),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), Vec<TrackFile>>(request_props, |track_file_vec, mut app| {
|
||||||
|
if app.data.lidarr_data.album_details_modal.is_none() {
|
||||||
|
app.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.lidarr_data
|
||||||
|
.album_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.track_files
|
||||||
|
.set_items(track_file_vec);
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,9 +3,10 @@
|
|||||||
pub mod test_utils {
|
pub mod test_utils {
|
||||||
use crate::models::lidarr_models::{
|
use crate::models::lidarr_models::{
|
||||||
AddArtistSearchResult, Album, AlbumStatistics, Artist, ArtistStatistics, ArtistStatus,
|
AddArtistSearchResult, Album, AlbumStatistics, Artist, ArtistStatistics, ArtistStatus,
|
||||||
DownloadRecord, DownloadStatus, DownloadsResponse, EditArtistParams, LidarrHistoryData,
|
AudioTags, DownloadRecord, DownloadStatus, DownloadsResponse, EditArtistParams,
|
||||||
LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper, LidarrRelease, LidarrTask,
|
LidarrHistoryData, LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper,
|
||||||
LidarrTaskName, Member, MetadataProfile, NewItemMonitorType, Ratings, SystemStatus,
|
LidarrRelease, LidarrTask, LidarrTaskName, MediaInfo, Member, MetadataProfile,
|
||||||
|
NewItemMonitorType, Ratings, SystemStatus, Track, TrackFile,
|
||||||
};
|
};
|
||||||
use crate::models::servarr_models::IndexerSettings;
|
use crate::models::servarr_models::IndexerSettings;
|
||||||
use crate::models::servarr_models::{
|
use crate::models::servarr_models::{
|
||||||
@@ -424,4 +425,54 @@ pub mod test_utils {
|
|||||||
quality: quality_wrapper(),
|
quality: quality_wrapper(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn audio_tags() -> AudioTags {
|
||||||
|
AudioTags {
|
||||||
|
title: "When I Get There".to_string(),
|
||||||
|
artist_title: "P!nk".to_string(),
|
||||||
|
album_title: "Trustfall".to_string(),
|
||||||
|
disc_number: 1,
|
||||||
|
disc_count: 1,
|
||||||
|
year: 2023,
|
||||||
|
duration: "00:03:20.1802267".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn media_info() -> MediaInfo {
|
||||||
|
MediaInfo {
|
||||||
|
audio_bitrate: Some("1563 kbps".to_owned()),
|
||||||
|
audio_channels: 2,
|
||||||
|
audio_codec: Some("FLAC".to_owned()),
|
||||||
|
audio_bits: Some("24bit".to_owned()),
|
||||||
|
audio_sample_rate: Some("44.1kHz".to_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn track_file() -> TrackFile {
|
||||||
|
TrackFile {
|
||||||
|
id: 1,
|
||||||
|
path: "/music/P!nk/TRUSTFALL/01 - When I Get There.flac".to_string(),
|
||||||
|
size: 39216378,
|
||||||
|
quality: quality_wrapper(),
|
||||||
|
date_added: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap()),
|
||||||
|
media_info: Some(media_info()),
|
||||||
|
audio_tags: Some(audio_tags()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn track() -> Track {
|
||||||
|
Track {
|
||||||
|
id: 1,
|
||||||
|
artist_id: 1,
|
||||||
|
foreign_track_id: "test-foreign-track-id".to_string(),
|
||||||
|
track_file_id: 1,
|
||||||
|
album_id: 1,
|
||||||
|
explicit: false,
|
||||||
|
track_number: "1".to_string(),
|
||||||
|
title: "Test title".to_string(),
|
||||||
|
duration: 200173,
|
||||||
|
has_file: false,
|
||||||
|
ratings: ratings(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,8 +61,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_resource_history(#[values(LidarrEvent::GetHistory(0))] event: LidarrEvent) {
|
fn test_resource_artist_history(
|
||||||
assert_str_eq!(event.resource(), "/history");
|
#[values(LidarrEvent::GetArtistHistory(0), LidarrEvent::GetAlbumHistory(0, 0))]
|
||||||
|
event: LidarrEvent,
|
||||||
|
) {
|
||||||
|
assert_str_eq!(event.resource(), "/history/artist");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -89,6 +92,7 @@ mod tests {
|
|||||||
#[values(
|
#[values(
|
||||||
LidarrEvent::UpdateAllArtists,
|
LidarrEvent::UpdateAllArtists,
|
||||||
LidarrEvent::TriggerAutomaticArtistSearch(0),
|
LidarrEvent::TriggerAutomaticArtistSearch(0),
|
||||||
|
LidarrEvent::TriggerAutomaticAlbumSearch(0),
|
||||||
LidarrEvent::UpdateAndScanArtist(0),
|
LidarrEvent::UpdateAndScanArtist(0),
|
||||||
LidarrEvent::UpdateDownloads,
|
LidarrEvent::UpdateDownloads,
|
||||||
LidarrEvent::GetQueuedEvents,
|
LidarrEvent::GetQueuedEvents,
|
||||||
@@ -128,13 +132,21 @@ mod tests {
|
|||||||
fn test_resource_release(
|
fn test_resource_release(
|
||||||
#[values(
|
#[values(
|
||||||
LidarrEvent::GetDiscographyReleases(0),
|
LidarrEvent::GetDiscographyReleases(0),
|
||||||
LidarrEvent::DownloadRelease(Default::default())
|
LidarrEvent::DownloadRelease(Default::default()),
|
||||||
|
LidarrEvent::GetAlbumReleases(0, 0)
|
||||||
)]
|
)]
|
||||||
event: LidarrEvent,
|
event: LidarrEvent,
|
||||||
) {
|
) {
|
||||||
assert_str_eq!(event.resource(), "/release");
|
assert_str_eq!(event.resource(), "/release");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_resource_track_file(
|
||||||
|
#[values(LidarrEvent::DeleteTrackFile(0), LidarrEvent::GetTrackFiles(0))] event: LidarrEvent,
|
||||||
|
) {
|
||||||
|
assert_str_eq!(event.resource(), "/trackfile");
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(LidarrEvent::GetDiskSpace, "/diskspace")]
|
#[case(LidarrEvent::GetDiskSpace, "/diskspace")]
|
||||||
#[case(LidarrEvent::GetMetadataProfiles, "/metadataprofile")]
|
#[case(LidarrEvent::GetMetadataProfiles, "/metadataprofile")]
|
||||||
@@ -146,9 +158,10 @@ mod tests {
|
|||||||
#[case(LidarrEvent::GetUpdates, "/update")]
|
#[case(LidarrEvent::GetUpdates, "/update")]
|
||||||
#[case(LidarrEvent::HealthCheck, "/health")]
|
#[case(LidarrEvent::HealthCheck, "/health")]
|
||||||
#[case(LidarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")]
|
#[case(LidarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")]
|
||||||
#[case(LidarrEvent::GetArtistHistory(0), "/history/artist")]
|
#[case(LidarrEvent::GetHistory(0), "/history")]
|
||||||
#[case(LidarrEvent::TestIndexer(0), "/indexer/test")]
|
#[case(LidarrEvent::TestIndexer(0), "/indexer/test")]
|
||||||
#[case(LidarrEvent::TestAllIndexers, "/indexer/testall")]
|
#[case(LidarrEvent::TestAllIndexers, "/indexer/testall")]
|
||||||
|
#[case(LidarrEvent::GetTracks(0, 0), "/track")]
|
||||||
fn test_resource(#[case] event: LidarrEvent, #[case] expected_uri: &str) {
|
fn test_resource(#[case] event: LidarrEvent, #[case] expected_uri: &str) {
|
||||||
assert_str_eq!(event.resource(), expected_uri);
|
assert_str_eq!(event.resource(), expected_uri);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,12 +35,15 @@ pub enum LidarrEvent {
|
|||||||
DeleteIndexer(i64),
|
DeleteIndexer(i64),
|
||||||
DeleteRootFolder(i64),
|
DeleteRootFolder(i64),
|
||||||
DeleteTag(i64),
|
DeleteTag(i64),
|
||||||
|
DeleteTrackFile(i64),
|
||||||
DownloadRelease(LidarrReleaseDownloadBody),
|
DownloadRelease(LidarrReleaseDownloadBody),
|
||||||
EditArtist(EditArtistParams),
|
EditArtist(EditArtistParams),
|
||||||
EditAllIndexerSettings(IndexerSettings),
|
EditAllIndexerSettings(IndexerSettings),
|
||||||
EditIndexer(EditIndexerParams),
|
EditIndexer(EditIndexerParams),
|
||||||
GetAlbums(i64),
|
GetAlbums(i64),
|
||||||
GetAlbumDetails(i64),
|
GetAlbumDetails(i64),
|
||||||
|
GetAlbumHistory(i64, i64),
|
||||||
|
GetAlbumReleases(i64, i64),
|
||||||
GetArtistHistory(i64),
|
GetArtistHistory(i64),
|
||||||
GetAllIndexerSettings,
|
GetAllIndexerSettings,
|
||||||
GetArtistDetails(i64),
|
GetArtistDetails(i64),
|
||||||
@@ -58,6 +61,8 @@ pub enum LidarrEvent {
|
|||||||
GetRootFolders,
|
GetRootFolders,
|
||||||
GetSecurityConfig,
|
GetSecurityConfig,
|
||||||
GetStatus,
|
GetStatus,
|
||||||
|
GetTracks(i64, i64),
|
||||||
|
GetTrackFiles(i64),
|
||||||
GetUpdates,
|
GetUpdates,
|
||||||
GetTags,
|
GetTags,
|
||||||
GetTasks,
|
GetTasks,
|
||||||
@@ -70,6 +75,7 @@ pub enum LidarrEvent {
|
|||||||
ToggleAlbumMonitoring(i64),
|
ToggleAlbumMonitoring(i64),
|
||||||
ToggleArtistMonitoring(i64),
|
ToggleArtistMonitoring(i64),
|
||||||
TriggerAutomaticArtistSearch(i64),
|
TriggerAutomaticArtistSearch(i64),
|
||||||
|
TriggerAutomaticAlbumSearch(i64),
|
||||||
UpdateAllArtists,
|
UpdateAllArtists,
|
||||||
UpdateAndScanArtist(i64),
|
UpdateAndScanArtist(i64),
|
||||||
UpdateDownloads,
|
UpdateDownloads,
|
||||||
@@ -79,6 +85,7 @@ impl NetworkResource for LidarrEvent {
|
|||||||
fn resource(&self) -> &'static str {
|
fn resource(&self) -> &'static str {
|
||||||
match &self {
|
match &self {
|
||||||
LidarrEvent::AddTag(_) | LidarrEvent::DeleteTag(_) | LidarrEvent::GetTags => "/tag",
|
LidarrEvent::AddTag(_) | LidarrEvent::DeleteTag(_) | LidarrEvent::GetTags => "/tag",
|
||||||
|
LidarrEvent::DeleteTrackFile(_) | LidarrEvent::GetTrackFiles(_) => "/trackfile",
|
||||||
LidarrEvent::GetAllIndexerSettings | LidarrEvent::EditAllIndexerSettings(_) => {
|
LidarrEvent::GetAllIndexerSettings | LidarrEvent::EditAllIndexerSettings(_) => {
|
||||||
"/config/indexer"
|
"/config/indexer"
|
||||||
}
|
}
|
||||||
@@ -92,13 +99,15 @@ impl NetworkResource for LidarrEvent {
|
|||||||
| LidarrEvent::ToggleAlbumMonitoring(_)
|
| LidarrEvent::ToggleAlbumMonitoring(_)
|
||||||
| LidarrEvent::GetAlbumDetails(_)
|
| LidarrEvent::GetAlbumDetails(_)
|
||||||
| LidarrEvent::DeleteAlbum(_) => "/album",
|
| LidarrEvent::DeleteAlbum(_) => "/album",
|
||||||
LidarrEvent::GetArtistHistory(_) => "/history/artist",
|
LidarrEvent::GetArtistHistory(_) | LidarrEvent::GetAlbumHistory(_, _) => "/history/artist",
|
||||||
LidarrEvent::GetLogs(_) => "/log",
|
LidarrEvent::GetLogs(_) => "/log",
|
||||||
LidarrEvent::GetDiskSpace => "/diskspace",
|
LidarrEvent::GetDiskSpace => "/diskspace",
|
||||||
LidarrEvent::GetDownloads(_) | LidarrEvent::DeleteDownload(_) => "/queue",
|
LidarrEvent::GetDownloads(_) | LidarrEvent::DeleteDownload(_) => "/queue",
|
||||||
LidarrEvent::GetHistory(_) => "/history",
|
LidarrEvent::GetHistory(_) => "/history",
|
||||||
LidarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
|
LidarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
|
||||||
LidarrEvent::GetDiscographyReleases(_) | LidarrEvent::DownloadRelease(_) => "/release",
|
LidarrEvent::GetDiscographyReleases(_)
|
||||||
|
| LidarrEvent::DownloadRelease(_)
|
||||||
|
| LidarrEvent::GetAlbumReleases(_, _) => "/release",
|
||||||
LidarrEvent::GetHostConfig | LidarrEvent::GetSecurityConfig => "/config/host",
|
LidarrEvent::GetHostConfig | LidarrEvent::GetSecurityConfig => "/config/host",
|
||||||
LidarrEvent::GetIndexers | LidarrEvent::DeleteIndexer(_) | LidarrEvent::EditIndexer(_) => {
|
LidarrEvent::GetIndexers | LidarrEvent::DeleteIndexer(_) | LidarrEvent::EditIndexer(_) => {
|
||||||
"/indexer"
|
"/indexer"
|
||||||
@@ -108,7 +117,8 @@ impl NetworkResource for LidarrEvent {
|
|||||||
| LidarrEvent::UpdateAndScanArtist(_)
|
| LidarrEvent::UpdateAndScanArtist(_)
|
||||||
| LidarrEvent::UpdateDownloads
|
| LidarrEvent::UpdateDownloads
|
||||||
| LidarrEvent::GetQueuedEvents
|
| LidarrEvent::GetQueuedEvents
|
||||||
| LidarrEvent::StartTask(_) => "/command",
|
| LidarrEvent::StartTask(_)
|
||||||
|
| LidarrEvent::TriggerAutomaticAlbumSearch(_) => "/command",
|
||||||
LidarrEvent::GetMetadataProfiles => "/metadataprofile",
|
LidarrEvent::GetMetadataProfiles => "/metadataprofile",
|
||||||
LidarrEvent::GetQualityProfiles => "/qualityprofile",
|
LidarrEvent::GetQualityProfiles => "/qualityprofile",
|
||||||
LidarrEvent::GetRootFolders
|
LidarrEvent::GetRootFolders
|
||||||
@@ -118,6 +128,7 @@ impl NetworkResource for LidarrEvent {
|
|||||||
LidarrEvent::TestAllIndexers => "/indexer/testall",
|
LidarrEvent::TestAllIndexers => "/indexer/testall",
|
||||||
LidarrEvent::GetStatus => "/system/status",
|
LidarrEvent::GetStatus => "/system/status",
|
||||||
LidarrEvent::GetTasks => "/system/task",
|
LidarrEvent::GetTasks => "/system/task",
|
||||||
|
LidarrEvent::GetTracks(_, _) => "/track",
|
||||||
LidarrEvent::GetUpdates => "/update",
|
LidarrEvent::GetUpdates => "/update",
|
||||||
LidarrEvent::HealthCheck => "/health",
|
LidarrEvent::HealthCheck => "/health",
|
||||||
LidarrEvent::SearchNewArtist(_) => "/artist/lookup",
|
LidarrEvent::SearchNewArtist(_) => "/artist/lookup",
|
||||||
@@ -152,6 +163,10 @@ impl Network<'_, '_> {
|
|||||||
.delete_lidarr_download(download_id)
|
.delete_lidarr_download(download_id)
|
||||||
.await
|
.await
|
||||||
.map(LidarrSerdeable::from),
|
.map(LidarrSerdeable::from),
|
||||||
|
LidarrEvent::DeleteTrackFile(track_file_id) => self
|
||||||
|
.delete_lidarr_track_file(track_file_id)
|
||||||
|
.await
|
||||||
|
.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::EditAllIndexerSettings(params) => self
|
LidarrEvent::EditAllIndexerSettings(params) => self
|
||||||
.edit_all_lidarr_indexer_settings(params)
|
.edit_all_lidarr_indexer_settings(params)
|
||||||
.await
|
.await
|
||||||
@@ -191,6 +206,14 @@ impl Network<'_, '_> {
|
|||||||
.get_album_details(album_id)
|
.get_album_details(album_id)
|
||||||
.await
|
.await
|
||||||
.map(LidarrSerdeable::from),
|
.map(LidarrSerdeable::from),
|
||||||
|
LidarrEvent::GetAlbumHistory(artist_id, album_id) => self
|
||||||
|
.get_lidarr_album_history(artist_id, album_id)
|
||||||
|
.await
|
||||||
|
.map(LidarrSerdeable::from),
|
||||||
|
LidarrEvent::GetAlbumReleases(artist_id, album_id) => self
|
||||||
|
.get_album_releases(artist_id, album_id)
|
||||||
|
.await
|
||||||
|
.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::GetDiscographyReleases(artist_id) => self
|
LidarrEvent::GetDiscographyReleases(artist_id) => self
|
||||||
.get_artist_discography_releases(artist_id)
|
.get_artist_discography_releases(artist_id)
|
||||||
.await
|
.await
|
||||||
@@ -244,6 +267,14 @@ impl Network<'_, '_> {
|
|||||||
LidarrEvent::GetStatus => self.get_lidarr_status().await.map(LidarrSerdeable::from),
|
LidarrEvent::GetStatus => self.get_lidarr_status().await.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::GetTags => self.get_lidarr_tags().await.map(LidarrSerdeable::from),
|
LidarrEvent::GetTags => self.get_lidarr_tags().await.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::GetTasks => self.get_lidarr_tasks().await.map(LidarrSerdeable::from),
|
LidarrEvent::GetTasks => self.get_lidarr_tasks().await.map(LidarrSerdeable::from),
|
||||||
|
LidarrEvent::GetTracks(artist_id, album_id) => self
|
||||||
|
.get_tracks(artist_id, album_id)
|
||||||
|
.await
|
||||||
|
.map(LidarrSerdeable::from),
|
||||||
|
LidarrEvent::GetTrackFiles(album_id) => self
|
||||||
|
.get_track_files(album_id)
|
||||||
|
.await
|
||||||
|
.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::GetUpdates => self.get_lidarr_updates().await.map(LidarrSerdeable::from),
|
LidarrEvent::GetUpdates => self.get_lidarr_updates().await.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::HealthCheck => self
|
LidarrEvent::HealthCheck => self
|
||||||
.get_lidarr_healthcheck()
|
.get_lidarr_healthcheck()
|
||||||
@@ -269,6 +300,10 @@ impl Network<'_, '_> {
|
|||||||
.trigger_automatic_artist_search(artist_id)
|
.trigger_automatic_artist_search(artist_id)
|
||||||
.await
|
.await
|
||||||
.map(LidarrSerdeable::from),
|
.map(LidarrSerdeable::from),
|
||||||
|
LidarrEvent::TriggerAutomaticAlbumSearch(album_id) => self
|
||||||
|
.trigger_automatic_album_search(album_id)
|
||||||
|
.await
|
||||||
|
.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::UpdateAllArtists => self.update_all_artists().await.map(LidarrSerdeable::from),
|
LidarrEvent::UpdateAllArtists => self.update_all_artists().await.map(LidarrSerdeable::from),
|
||||||
LidarrEvent::UpdateAndScanArtist(artist_id) => self
|
LidarrEvent::UpdateAndScanArtist(artist_id) => self
|
||||||
.update_and_scan_artist(artist_id)
|
.update_and_scan_artist(artist_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user