feat: Completed support for viewing Lidarr artist details
This commit is contained in:
@@ -245,6 +245,14 @@ pub struct AddArtistSearchResult {
|
||||
pub ratings: Option<Ratings>,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LidarrCommandBody {
|
||||
pub name: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub artist_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub struct DeleteArtistParams {
|
||||
@@ -291,6 +299,44 @@ pub struct EditArtistParams {
|
||||
pub clear_tags: bool,
|
||||
}
|
||||
|
||||
#[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Album {
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub id: i64,
|
||||
pub title: HorizontallyScrollableText,
|
||||
pub foreign_album_id: String,
|
||||
pub monitored: bool,
|
||||
#[serde(default)]
|
||||
pub any_release_ok: bool,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub profile_id: i64,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub duration: i64,
|
||||
pub album_type: Option<String>,
|
||||
pub genres: Vec<String>,
|
||||
pub ratings: Option<Ratings>,
|
||||
pub release_date: Option<DateTime<Utc>>,
|
||||
pub statistics: Option<AlbumStatistics>,
|
||||
}
|
||||
|
||||
#[derive(Derivative, Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AlbumStatistics {
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub track_file_count: i64,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub track_count: i64,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub total_track_count: i64,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub size_on_disk: i64,
|
||||
#[serde(deserialize_with = "super::from_f64")]
|
||||
pub percent_of_tracks: f64,
|
||||
}
|
||||
|
||||
impl Eq for AlbumStatistics {}
|
||||
|
||||
impl From<LidarrSerdeable> for Serdeable {
|
||||
fn from(value: LidarrSerdeable) -> Serdeable {
|
||||
Serdeable::Lidarr(value)
|
||||
@@ -300,6 +346,8 @@ impl From<LidarrSerdeable> for Serdeable {
|
||||
serde_enum_from!(
|
||||
LidarrSerdeable {
|
||||
AddArtistSearchResults(Vec<AddArtistSearchResult>),
|
||||
Albums(Vec<Album>),
|
||||
Album(Album),
|
||||
Artist(Artist),
|
||||
Artists(Vec<Artist>),
|
||||
DiskSpaces(Vec<DiskSpace>),
|
||||
|
||||
@@ -5,7 +5,7 @@ mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
use crate::models::lidarr_models::{
|
||||
AddArtistSearchResult, DownloadRecord, DownloadStatus, DownloadsResponse, Member,
|
||||
AddArtistSearchResult, Album, DownloadRecord, DownloadStatus, DownloadsResponse, Member,
|
||||
MetadataProfile, MonitorType, NewItemMonitorType, SystemStatus,
|
||||
};
|
||||
use crate::models::servarr_models::{
|
||||
@@ -401,6 +401,45 @@ mod tests {
|
||||
assert_eq!(lidarr_serdeable, LidarrSerdeable::Tags(tags));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_serdeable_from_add_artist_search_results() {
|
||||
let search_results = vec![AddArtistSearchResult {
|
||||
foreign_artist_id: "test-id".to_owned(),
|
||||
..AddArtistSearchResult::default()
|
||||
}];
|
||||
|
||||
let lidarr_serdeable: LidarrSerdeable = search_results.clone().into();
|
||||
|
||||
assert_eq!(
|
||||
lidarr_serdeable,
|
||||
LidarrSerdeable::AddArtistSearchResults(search_results)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_serdeable_from_albums() {
|
||||
let albums = vec![Album {
|
||||
id: 1,
|
||||
..Album::default()
|
||||
}];
|
||||
|
||||
let lidarr_serdeable: LidarrSerdeable = albums.clone().into();
|
||||
|
||||
assert_eq!(lidarr_serdeable, LidarrSerdeable::Albums(albums));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_serdeable_from_album() {
|
||||
let album = Album {
|
||||
id: 1,
|
||||
..Album::default()
|
||||
};
|
||||
|
||||
let lidarr_serdeable: LidarrSerdeable = album.clone().into();
|
||||
|
||||
assert_eq!(lidarr_serdeable, LidarrSerdeable::Album(album));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_status_display() {
|
||||
assert_str_eq!(ArtistStatus::Continuing.to_string(), "continuing");
|
||||
@@ -501,19 +540,4 @@ mod tests {
|
||||
assert!(search_result.genres.is_empty());
|
||||
assert_none!(&search_result.ratings);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lidarr_serdeable_from_add_artist_search_results() {
|
||||
let search_results = vec![AddArtistSearchResult {
|
||||
foreign_artist_id: "test-id".to_owned(),
|
||||
..AddArtistSearchResult::default()
|
||||
}];
|
||||
|
||||
let lidarr_serdeable: LidarrSerdeable = search_results.clone().into();
|
||||
|
||||
assert_eq!(
|
||||
lidarr_serdeable,
|
||||
LidarrSerdeable::AddArtistSearchResults(search_results)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use serde_json::Number;
|
||||
|
||||
use super::modals::{AddArtistModal, EditArtistModal};
|
||||
use crate::app::lidarr::lidarr_context_clues::ARTISTS_CONTEXT_CLUES;
|
||||
use crate::app::lidarr::lidarr_context_clues::{
|
||||
ARTIST_DETAILS_CONTEXT_CLUES, ARTISTS_CONTEXT_CLUES,
|
||||
};
|
||||
use crate::models::{
|
||||
BlockSelectionState, HorizontallyScrollableText, Route, TabRoute, TabState,
|
||||
lidarr_models::{AddArtistSearchResult, Artist, DownloadRecord},
|
||||
lidarr_models::{AddArtistSearchResult, Album, Artist, DownloadRecord},
|
||||
servarr_models::{DiskSpace, RootFolder},
|
||||
stateful_table::StatefulTable,
|
||||
};
|
||||
@@ -19,8 +21,8 @@ use {
|
||||
crate::models::stateful_table::SortOption,
|
||||
crate::network::lidarr_network::lidarr_network_test_utils::test_utils::quality_profile_map,
|
||||
crate::network::lidarr_network::lidarr_network_test_utils::test_utils::{
|
||||
add_artist_search_result, download_record, metadata_profile, metadata_profile_map,
|
||||
quality_profile, root_folder, tags_map,
|
||||
add_artist_search_result, album, artist, download_record, metadata_profile,
|
||||
metadata_profile_map, quality_profile, root_folder, tags_map,
|
||||
},
|
||||
crate::network::servarr_test_utils::diskspace,
|
||||
strum::{Display, EnumString, IntoEnumIterator},
|
||||
@@ -35,6 +37,8 @@ pub struct LidarrData<'a> {
|
||||
pub add_artist_search: Option<HorizontallyScrollableText>,
|
||||
pub add_import_list_exclusion: bool,
|
||||
pub add_searched_artists: Option<StatefulTable<AddArtistSearchResult>>,
|
||||
pub albums: StatefulTable<Album>,
|
||||
pub artist_info_tabs: TabState,
|
||||
pub artists: StatefulTable<Artist>,
|
||||
pub delete_artist_files: bool,
|
||||
pub disk_space_vec: Vec<DiskSpace>,
|
||||
@@ -58,6 +62,11 @@ impl LidarrData<'_> {
|
||||
self.add_import_list_exclusion = false;
|
||||
}
|
||||
|
||||
pub fn reset_artist_info_tabs(&mut self) {
|
||||
self.albums = StatefulTable::default();
|
||||
self.artist_info_tabs.index = 0;
|
||||
}
|
||||
|
||||
pub fn tag_ids_to_display(&self, tag_ids: &[Number]) -> String {
|
||||
tag_ids
|
||||
.iter()
|
||||
@@ -97,6 +106,7 @@ impl<'a> Default for LidarrData<'a> {
|
||||
add_artist_search: None,
|
||||
add_import_list_exclusion: false,
|
||||
add_searched_artists: None,
|
||||
albums: StatefulTable::default(),
|
||||
artists: StatefulTable::default(),
|
||||
delete_artist_files: false,
|
||||
disk_space_vec: Vec::new(),
|
||||
@@ -117,6 +127,12 @@ impl<'a> Default for LidarrData<'a> {
|
||||
contextual_help: Some(&ARTISTS_CONTEXT_CLUES),
|
||||
config: None,
|
||||
}]),
|
||||
artist_info_tabs: TabState::new(vec![TabRoute {
|
||||
title: "Albums".to_string(),
|
||||
route: ActiveLidarrBlock::ArtistDetails.into(),
|
||||
contextual_help: Some(&ARTIST_DETAILS_CONTEXT_CLUES),
|
||||
config: None,
|
||||
}]),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +185,9 @@ impl LidarrData<'_> {
|
||||
tags_map: tags_map(),
|
||||
..LidarrData::default()
|
||||
};
|
||||
lidarr_data.artists.set_items(vec![Artist::default()]);
|
||||
lidarr_data.albums.set_items(vec![album()]);
|
||||
lidarr_data.albums.search = Some("album search".into());
|
||||
lidarr_data.artists.set_items(vec![artist()]);
|
||||
lidarr_data.artists.sorting(vec![SortOption {
|
||||
name: "Name",
|
||||
cmp_fn: Some(|a: &Artist, b: &Artist| a.artist_name.text.cmp(&b.artist_name.text)),
|
||||
@@ -193,6 +211,7 @@ impl LidarrData<'_> {
|
||||
pub enum ActiveLidarrBlock {
|
||||
#[default]
|
||||
Artists,
|
||||
ArtistDetails,
|
||||
ArtistsSortPrompt,
|
||||
AddArtistAlreadyInLibrary,
|
||||
AddArtistConfirmPrompt,
|
||||
@@ -206,6 +225,7 @@ pub enum ActiveLidarrBlock {
|
||||
AddArtistSelectQualityProfile,
|
||||
AddArtistSelectRootFolder,
|
||||
AddArtistTagsInput,
|
||||
AutomaticallySearchArtistPrompt,
|
||||
DeleteArtistPrompt,
|
||||
DeleteArtistConfirmPrompt,
|
||||
DeleteArtistToggleDeleteFile,
|
||||
@@ -220,9 +240,12 @@ pub enum ActiveLidarrBlock {
|
||||
EditArtistToggleMonitored,
|
||||
FilterArtists,
|
||||
FilterArtistsError,
|
||||
SearchAlbums,
|
||||
SearchAlbumsError,
|
||||
SearchArtists,
|
||||
SearchArtistsError,
|
||||
UpdateAllArtistsPrompt,
|
||||
UpdateAndScanArtistPrompt,
|
||||
}
|
||||
|
||||
pub static LIBRARY_BLOCKS: [ActiveLidarrBlock; 7] = [
|
||||
@@ -235,6 +258,14 @@ pub static LIBRARY_BLOCKS: [ActiveLidarrBlock; 7] = [
|
||||
ActiveLidarrBlock::UpdateAllArtistsPrompt,
|
||||
];
|
||||
|
||||
pub static ARTIST_DETAILS_BLOCKS: [ActiveLidarrBlock; 5] = [
|
||||
ActiveLidarrBlock::ArtistDetails,
|
||||
ActiveLidarrBlock::AutomaticallySearchArtistPrompt,
|
||||
ActiveLidarrBlock::SearchAlbums,
|
||||
ActiveLidarrBlock::SearchAlbumsError,
|
||||
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
|
||||
];
|
||||
|
||||
pub static ADD_ARTIST_BLOCKS: [ActiveLidarrBlock; 12] = [
|
||||
ActiveLidarrBlock::AddArtistAlreadyInLibrary,
|
||||
ActiveLidarrBlock::AddArtistConfirmPrompt,
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::app::lidarr::lidarr_context_clues::ARTISTS_CONTEXT_CLUES;
|
||||
use crate::app::lidarr::lidarr_context_clues::{
|
||||
ARTIST_DETAILS_CONTEXT_CLUES, ARTISTS_CONTEXT_CLUES,
|
||||
};
|
||||
use crate::models::lidarr_models::Album;
|
||||
use crate::models::servarr_data::lidarr::lidarr_data::{
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, DELETE_ARTIST_BLOCKS,
|
||||
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ARTIST_DETAILS_BLOCKS, DELETE_ARTIST_BLOCKS,
|
||||
DELETE_ARTIST_SELECTION_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS,
|
||||
};
|
||||
use crate::models::{
|
||||
@@ -44,6 +47,18 @@ mod tests {
|
||||
assert!(!lidarr_data.add_import_list_exclusion);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reset_artist_info_tabs() {
|
||||
let mut lidarr_data = LidarrData::default();
|
||||
lidarr_data.albums.set_items(vec![Album::default()]);
|
||||
lidarr_data.artist_info_tabs.index = 1;
|
||||
|
||||
lidarr_data.reset_artist_info_tabs();
|
||||
|
||||
assert_is_empty!(lidarr_data.albums);
|
||||
assert_eq!(lidarr_data.artist_info_tabs.index, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_tag_ids_to_display() {
|
||||
let mut tags_map = BiMap::new();
|
||||
@@ -112,6 +127,7 @@ mod tests {
|
||||
assert_none!(lidarr_data.add_artist_search);
|
||||
assert!(!lidarr_data.add_import_list_exclusion);
|
||||
assert_none!(lidarr_data.add_searched_artists);
|
||||
assert_is_empty!(lidarr_data.albums);
|
||||
assert_is_empty!(lidarr_data.artists);
|
||||
assert!(!lidarr_data.delete_artist_files);
|
||||
assert_is_empty!(lidarr_data.disk_space_vec);
|
||||
@@ -139,6 +155,18 @@ mod tests {
|
||||
&ARTISTS_CONTEXT_CLUES
|
||||
);
|
||||
assert_none!(lidarr_data.main_tabs.tabs[0].config);
|
||||
|
||||
assert_eq!(lidarr_data.artist_info_tabs.tabs.len(), 1);
|
||||
assert_str_eq!(lidarr_data.artist_info_tabs.tabs[0].title, "Albums");
|
||||
assert_eq!(
|
||||
lidarr_data.artist_info_tabs.tabs[0].route,
|
||||
ActiveLidarrBlock::ArtistDetails.into()
|
||||
);
|
||||
assert_some_eq_x!(
|
||||
&lidarr_data.artist_info_tabs.tabs[0].contextual_help,
|
||||
&ARTIST_DETAILS_CONTEXT_CLUES
|
||||
);
|
||||
assert_none!(lidarr_data.artist_info_tabs.tabs[0].config);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -153,6 +181,16 @@ mod tests {
|
||||
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::UpdateAllArtistsPrompt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_artist_details_blocks_contains_expected_blocks() {
|
||||
assert_eq!(ARTIST_DETAILS_BLOCKS.len(), 5);
|
||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::ArtistDetails));
|
||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::AutomaticallySearchArtistPrompt));
|
||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::SearchAlbums));
|
||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::SearchAlbumsError));
|
||||
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::UpdateAndScanArtistPrompt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_artist_blocks_contents() {
|
||||
assert_eq!(ADD_ARTIST_BLOCKS.len(), 12);
|
||||
|
||||
Reference in New Issue
Block a user