Compare commits
2 Commits
1329589bd6
...
bc6ecc39f4
| Author | SHA1 | Date | |
|---|---|---|---|
| bc6ecc39f4 | |||
| 5e70d70758 |
@@ -6,8 +6,8 @@ use crate::app::context_clues::{
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::models::Route;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
|
||||
EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||
ADD_ARTIST_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS,
|
||||
ActiveLidarrBlock, EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -92,6 +92,55 @@ pub static MANUAL_ARTIST_SEARCH_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||
(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;
|
||||
|
||||
impl ContextClueProvider for LidarrContextClueProvider {
|
||||
@@ -106,6 +155,14 @@ impl ContextClueProvider for LidarrContextClueProvider {
|
||||
.lidarr_data
|
||||
.artist_info_tabs
|
||||
.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::AddArtistEmptySearchResults
|
||||
| ActiveLidarrBlock::TestAllIndexers
|
||||
|
||||
@@ -7,14 +7,16 @@ mod tests {
|
||||
};
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::app::lidarr::lidarr_context_clues::{
|
||||
ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES, ARTIST_DETAILS_CONTEXT_CLUES,
|
||||
ARTIST_HISTORY_CONTEXT_CLUES, ARTISTS_CONTEXT_CLUES, LidarrContextClueProvider,
|
||||
ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES, ALBUM_DETAILS_CONTEXT_CLUES,
|
||||
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,
|
||||
};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ROOT_FOLDER_BLOCKS, ActiveLidarrBlock, EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS,
|
||||
INDEXER_SETTINGS_BLOCKS, LidarrData,
|
||||
};
|
||||
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use rstest::rstest;
|
||||
|
||||
@@ -236,6 +238,123 @@ mod tests {
|
||||
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]
|
||||
#[case(0, ActiveLidarrBlock::ArtistDetails, &ARTIST_DETAILS_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);
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn test_lidarr_context_clue_provider_artists_block() {
|
||||
let mut app = App::test_default();
|
||||
@@ -362,7 +505,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[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();
|
||||
|
||||
app.push_navigation_stack(ActiveLidarrBlock::SystemTasks.into());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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_models::Indexer;
|
||||
use crate::network::NetworkEvent;
|
||||
@@ -120,6 +120,42 @@ mod tests {
|
||||
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]
|
||||
async fn test_dispatch_by_downloads_block() {
|
||||
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
|
||||
|
||||
@@ -54,6 +54,19 @@ impl App<'_> {
|
||||
.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 => {
|
||||
self
|
||||
.dispatch_network_event(
|
||||
@@ -134,6 +147,10 @@ impl App<'_> {
|
||||
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 {
|
||||
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")]
|
||||
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")]
|
||||
Artist {
|
||||
#[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?;
|
||||
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 {
|
||||
artist_id,
|
||||
delete_files_from_disk,
|
||||
|
||||
@@ -86,6 +86,40 @@ mod tests {
|
||||
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]
|
||||
fn test_delete_artist_requires_arguments() {
|
||||
let result = Cli::command().try_get_matches_from(["managarr", "lidarr", "delete", "artist"]);
|
||||
@@ -327,6 +361,32 @@ mod tests {
|
||||
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]
|
||||
async fn test_handle_delete_artist_command() {
|
||||
let expected_delete_artist_params = DeleteParams {
|
||||
|
||||
@@ -27,6 +27,23 @@ pub enum LidarrListCommand {
|
||||
)]
|
||||
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")]
|
||||
ArtistHistory {
|
||||
#[arg(
|
||||
@@ -72,6 +89,32 @@ pub enum LidarrListCommand {
|
||||
Tags,
|
||||
#[command(about = "List all Lidarr 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")]
|
||||
Updates,
|
||||
}
|
||||
@@ -110,6 +153,16 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrListCommand> for LidarrListCommandH
|
||||
.await?;
|
||||
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 } => {
|
||||
let resp = self
|
||||
.network
|
||||
@@ -204,6 +257,23 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrListCommand> for LidarrListCommandH
|
||||
.await?;
|
||||
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 => {
|
||||
let resp = self
|
||||
.network
|
||||
|
||||
@@ -69,6 +69,58 @@ mod tests {
|
||||
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]
|
||||
fn test_list_artist_history_requires_artist_id() {
|
||||
let result =
|
||||
@@ -172,6 +224,101 @@ mod tests {
|
||||
};
|
||||
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 {
|
||||
@@ -248,6 +395,36 @@ mod tests {
|
||||
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]
|
||||
async fn test_handle_list_artist_history_command() {
|
||||
let expected_artist_id = 1;
|
||||
@@ -353,5 +530,60 @@ mod tests {
|
||||
|
||||
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)]
|
||||
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(
|
||||
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> {
|
||||
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 } => {
|
||||
println!("Searching for artist discography releases. This may take a minute...");
|
||||
match self
|
||||
|
||||
@@ -23,6 +23,58 @@ mod tests {
|
||||
use clap::error::ErrorKind;
|
||||
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]
|
||||
fn test_manual_discography_search_requires_artist_id() {
|
||||
let result =
|
||||
@@ -65,6 +117,39 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
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]
|
||||
async fn test_manual_discography_search_command() {
|
||||
let expected_artist_id = 1;
|
||||
|
||||
@@ -18,6 +18,15 @@ mod trigger_automatic_search_command_handler_tests;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Subcommand)]
|
||||
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")]
|
||||
Artist {
|
||||
#[arg(
|
||||
@@ -58,6 +67,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, LidarrTriggerAutomaticSearchCommand>
|
||||
|
||||
async fn handle(self) -> Result<String> {
|
||||
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 } => {
|
||||
let resp = self
|
||||
.network
|
||||
|
||||
@@ -28,6 +28,36 @@ mod tests {
|
||||
use clap::error::ErrorKind;
|
||||
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]
|
||||
fn test_trigger_automatic_artist_search_requires_artist_id() {
|
||||
let result = Cli::command().try_get_matches_from([
|
||||
@@ -75,6 +105,35 @@ mod tests {
|
||||
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]
|
||||
async fn test_handle_trigger_automatic_artist_search_command() {
|
||||
let mut mock_network = MockNetworkTrait::new();
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use rstest::rstest;
|
||||
use serde_json::Number;
|
||||
use std::cmp::Ordering;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::lidarr_handlers::library::artist_details_handler::ArtistDetailsHandler;
|
||||
use crate::models::lidarr_models::LidarrHistoryItem;
|
||||
use crate::handlers::lidarr_handlers::library::artist_details_handler::{
|
||||
ArtistDetailsHandler, releases_sorting_options,
|
||||
};
|
||||
use crate::models::HorizontallyScrollableText;
|
||||
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
|
||||
};
|
||||
use crate::models::servarr_models::{Quality, QualityWrapper};
|
||||
|
||||
mod test_handle_delete {
|
||||
use super::*;
|
||||
@@ -50,6 +56,8 @@ mod tests {
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::assert_navigation_pushed;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::lidarr_handlers::library::artist_details_handler::ArtistDetailsHandler;
|
||||
@@ -59,7 +67,8 @@ mod tests {
|
||||
fn test_left_right_prompt_toggle(
|
||||
#[values(
|
||||
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
|
||||
ActiveLidarrBlock::AutomaticallySearchArtistPrompt
|
||||
ActiveLidarrBlock::AutomaticallySearchArtistPrompt,
|
||||
ActiveLidarrBlock::ManualArtistSearchConfirmPrompt
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
#[values(Key::Left, Key::Right)] key: Key,
|
||||
@@ -76,6 +85,50 @@ mod tests {
|
||||
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[case(
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
#[case(
|
||||
ActiveLidarrBlock::ManualArtistSearch,
|
||||
ActiveLidarrBlock::ArtistDetails
|
||||
)]
|
||||
fn test_artist_details_tabs_left_right_action(
|
||||
#[case] left_block: ActiveLidarrBlock,
|
||||
#[case] right_block: ActiveLidarrBlock,
|
||||
#[values(true, false)] is_loading: bool,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
app.is_loading = is_loading;
|
||||
app.push_navigation_stack(right_block.into());
|
||||
app.data.lidarr_data.artist_info_tabs.index = app
|
||||
.data
|
||||
.lidarr_data
|
||||
.artist_info_tabs
|
||||
.tabs
|
||||
.iter()
|
||||
.position(|tab_route| tab_route.route == right_block.into())
|
||||
.unwrap_or_default();
|
||||
|
||||
ArtistDetailsHandler::new(DEFAULT_KEYBINDINGS.left.key, &mut app, right_block, None).handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
app.data.lidarr_data.artist_info_tabs.get_active_route()
|
||||
);
|
||||
assert_navigation_pushed!(app, left_block.into());
|
||||
|
||||
ArtistDetailsHandler::new(DEFAULT_KEYBINDINGS.right.key, &mut app, left_block, None).handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
app.data.lidarr_data.artist_info_tabs.get_active_route()
|
||||
);
|
||||
assert_navigation_pushed!(app, right_block.into());
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_submit {
|
||||
@@ -84,11 +137,14 @@ mod tests {
|
||||
use crate::event::Key;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::lidarr_handlers::library::artist_details_handler::ArtistDetailsHandler;
|
||||
use crate::models::lidarr_models::LidarrHistoryItem;
|
||||
use crate::models::lidarr_models::{LidarrHistoryItem, LidarrReleaseDownloadBody};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock;
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::artist;
|
||||
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{
|
||||
artist, torrent_release,
|
||||
};
|
||||
use crate::{assert_navigation_popped, assert_navigation_pushed};
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
|
||||
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||
@@ -181,6 +237,106 @@ mod tests {
|
||||
|
||||
assert_eq!(app.get_current_route(), ActiveLidarrBlock::Artists.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_manual_artist_search_submit() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.discography_releases
|
||||
.set_items(vec![torrent_release()]);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
|
||||
ArtistDetailsHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearch,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_pushed!(
|
||||
app,
|
||||
ActiveLidarrBlock::ManualArtistSearchConfirmPrompt.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_manual_artist_search_submit_no_op_when_not_ready() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = true;
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
|
||||
ArtistDetailsHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearch,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
ActiveLidarrBlock::ManualArtistSearch.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_manual_artist_search_confirm_prompt_confirm_submit() {
|
||||
let mut app = App::test_default();
|
||||
let release = torrent_release();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.discography_releases
|
||||
.set_items(vec![release.clone()]);
|
||||
app.data.lidarr_data.prompt_confirm = true;
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearchConfirmPrompt.into());
|
||||
|
||||
ArtistDetailsHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearchConfirmPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.prompt_confirm_action,
|
||||
Some(LidarrEvent::DownloadRelease(LidarrReleaseDownloadBody {
|
||||
guid: release.guid,
|
||||
indexer_id: release.indexer_id,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_manual_artist_search_confirm_prompt_decline_submit() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.discography_releases
|
||||
.set_items(vec![torrent_release()]);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearchConfirmPrompt.into());
|
||||
|
||||
ArtistDetailsHandler::new(
|
||||
SUBMIT_KEY,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearchConfirmPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
assert_none!(app.data.lidarr_data.prompt_confirm_action);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_esc {
|
||||
@@ -193,6 +349,7 @@ mod tests {
|
||||
use crate::models::lidarr_models::LidarrHistoryItem;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock;
|
||||
use crate::models::stateful_table::StatefulTable;
|
||||
use pretty_assertions::assert_eq;
|
||||
use ratatui::widgets::TableState;
|
||||
use rstest::rstest;
|
||||
|
||||
@@ -200,7 +357,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_artist_history_details_block_esc() {
|
||||
let mut app = App::test_default();
|
||||
let mut app = App::test_default_fully_populated();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistHistory.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistHistoryDetails.into());
|
||||
|
||||
@@ -242,7 +399,8 @@ mod tests {
|
||||
fn test_artist_details_esc(
|
||||
#[values(
|
||||
ActiveLidarrBlock::AutomaticallySearchArtistPrompt,
|
||||
ActiveLidarrBlock::UpdateAndScanArtistPrompt
|
||||
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
|
||||
ActiveLidarrBlock::ManualArtistSearchConfirmPrompt
|
||||
)]
|
||||
prompt_block: ActiveLidarrBlock,
|
||||
#[values(true, false)] is_ready: bool,
|
||||
@@ -258,6 +416,31 @@ mod tests {
|
||||
assert!(!app.data.lidarr_data.prompt_confirm);
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_blocks_esc(
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default();
|
||||
app.data.lidarr_data.artist_history.filter = None;
|
||||
app.data.lidarr_data.artist_history.filtered_items = None;
|
||||
app.data.lidarr_data.artist_history.filtered_state = None;
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
app.push_navigation_stack(active_lidarr_block.into());
|
||||
|
||||
ArtistDetailsHandler::new(ESC_KEY, &mut app, active_lidarr_block, None).handle();
|
||||
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::Artists.into());
|
||||
assert_is_empty!(app.data.lidarr_data.albums);
|
||||
assert_is_empty!(app.data.lidarr_data.discography_releases);
|
||||
assert_is_empty!(app.data.lidarr_data.artist_history);
|
||||
assert_eq!(app.data.lidarr_data.artist_info_tabs.index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_char_key_event {
|
||||
@@ -266,18 +449,23 @@ mod tests {
|
||||
use crate::assert_navigation_pushed;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::lidarr_handlers::library::artist_details_handler::ArtistDetailsHandler;
|
||||
use crate::models::lidarr_models::Artist;
|
||||
use crate::models::lidarr_models::{Artist, LidarrReleaseDownloadBody};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ActiveLidarrBlock, EDIT_ARTIST_SELECTION_BLOCKS,
|
||||
};
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::torrent_release;
|
||||
use crate::{assert_modal_absent, assert_modal_present, assert_navigation_popped};
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_edit_key(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
@@ -310,7 +498,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_edit_key_no_op_when_not_ready(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default();
|
||||
@@ -403,7 +595,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_auto_search_key(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
@@ -425,7 +621,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_auto_search_key_no_op_when_not_ready(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
@@ -445,7 +645,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_update_key(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
@@ -464,7 +668,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_update_key_no_op_when_not_ready(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
@@ -484,7 +692,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_refresh_key(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
@@ -506,7 +718,11 @@ mod tests {
|
||||
|
||||
#[rstest]
|
||||
fn test_artist_details_refresh_key_no_op_when_not_ready(
|
||||
#[values(ActiveLidarrBlock::ArtistDetails, ActiveLidarrBlock::ArtistHistory)]
|
||||
#[values(
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::ArtistHistory,
|
||||
ActiveLidarrBlock::ManualArtistSearch
|
||||
)]
|
||||
active_lidarr_block: ActiveLidarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default();
|
||||
@@ -560,6 +776,37 @@ mod tests {
|
||||
&expected_action
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_manual_artist_search_confirm_prompt_confirm_key() {
|
||||
let mut app = App::test_default();
|
||||
let release = torrent_release();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.discography_releases
|
||||
.set_items(vec![release.clone()]);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ManualArtistSearchConfirmPrompt.into());
|
||||
|
||||
ArtistDetailsHandler::new(
|
||||
DEFAULT_KEYBINDINGS.confirm.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearchConfirmPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert!(app.data.lidarr_data.prompt_confirm);
|
||||
assert_navigation_popped!(app, ActiveLidarrBlock::ManualArtistSearch.into());
|
||||
assert_eq!(
|
||||
app.data.lidarr_data.prompt_confirm_action,
|
||||
Some(LidarrEvent::DownloadRelease(LidarrReleaseDownloadBody {
|
||||
guid: release.guid,
|
||||
indexer_id: release.indexer_id,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -692,4 +939,252 @@ mod tests {
|
||||
|
||||
assert!(handler.is_ready());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_handler_is_not_ready_when_not_loading_and_discography_releases_is_empty() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
|
||||
let handler = ArtistDetailsHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearch,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(!handler.is_ready());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_handler_ready_when_not_loading_and_discography_releases_is_non_empty() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveLidarrBlock::Artists.into());
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.discography_releases
|
||||
.set_items(vec![LidarrRelease::default()]);
|
||||
|
||||
let handler = ArtistDetailsHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::ManualArtistSearch,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(handler.is_ready());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delegates_delete_album_blocks_to_delete_album_handler() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.albums
|
||||
.set_items(vec![Album::default()]);
|
||||
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
|
||||
app.push_navigation_stack(ActiveLidarrBlock::DeleteAlbumPrompt.into());
|
||||
|
||||
ArtistDetailsHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveLidarrBlock::DeleteAlbumPrompt,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
ActiveLidarrBlock::ArtistDetails.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_source() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering =
|
||||
|a, b| a.protocol.cmp(&b.protocol);
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[0].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Source");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_age() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering = |a, b| a.age.cmp(&b.age);
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[1].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Age");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_rejected() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering =
|
||||
|a, b| a.rejected.cmp(&b.rejected);
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[2].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Rejected");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_title() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering = |a, b| {
|
||||
a.title
|
||||
.text
|
||||
.to_lowercase()
|
||||
.cmp(&b.title.text.to_lowercase())
|
||||
};
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[3].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Title");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_indexer() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering =
|
||||
|a, b| a.indexer.to_lowercase().cmp(&b.indexer.to_lowercase());
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[4].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Indexer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_size() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering =
|
||||
|a, b| a.size.cmp(&b.size);
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[5].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Size");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_peers() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering = |a, b| {
|
||||
let default_number = Number::from(i64::MAX);
|
||||
let seeder_a = a
|
||||
.seeders
|
||||
.as_ref()
|
||||
.unwrap_or(&default_number)
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
let seeder_b = b
|
||||
.seeders
|
||||
.as_ref()
|
||||
.unwrap_or(&default_number)
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
|
||||
seeder_a.cmp(&seeder_b)
|
||||
};
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[6].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Peers");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_releases_sorting_options_quality() {
|
||||
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering =
|
||||
|a, b| a.quality.cmp(&b.quality);
|
||||
let mut expected_releases_vec = release_vec();
|
||||
expected_releases_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = releases_sorting_options()[7].clone();
|
||||
let mut sorted_releases_vec = release_vec();
|
||||
sorted_releases_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_releases_vec, expected_releases_vec);
|
||||
assert_str_eq!(sort_option.name, "Quality");
|
||||
}
|
||||
|
||||
fn release_vec() -> Vec<LidarrRelease> {
|
||||
let release_a = LidarrRelease {
|
||||
protocol: "Protocol A".to_owned(),
|
||||
age: 1,
|
||||
title: HorizontallyScrollableText::from("Title A"),
|
||||
indexer: "Indexer A".to_owned(),
|
||||
size: 1,
|
||||
rejected: true,
|
||||
seeders: Some(Number::from(1)),
|
||||
quality: QualityWrapper {
|
||||
quality: Quality {
|
||||
name: "Quality A".to_owned(),
|
||||
},
|
||||
},
|
||||
..LidarrRelease::default()
|
||||
};
|
||||
let release_b = LidarrRelease {
|
||||
protocol: "Protocol B".to_owned(),
|
||||
age: 2,
|
||||
title: HorizontallyScrollableText::from("title B"),
|
||||
indexer: "indexer B".to_owned(),
|
||||
size: 2,
|
||||
rejected: false,
|
||||
seeders: Some(Number::from(2)),
|
||||
quality: QualityWrapper {
|
||||
quality: Quality {
|
||||
name: "Quality B".to_owned(),
|
||||
},
|
||||
},
|
||||
..LidarrRelease::default()
|
||||
};
|
||||
let release_c = LidarrRelease {
|
||||
protocol: "Protocol C".to_owned(),
|
||||
age: 3,
|
||||
title: HorizontallyScrollableText::from("Title C"),
|
||||
indexer: "Indexer C".to_owned(),
|
||||
size: 3,
|
||||
rejected: false,
|
||||
seeders: None,
|
||||
quality: QualityWrapper {
|
||||
quality: Quality {
|
||||
name: "Quality C".to_owned(),
|
||||
},
|
||||
},
|
||||
..LidarrRelease::default()
|
||||
};
|
||||
|
||||
vec![release_a, release_b, release_c]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,6 +256,8 @@ pub struct LidarrCommandBody {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
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)]
|
||||
@@ -495,6 +497,67 @@ pub struct LidarrReleaseDownloadBody {
|
||||
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 {
|
||||
fn from(value: LidarrSerdeable) -> Serdeable {
|
||||
Serdeable::Lidarr(value)
|
||||
@@ -527,6 +590,9 @@ serde_enum_from!(
|
||||
Tag(Tag),
|
||||
Tags(Vec<Tag>),
|
||||
Tasks(Vec<LidarrTask>),
|
||||
Track(Track),
|
||||
Tracks(Vec<Track>),
|
||||
TrackFiles(Vec<TrackFile>),
|
||||
Updates(Vec<Update>),
|
||||
Value(Value),
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
use crate::models::lidarr_models::{
|
||||
AddArtistSearchResult, Album, DownloadRecord, DownloadStatus, DownloadsResponse,
|
||||
AddArtistSearchResult, Album, AudioTags, DownloadRecord, DownloadStatus, DownloadsResponse,
|
||||
LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper, LidarrRelease, LidarrTask,
|
||||
Member, MetadataProfile, MonitorType, NewItemMonitorType, SystemStatus,
|
||||
MediaInfo, Member, MetadataProfile, MonitorType, NewItemMonitorType, SystemStatus, Track,
|
||||
TrackFile,
|
||||
};
|
||||
use crate::models::servarr_models::{
|
||||
DiskSpace, HostConfig, Indexer, IndexerSettings, IndexerTestResult, Log, LogResponse,
|
||||
@@ -577,6 +578,50 @@ mod tests {
|
||||
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]
|
||||
fn test_artist_status_display() {
|
||||
assert_str_eq!(ArtistStatus::Continuing.to_string(), "continuing");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde_json::Number;
|
||||
|
||||
use super::modals::{AddArtistModal, AddRootFolderModal, EditArtistModal};
|
||||
use super::modals::{AddArtistModal, AddRootFolderModal, AlbumDetailsModal, EditArtistModal};
|
||||
use crate::app::context_clues::{
|
||||
DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
@@ -39,6 +39,7 @@ use {
|
||||
crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{
|
||||
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::indexer_test_result,
|
||||
crate::network::servarr_test_utils::queued_event,
|
||||
@@ -58,6 +59,7 @@ pub struct LidarrData<'a> {
|
||||
pub add_root_folder_modal: Option<AddRootFolderModal>,
|
||||
pub add_searched_artists: Option<StatefulTable<AddArtistSearchResult>>,
|
||||
pub albums: StatefulTable<Album>,
|
||||
pub album_details_modal: Option<AlbumDetailsModal>,
|
||||
pub artist_history: StatefulTable<LidarrHistoryItem>,
|
||||
pub artist_info_tabs: TabState,
|
||||
pub artists: StatefulTable<Artist>,
|
||||
@@ -143,6 +145,7 @@ impl<'a> Default for LidarrData<'a> {
|
||||
add_root_folder_modal: None,
|
||||
add_searched_artists: None,
|
||||
albums: StatefulTable::default(),
|
||||
album_details_modal: None,
|
||||
artist_history: StatefulTable::default(),
|
||||
artists: StatefulTable::default(),
|
||||
delete_files: false,
|
||||
@@ -289,6 +292,27 @@ impl LidarrData<'_> {
|
||||
.metadata_profile_list
|
||||
.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 {
|
||||
name: "DrunkenSlug".into(),
|
||||
enable_rss: Some(true),
|
||||
@@ -305,6 +329,7 @@ impl LidarrData<'_> {
|
||||
indexer_test_all_results.set_items(vec![indexer_test_result()]);
|
||||
|
||||
let mut lidarr_data = LidarrData {
|
||||
album_details_modal: Some(album_details_modal),
|
||||
delete_files: true,
|
||||
disk_space_vec: vec![diskspace()],
|
||||
quality_profile_map: quality_profile_map(),
|
||||
@@ -376,9 +401,6 @@ pub enum ActiveLidarrBlock {
|
||||
ArtistHistoryDetails,
|
||||
ArtistHistorySortPrompt,
|
||||
ArtistsSortPrompt,
|
||||
ManualArtistSearch,
|
||||
ManualArtistSearchConfirmPrompt,
|
||||
ManualArtistSearchSortPrompt,
|
||||
AddArtistAlreadyInLibrary,
|
||||
AddArtistConfirmPrompt,
|
||||
AddArtistEmptySearchResults,
|
||||
@@ -400,7 +422,12 @@ pub enum ActiveLidarrBlock {
|
||||
AddRootFolderSelectQualityProfile,
|
||||
AddRootFolderSelectMetadataProfile,
|
||||
AddRootFolderTagsInput,
|
||||
AlbumDetails,
|
||||
AlbumHistory,
|
||||
AlbumHistoryDetails,
|
||||
AlbumHistorySortPrompt,
|
||||
AllIndexerSettingsPrompt,
|
||||
AutomaticallySearchAlbumPrompt,
|
||||
AutomaticallySearchArtistPrompt,
|
||||
DeleteAlbumPrompt,
|
||||
DeleteAlbumConfirmPrompt,
|
||||
@@ -410,6 +437,7 @@ pub enum ActiveLidarrBlock {
|
||||
DeleteArtistConfirmPrompt,
|
||||
DeleteArtistToggleDeleteFile,
|
||||
DeleteArtistToggleAddListExclusion,
|
||||
DeleteTrackFilePrompt,
|
||||
DeleteDownloadPrompt,
|
||||
DeleteRootFolderPrompt,
|
||||
Downloads,
|
||||
@@ -433,6 +461,8 @@ pub enum ActiveLidarrBlock {
|
||||
EditIndexerPriorityInput,
|
||||
EditIndexerTagsInput,
|
||||
DeleteIndexerPrompt,
|
||||
FilterAlbumHistory,
|
||||
FilterAlbumHistoryError,
|
||||
FilterArtists,
|
||||
FilterArtistsError,
|
||||
FilterHistory,
|
||||
@@ -448,9 +478,17 @@ pub enum ActiveLidarrBlock {
|
||||
IndexerSettingsMinimumAgeInput,
|
||||
IndexerSettingsRetentionInput,
|
||||
IndexerSettingsRssSyncIntervalInput,
|
||||
ManualAlbumSearch,
|
||||
ManualAlbumSearchConfirmPrompt,
|
||||
ManualAlbumSearchSortPrompt,
|
||||
ManualArtistSearch,
|
||||
ManualArtistSearchConfirmPrompt,
|
||||
ManualArtistSearchSortPrompt,
|
||||
TestAllIndexers,
|
||||
TestIndexer,
|
||||
RootFolders,
|
||||
SearchAlbumHistory,
|
||||
SearchAlbumHistoryError,
|
||||
SearchAlbums,
|
||||
SearchAlbumsError,
|
||||
SearchArtists,
|
||||
@@ -459,6 +497,8 @@ pub enum ActiveLidarrBlock {
|
||||
SearchHistoryError,
|
||||
SearchArtistHistory,
|
||||
SearchArtistHistoryError,
|
||||
SearchTracks,
|
||||
SearchTracksError,
|
||||
System,
|
||||
SystemLogs,
|
||||
SystemQueuedEvents,
|
||||
@@ -498,6 +538,24 @@ pub static ARTIST_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
|
||||
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] = [
|
||||
ActiveLidarrBlock::Downloads,
|
||||
ActiveLidarrBlock::DeleteDownloadPrompt,
|
||||
|
||||
@@ -10,9 +10,9 @@ mod tests {
|
||||
};
|
||||
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ARTIST_DETAILS_BLOCKS,
|
||||
DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_BLOCKS, DELETE_ARTIST_BLOCKS,
|
||||
DELETE_ARTIST_SELECTION_BLOCKS, DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS,
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS,
|
||||
ARTIST_DETAILS_BLOCKS, DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_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_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS, INDEXER_SETTINGS_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_none!(lidarr_data.add_searched_artists);
|
||||
assert_is_empty!(lidarr_data.albums);
|
||||
assert_none!(lidarr_data.album_details_modal);
|
||||
assert_is_empty!(lidarr_data.artists);
|
||||
assert_is_empty!(lidarr_data.artist_history);
|
||||
assert!(!lidarr_data.delete_files);
|
||||
@@ -304,6 +305,26 @@ mod tests {
|
||||
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]
|
||||
fn test_downloads_blocks_contains_expected_blocks() {
|
||||
assert_eq!(DOWNLOADS_BLOCKS.len(), 3);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use super::lidarr_data::LidarrData;
|
||||
use super::lidarr_data::{ActiveLidarrBlock, LidarrData};
|
||||
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::{LidarrHistoryItem, LidarrRelease, Track, TrackFile};
|
||||
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||
use crate::models::servarr_models::Indexer;
|
||||
use crate::models::stateful_table::StatefulTable;
|
||||
use crate::models::{
|
||||
HorizontallyScrollableText,
|
||||
HorizontallyScrollableText, TabRoute, TabState,
|
||||
lidarr_models::{MonitorType, NewItemMonitorType},
|
||||
servarr_models::RootFolder,
|
||||
stateful_list::StatefulList,
|
||||
};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "modals_tests.rs"]
|
||||
@@ -217,3 +221,45 @@ impl From<&LidarrData<'_>> for AddRootFolderModal {
|
||||
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)]
|
||||
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::servarr_data::lidarr::lidarr_data::LidarrData;
|
||||
use crate::models::servarr_data::lidarr::modals::{AddArtistModal, EditArtistModal};
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, LidarrData};
|
||||
use crate::models::servarr_data::lidarr::modals::{
|
||||
AddArtistModal, AlbumDetailsModal, EditArtistModal,
|
||||
};
|
||||
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||
use crate::models::servarr_models::{Indexer, IndexerField, RootFolder};
|
||||
use bimap::BiMap;
|
||||
@@ -208,4 +213,80 @@ mod tests {
|
||||
assert_str_eq!(edit_indexer_modal.api_key.text, "1234");
|
||||
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)]
|
||||
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::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 mockito::Matcher;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
use serde_json::{Value, json};
|
||||
|
||||
#[tokio::test]
|
||||
@@ -128,4 +135,397 @@ mod tests {
|
||||
|
||||
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::{Network, RequestMethod};
|
||||
use anyhow::Result;
|
||||
@@ -57,6 +60,88 @@ impl Network<'_, '_> {
|
||||
.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(
|
||||
&mut self,
|
||||
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 artists;
|
||||
mod tracks;
|
||||
|
||||
#[cfg(test)]
|
||||
#[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 {
|
||||
use crate::models::lidarr_models::{
|
||||
AddArtistSearchResult, Album, AlbumStatistics, Artist, ArtistStatistics, ArtistStatus,
|
||||
DownloadRecord, DownloadStatus, DownloadsResponse, EditArtistParams, LidarrHistoryData,
|
||||
LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper, LidarrRelease, LidarrTask,
|
||||
LidarrTaskName, Member, MetadataProfile, NewItemMonitorType, Ratings, SystemStatus,
|
||||
AudioTags, DownloadRecord, DownloadStatus, DownloadsResponse, EditArtistParams,
|
||||
LidarrHistoryData, LidarrHistoryEventType, LidarrHistoryItem, LidarrHistoryWrapper,
|
||||
LidarrRelease, LidarrTask, LidarrTaskName, MediaInfo, Member, MetadataProfile,
|
||||
NewItemMonitorType, Ratings, SystemStatus, Track, TrackFile,
|
||||
};
|
||||
use crate::models::servarr_models::IndexerSettings;
|
||||
use crate::models::servarr_models::{
|
||||
@@ -424,4 +425,54 @@ pub mod test_utils {
|
||||
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]
|
||||
fn test_resource_history(#[values(LidarrEvent::GetHistory(0))] event: LidarrEvent) {
|
||||
assert_str_eq!(event.resource(), "/history");
|
||||
fn test_resource_artist_history(
|
||||
#[values(LidarrEvent::GetArtistHistory(0), LidarrEvent::GetAlbumHistory(0, 0))]
|
||||
event: LidarrEvent,
|
||||
) {
|
||||
assert_str_eq!(event.resource(), "/history/artist");
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@@ -89,6 +92,7 @@ mod tests {
|
||||
#[values(
|
||||
LidarrEvent::UpdateAllArtists,
|
||||
LidarrEvent::TriggerAutomaticArtistSearch(0),
|
||||
LidarrEvent::TriggerAutomaticAlbumSearch(0),
|
||||
LidarrEvent::UpdateAndScanArtist(0),
|
||||
LidarrEvent::UpdateDownloads,
|
||||
LidarrEvent::GetQueuedEvents,
|
||||
@@ -128,13 +132,21 @@ mod tests {
|
||||
fn test_resource_release(
|
||||
#[values(
|
||||
LidarrEvent::GetDiscographyReleases(0),
|
||||
LidarrEvent::DownloadRelease(Default::default())
|
||||
LidarrEvent::DownloadRelease(Default::default()),
|
||||
LidarrEvent::GetAlbumReleases(0, 0)
|
||||
)]
|
||||
event: LidarrEvent,
|
||||
) {
|
||||
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]
|
||||
#[case(LidarrEvent::GetDiskSpace, "/diskspace")]
|
||||
#[case(LidarrEvent::GetMetadataProfiles, "/metadataprofile")]
|
||||
@@ -146,9 +158,10 @@ mod tests {
|
||||
#[case(LidarrEvent::GetUpdates, "/update")]
|
||||
#[case(LidarrEvent::HealthCheck, "/health")]
|
||||
#[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::TestAllIndexers, "/indexer/testall")]
|
||||
#[case(LidarrEvent::GetTracks(0, 0), "/track")]
|
||||
fn test_resource(#[case] event: LidarrEvent, #[case] expected_uri: &str) {
|
||||
assert_str_eq!(event.resource(), expected_uri);
|
||||
}
|
||||
|
||||
@@ -35,12 +35,15 @@ pub enum LidarrEvent {
|
||||
DeleteIndexer(i64),
|
||||
DeleteRootFolder(i64),
|
||||
DeleteTag(i64),
|
||||
DeleteTrackFile(i64),
|
||||
DownloadRelease(LidarrReleaseDownloadBody),
|
||||
EditArtist(EditArtistParams),
|
||||
EditAllIndexerSettings(IndexerSettings),
|
||||
EditIndexer(EditIndexerParams),
|
||||
GetAlbums(i64),
|
||||
GetAlbumDetails(i64),
|
||||
GetAlbumHistory(i64, i64),
|
||||
GetAlbumReleases(i64, i64),
|
||||
GetArtistHistory(i64),
|
||||
GetAllIndexerSettings,
|
||||
GetArtistDetails(i64),
|
||||
@@ -58,6 +61,8 @@ pub enum LidarrEvent {
|
||||
GetRootFolders,
|
||||
GetSecurityConfig,
|
||||
GetStatus,
|
||||
GetTracks(i64, i64),
|
||||
GetTrackFiles(i64),
|
||||
GetUpdates,
|
||||
GetTags,
|
||||
GetTasks,
|
||||
@@ -70,6 +75,7 @@ pub enum LidarrEvent {
|
||||
ToggleAlbumMonitoring(i64),
|
||||
ToggleArtistMonitoring(i64),
|
||||
TriggerAutomaticArtistSearch(i64),
|
||||
TriggerAutomaticAlbumSearch(i64),
|
||||
UpdateAllArtists,
|
||||
UpdateAndScanArtist(i64),
|
||||
UpdateDownloads,
|
||||
@@ -79,6 +85,7 @@ impl NetworkResource for LidarrEvent {
|
||||
fn resource(&self) -> &'static str {
|
||||
match &self {
|
||||
LidarrEvent::AddTag(_) | LidarrEvent::DeleteTag(_) | LidarrEvent::GetTags => "/tag",
|
||||
LidarrEvent::DeleteTrackFile(_) | LidarrEvent::GetTrackFiles(_) => "/trackfile",
|
||||
LidarrEvent::GetAllIndexerSettings | LidarrEvent::EditAllIndexerSettings(_) => {
|
||||
"/config/indexer"
|
||||
}
|
||||
@@ -92,13 +99,15 @@ impl NetworkResource for LidarrEvent {
|
||||
| LidarrEvent::ToggleAlbumMonitoring(_)
|
||||
| LidarrEvent::GetAlbumDetails(_)
|
||||
| LidarrEvent::DeleteAlbum(_) => "/album",
|
||||
LidarrEvent::GetArtistHistory(_) => "/history/artist",
|
||||
LidarrEvent::GetArtistHistory(_) | LidarrEvent::GetAlbumHistory(_, _) => "/history/artist",
|
||||
LidarrEvent::GetLogs(_) => "/log",
|
||||
LidarrEvent::GetDiskSpace => "/diskspace",
|
||||
LidarrEvent::GetDownloads(_) | LidarrEvent::DeleteDownload(_) => "/queue",
|
||||
LidarrEvent::GetHistory(_) => "/history",
|
||||
LidarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
|
||||
LidarrEvent::GetDiscographyReleases(_) | LidarrEvent::DownloadRelease(_) => "/release",
|
||||
LidarrEvent::GetDiscographyReleases(_)
|
||||
| LidarrEvent::DownloadRelease(_)
|
||||
| LidarrEvent::GetAlbumReleases(_, _) => "/release",
|
||||
LidarrEvent::GetHostConfig | LidarrEvent::GetSecurityConfig => "/config/host",
|
||||
LidarrEvent::GetIndexers | LidarrEvent::DeleteIndexer(_) | LidarrEvent::EditIndexer(_) => {
|
||||
"/indexer"
|
||||
@@ -108,7 +117,8 @@ impl NetworkResource for LidarrEvent {
|
||||
| LidarrEvent::UpdateAndScanArtist(_)
|
||||
| LidarrEvent::UpdateDownloads
|
||||
| LidarrEvent::GetQueuedEvents
|
||||
| LidarrEvent::StartTask(_) => "/command",
|
||||
| LidarrEvent::StartTask(_)
|
||||
| LidarrEvent::TriggerAutomaticAlbumSearch(_) => "/command",
|
||||
LidarrEvent::GetMetadataProfiles => "/metadataprofile",
|
||||
LidarrEvent::GetQualityProfiles => "/qualityprofile",
|
||||
LidarrEvent::GetRootFolders
|
||||
@@ -118,6 +128,7 @@ impl NetworkResource for LidarrEvent {
|
||||
LidarrEvent::TestAllIndexers => "/indexer/testall",
|
||||
LidarrEvent::GetStatus => "/system/status",
|
||||
LidarrEvent::GetTasks => "/system/task",
|
||||
LidarrEvent::GetTracks(_, _) => "/track",
|
||||
LidarrEvent::GetUpdates => "/update",
|
||||
LidarrEvent::HealthCheck => "/health",
|
||||
LidarrEvent::SearchNewArtist(_) => "/artist/lookup",
|
||||
@@ -152,6 +163,10 @@ impl Network<'_, '_> {
|
||||
.delete_lidarr_download(download_id)
|
||||
.await
|
||||
.map(LidarrSerdeable::from),
|
||||
LidarrEvent::DeleteTrackFile(track_file_id) => self
|
||||
.delete_lidarr_track_file(track_file_id)
|
||||
.await
|
||||
.map(LidarrSerdeable::from),
|
||||
LidarrEvent::EditAllIndexerSettings(params) => self
|
||||
.edit_all_lidarr_indexer_settings(params)
|
||||
.await
|
||||
@@ -191,6 +206,14 @@ impl Network<'_, '_> {
|
||||
.get_album_details(album_id)
|
||||
.await
|
||||
.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
|
||||
.get_artist_discography_releases(artist_id)
|
||||
.await
|
||||
@@ -244,6 +267,14 @@ impl Network<'_, '_> {
|
||||
LidarrEvent::GetStatus => self.get_lidarr_status().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::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::HealthCheck => self
|
||||
.get_lidarr_healthcheck()
|
||||
@@ -269,6 +300,10 @@ impl Network<'_, '_> {
|
||||
.trigger_automatic_artist_search(artist_id)
|
||||
.await
|
||||
.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::UpdateAndScanArtist(artist_id) => self
|
||||
.update_and_scan_artist(artist_id)
|
||||
|
||||
Reference in New Issue
Block a user