diff --git a/src/models/servarr_data/sonarr/modals.rs b/src/models/servarr_data/sonarr/modals.rs index 208c9a0..d8b53d5 100644 --- a/src/models/servarr_data/sonarr/modals.rs +++ b/src/models/servarr_data/sonarr/modals.rs @@ -3,7 +3,7 @@ use strum::IntoEnumIterator; use crate::models::{ servarr_data::modals::EditIndexerModal, servarr_models::{Indexer, RootFolder}, - sonarr_models::{Episode, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease}, + sonarr_models::{Episode, Series, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease}, stateful_list::StatefulList, stateful_table::StatefulTable, HorizontallyScrollableText, ScrollableText, @@ -142,6 +142,110 @@ impl From<&SonarrData> for EditIndexerModal { } } +#[derive(Default)] +pub struct EditSeriesModal { + pub series_type_list: StatefulList, + pub quality_profile_list: StatefulList, + pub language_profile_list: StatefulList, + pub monitored: Option, + pub use_season_folders: Option, + pub path: HorizontallyScrollableText, + pub tags: HorizontallyScrollableText, +} + +impl From<&SonarrData> for EditSeriesModal { + fn from(sonarr_data: &SonarrData) -> EditSeriesModal { + let mut edit_series_modal = EditSeriesModal::default(); + let Series { + path, + tags, + monitored, + season_folder, + series_type, + quality_profile_id, + language_profile_id, + .. + } = sonarr_data.series.current_selection(); + + edit_series_modal + .series_type_list + .set_items(Vec::from_iter(SeriesType::iter())); + edit_series_modal.path = path.clone().into(); + edit_series_modal.tags = tags + .iter() + .map(|tag_id| { + sonarr_data + .tags_map + .get_by_left(&tag_id.as_i64().unwrap()) + .unwrap() + .clone() + }) + .collect::>() + .join(", ") + .into(); + + edit_series_modal.monitored = Some(*monitored); + edit_series_modal.use_season_folders = Some(*season_folder); + + let series_type_index = edit_series_modal + .series_type_list + .items + .iter() + .position(|st| st == series_type); + edit_series_modal + .series_type_list + .state + .select(series_type_index); + + let mut quality_profile_names: Vec = sonarr_data + .quality_profile_map + .right_values() + .cloned() + .collect(); + quality_profile_names.sort(); + edit_series_modal + .quality_profile_list + .set_items(quality_profile_names); + let quality_profile_name = sonarr_data + .quality_profile_map + .get_by_left(quality_profile_id) + .unwrap(); + let quality_profile_index = edit_series_modal + .quality_profile_list + .items + .iter() + .position(|profile| profile == quality_profile_name); + edit_series_modal + .quality_profile_list + .state + .select(quality_profile_index); + let mut language_profile_names: Vec = sonarr_data + .language_profiles_map + .right_values() + .cloned() + .collect(); + language_profile_names.sort(); + edit_series_modal + .language_profile_list + .set_items(language_profile_names); + let language_profile_name = sonarr_data + .language_profiles_map + .get_by_left(language_profile_id) + .unwrap(); + let language_profile_index = edit_series_modal + .language_profile_list + .items + .iter() + .position(|profile| profile == language_profile_name); + edit_series_modal + .language_profile_list + .state + .select(language_profile_index); + + edit_series_modal + } +} + #[derive(Default)] pub struct EpisodeDetailsModal { pub episode_details: ScrollableText, diff --git a/src/models/servarr_data/sonarr/modals_tests.rs b/src/models/servarr_data/sonarr/modals_tests.rs index 0dfd63c..96af39f 100644 --- a/src/models/servarr_data/sonarr/modals_tests.rs +++ b/src/models/servarr_data/sonarr/modals_tests.rs @@ -5,12 +5,14 @@ mod tests { use rstest::rstest; use strum::IntoEnumIterator; + use crate::models::servarr_data::sonarr::modals::EditSeriesModal; use crate::models::servarr_models::{Indexer, IndexerField}; use crate::models::{ servarr_data::sonarr::{modals::AddSeriesModal, sonarr_data::SonarrData}, servarr_models::RootFolder, sonarr_models::{SeriesMonitor, SeriesType}, }; + use crate::models::{sonarr_models::Series, stateful_table::StatefulTable}; use serde_json::{Number, Value}; use crate::models::servarr_data::modals::EditIndexerModal; @@ -112,4 +114,111 @@ mod tests { assert!(edit_indexer_modal.seed_ratio.text.is_empty()); } } + + #[test] + fn test_edit_indexer_modal_from_sonarr_data_seed_ratio_value_is_none() { + let mut sonarr_data = SonarrData { + tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]), + ..SonarrData::default() + }; + let fields = vec![ + IndexerField { + name: Some("baseUrl".to_owned()), + value: Some(Value::String("https://test.com".to_owned())), + }, + IndexerField { + name: Some("apiKey".to_owned()), + value: Some(Value::String("1234".to_owned())), + }, + IndexerField { + name: Some("seedCriteria.seedRatio".to_owned()), + value: None, + }, + ]; + + let indexer = Indexer { + name: Some("Test".to_owned()), + enable_rss: true, + enable_automatic_search: true, + enable_interactive_search: true, + tags: vec![Number::from(1), Number::from(2)], + fields: Some(fields), + ..Indexer::default() + }; + sonarr_data.indexers.set_items(vec![indexer]); + + let edit_indexer_modal = EditIndexerModal::from(&sonarr_data); + + assert_str_eq!(edit_indexer_modal.name.text, "Test"); + assert_eq!(edit_indexer_modal.enable_rss, Some(true)); + assert_eq!(edit_indexer_modal.enable_automatic_search, Some(true)); + assert_eq!(edit_indexer_modal.enable_interactive_search, Some(true)); + assert_str_eq!(edit_indexer_modal.url.text, "https://test.com"); + assert_str_eq!(edit_indexer_modal.api_key.text, "1234"); + assert!(edit_indexer_modal.seed_ratio.text.is_empty()); + } + + #[rstest] + fn test_edit_series_modal_from_sonarr_data(#[values(true, false)] test_filtered_series: bool) { + let mut sonarr_data = SonarrData { + quality_profile_map: BiMap::from_iter([ + (2222, "HD - 1080p".to_owned()), + (1111, "Any".to_owned()), + ]), + language_profiles_map: BiMap::from_iter([ + (2222, "English".to_owned()), + (1111, "Any".to_owned()), + ]), + tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]), + series: StatefulTable::default(), + ..SonarrData::default() + }; + let series = Series { + path: "/nfs/seriess/Test".to_owned(), + monitored: true, + season_folder: true, + quality_profile_id: 2222, + language_profile_id: 2222, + series_type: SeriesType::Anime, + tags: vec![Number::from(1), Number::from(2)], + ..Series::default() + }; + + if test_filtered_series { + sonarr_data.series.set_filtered_items(vec![series]); + } else { + sonarr_data.series.set_items(vec![series]); + } + + let edit_series_modal = EditSeriesModal::from(&sonarr_data); + + assert_eq!( + edit_series_modal.series_type_list.items, + Vec::from_iter(SeriesType::iter()) + ); + assert_eq!( + edit_series_modal.series_type_list.current_selection(), + &SeriesType::Anime, + ); + assert_eq!( + edit_series_modal.quality_profile_list.items, + vec!["Any".to_owned(), "HD - 1080p".to_owned()] + ); + assert_str_eq!( + edit_series_modal.quality_profile_list.current_selection(), + "HD - 1080p" + ); + assert_eq!( + edit_series_modal.language_profile_list.items, + vec!["Any".to_owned(), "English".to_owned()] + ); + assert_str_eq!( + edit_series_modal.language_profile_list.current_selection(), + "English" + ); + assert_str_eq!(edit_series_modal.path.text, "/nfs/seriess/Test"); + assert_str_eq!(edit_series_modal.tags.text, "usenet, test"); + assert_eq!(edit_series_modal.monitored, Some(true)); + assert_eq!(edit_series_modal.use_season_folders, Some(true)); + } } diff --git a/src/models/servarr_data/sonarr/sonarr_data.rs b/src/models/servarr_data/sonarr/sonarr_data.rs index 76fbd78..1b34d4a 100644 --- a/src/models/servarr_data/sonarr/sonarr_data.rs +++ b/src/models/servarr_data/sonarr/sonarr_data.rs @@ -14,7 +14,7 @@ use crate::models::{ HorizontallyScrollableText, Route, ScrollableText, }; -use super::modals::{AddSeriesModal, SeasonDetailsModal}; +use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal}; #[cfg(test)] #[path = "sonarr_data_tests.rs"] @@ -31,6 +31,7 @@ pub struct SonarrData { pub disk_space_vec: Vec, pub edit_indexer_modal: Option, pub edit_root_folder: Option, + pub edit_series_modal: Option, pub history: StatefulTable, pub indexers: StatefulTable, pub indexer_settings: Option, @@ -72,6 +73,7 @@ impl Default for SonarrData { disk_space_vec: Vec::new(), edit_indexer_modal: None, edit_root_folder: None, + edit_series_modal: None, history: StatefulTable::default(), indexers: StatefulTable::default(), indexer_settings: None, diff --git a/src/models/servarr_data/sonarr/sonarr_data_tests.rs b/src/models/servarr_data/sonarr/sonarr_data_tests.rs index 30c7ee6..de9b25a 100644 --- a/src/models/servarr_data/sonarr/sonarr_data_tests.rs +++ b/src/models/servarr_data/sonarr/sonarr_data_tests.rs @@ -58,6 +58,7 @@ mod tests { assert!(sonarr_data.disk_space_vec.is_empty()); assert!(sonarr_data.edit_indexer_modal.is_none()); assert!(sonarr_data.edit_root_folder.is_none()); + assert!(sonarr_data.edit_series_modal.is_none()); assert!(sonarr_data.history.is_empty()); assert!(sonarr_data.indexers.is_empty()); assert!(sonarr_data.indexer_settings.is_none()); diff --git a/src/models/sonarr_models.rs b/src/models/sonarr_models.rs index 8b01276..d98d9a7 100644 --- a/src/models/sonarr_models.rs +++ b/src/models/sonarr_models.rs @@ -128,6 +128,20 @@ pub struct DownloadsResponse { pub records: Vec, } +#[derive(Default, Clone, Serialize, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct EditSeriesParams { + pub series_id: i64, + pub monitored: Option, + pub use_season_folders: Option, + pub quality_profile_id: Option, + pub language_profile_id: Option, + pub series_type: Option, + pub root_folder_path: Option, + pub tags: Option>, + pub clear_tags: bool, +} + #[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Episode {