From b16a58deaee6b484e7e21bab54985b8ee1cccb60 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Thu, 7 Sep 2023 17:20:38 -0600 Subject: [PATCH] Updated Ratatui, created custom deserialization logic for i64s to make life easier, and used string interpolation where possible to reduce the lines needed to write log messages or create formatted text --- Cargo.toml | 6 +- Makefile | 2 +- rust-toolchain.toml | 2 + src/app/context_clues.rs | 2 +- src/app/mod.rs | 4 +- src/event/key.rs | 6 +- src/event/key_tests.rs | 2 +- .../collections/collection_details_handler.rs | 3 +- .../collection_details_handler_tests.rs | 2 +- .../collections/collections_handler_tests.rs | 2 +- .../library/add_movie_handler.rs | 3 +- .../library/movie_details_handler.rs | 11 +- .../library/movie_details_handler_tests.rs | 12 +- .../radarr_handler_test_utils.rs | 4 +- src/main.rs | 3 +- src/models/mod.rs | 13 +- src/models/model_tests.rs | 22 ++ src/models/radarr_models.rs | 237 ++++++++-------- src/models/servarr_data/radarr/modals.rs | 6 +- .../servarr_data/radarr/modals_tests.rs | 8 +- src/models/servarr_data/radarr/radarr_data.rs | 4 +- src/network/mod.rs | 28 +- src/network/radarr_network.rs | 268 ++++++------------ src/network/radarr_network_tests.rs | 164 +++++------ src/ui/mod.rs | 8 +- .../collections/collection_details_ui.rs | 14 +- .../collections/edit_collection_ui.rs | 4 +- src/ui/radarr_ui/collections/mod.rs | 4 +- src/ui/radarr_ui/downloads/mod.rs | 8 +- .../radarr_ui/indexers/indexer_settings_ui.rs | 2 +- src/ui/radarr_ui/indexers/mod.rs | 4 +- src/ui/radarr_ui/library/add_movie_ui.rs | 14 +- src/ui/radarr_ui/library/delete_movie_ui.rs | 2 +- src/ui/radarr_ui/library/edit_movie_ui.rs | 4 +- src/ui/radarr_ui/library/mod.rs | 16 +- src/ui/radarr_ui/library/movie_details_ui.rs | 12 +- src/ui/radarr_ui/mod.rs | 18 +- src/ui/radarr_ui/radarr_ui_utils.rs | 12 +- src/ui/radarr_ui/root_folders/mod.rs | 6 +- src/ui/radarr_ui/system/mod.rs | 10 +- src/ui/radarr_ui/system/system_details_ui.rs | 2 +- src/ui/utils.rs | 4 +- src/utils.rs | 4 +- 43 files changed, 426 insertions(+), 536 deletions(-) create mode 100644 rust-toolchain.toml diff --git a/Cargo.toml b/Cargo.toml index 546c38d..d6d294f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ backtrace = "0.3.67" bimap = "0.6.3" chrono = { version = "0.4", features = ["serde"] } confy = { version = "0.5.1", default_features = false, features = ["yaml_conf"] } -crossterm = "0.26.1" +crossterm = "0.27.0" derivative = "2.2.0" human-panic = "1.1.3" indoc = "2.0.0" @@ -32,14 +32,14 @@ strum = {version = "0.25.0", features = ["derive"] } strum_macros = "0.25.0" tokio = { version = "1.29.0", features = ["full"] } tokio-util = "0.7.8" -tui = { version = "0.22.0", package = "ratatui", features = ["all-widgets"] } +tui = { version = "0.23.0", package = "ratatui", features = ["all-widgets"] } urlencoding = "2.1.2" [dev-dependencies] cargo-husky = { version = "1.5.0", default_features = false, features = ["user-hooks"] } mockito = "1.0.0" pretty_assertions = "1.3.0" -rstest = "0.17.0" +rstest = "0.18.2" [[bin]] bench = false diff --git a/Makefile b/Makefile index 97ced64..12d3594 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ run: @CARGO_INCREMENTAL=1 cargo fmt && make lint && cargo run lint: - @find . | grep '\.\/src\/.*\.rs$$' | xargs touch && cargo clippy --all-targets --workspace +` @find . | grep '\.\/src\/.*\.rs$$' | xargs touch && CARGO_INCREMENTAL=0 cargo clippy --all-targets --workspace lint-fix: @cargo fix diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..b7eadd6 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.72.0" \ No newline at end of file diff --git a/src/app/context_clues.rs b/src/app/context_clues.rs index 1bd8182..6725eaf 100644 --- a/src/app/context_clues.rs +++ b/src/app/context_clues.rs @@ -9,7 +9,7 @@ pub(in crate::app) type ContextClue = (KeyBinding, &'static str); pub fn build_context_clue_string(context_clues: &[(KeyBinding, &str)]) -> String { context_clues .iter() - .map(|(key_binding, desc)| format!("{} {}", key_binding.key, desc)) + .map(|(key_binding, desc)| format!("{} {desc}", key_binding.key)) .collect::>() .join(" | ") } diff --git a/src/app/mod.rs b/src/app/mod.rs index b2bfa45..0cba1c5 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -54,13 +54,13 @@ impl<'a> App<'a> { } pub async fn dispatch_network_event(&mut self, action: NetworkEvent) { - debug!("Dispatching network event: {:?}", action); + debug!("Dispatching network event: {action:?}"); self.is_loading = true; if let Some(network_tx) = &self.network_tx { if let Err(e) = network_tx.send(action).await { self.is_loading = false; - error!("Failed to send event. {:?}", e); + error!("Failed to send event. {e:?}"); self.handle_error(anyhow!(e)); } } diff --git a/src/event/key.rs b/src/event/key.rs index be68858..a217268 100644 --- a/src/event/key.rs +++ b/src/event/key.rs @@ -28,8 +28,8 @@ pub enum Key { impl Display for Key { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match *self { - Key::Char(c) => write!(f, "<{}>", c), - Key::Ctrl(c) => write!(f, "", c), + Key::Char(c) => write!(f, "<{c}>"), + Key::Ctrl(c) => write!(f, ""), Key::Up => write!(f, "<↑>"), Key::Down => write!(f, "<↓>"), Key::Left => write!(f, "<←>"), @@ -41,7 +41,7 @@ impl Display for Key { Key::End => write!(f, ""), Key::Tab => write!(f, ""), Key::Delete => write!(f, ""), - _ => write!(f, "<{:?}>", self), + _ => write!(f, "<{self:?}>"), } } } diff --git a/src/event/key_tests.rs b/src/event/key_tests.rs index 2bc28ff..5429aad 100644 --- a/src/event/key_tests.rs +++ b/src/event/key_tests.rs @@ -21,7 +21,7 @@ mod tests { #[case(Key::Char('q'), "q")] #[case(Key::Ctrl('q'), "ctrl-q")] fn test_key_formatter(#[case] key: Key, #[case] expected_str: &str) { - assert_str_eq!(format!("{}", key), format!("<{}>", expected_str)); + assert_str_eq!(format!("{key}"), format!("<{expected_str}>")); } #[test] diff --git a/src/handlers/radarr_handlers/collections/collection_details_handler.rs b/src/handlers/radarr_handlers/collections/collection_details_handler.rs index 44c67b5..8d4fa81 100644 --- a/src/handlers/radarr_handlers/collections/collection_details_handler.rs +++ b/src/handlers/radarr_handlers/collections/collection_details_handler.rs @@ -83,8 +83,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan .radarr_data .collection_movies .current_selection() - .tmdb_id - .clone(); + .tmdb_id; if self .app diff --git a/src/handlers/radarr_handlers/collections/collection_details_handler_tests.rs b/src/handlers/radarr_handlers/collections/collection_details_handler_tests.rs index 6b9e647..e91789b 100644 --- a/src/handlers/radarr_handlers/collections/collection_details_handler_tests.rs +++ b/src/handlers/radarr_handlers/collections/collection_details_handler_tests.rs @@ -225,7 +225,7 @@ mod tests { mod test_handle_key_char { use bimap::BiMap; use pretty_assertions::{assert_eq, assert_str_eq}; - use serde_json::Number; + use strum::IntoEnumIterator; use crate::models::radarr_models::{Collection, MinimumAvailability}; diff --git a/src/handlers/radarr_handlers/collections/collections_handler_tests.rs b/src/handlers/radarr_handlers/collections/collections_handler_tests.rs index 7249278..b2b6ed7 100644 --- a/src/handlers/radarr_handlers/collections/collections_handler_tests.rs +++ b/src/handlers/radarr_handlers/collections/collections_handler_tests.rs @@ -796,7 +796,7 @@ mod tests { mod test_handle_key_char { use bimap::BiMap; use pretty_assertions::{assert_eq, assert_str_eq}; - use serde_json::Number; + use strum::IntoEnumIterator; use crate::models::radarr_models::MinimumAvailability; diff --git a/src/handlers/radarr_handlers/library/add_movie_handler.rs b/src/handlers/radarr_handlers/library/add_movie_handler.rs index 9c40784..b9f4b92 100644 --- a/src/handlers/radarr_handlers/library/add_movie_handler.rs +++ b/src/handlers/radarr_handlers/library/add_movie_handler.rs @@ -336,8 +336,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a, .as_ref() .unwrap() .current_selection() - .tmdb_id - .clone(); + .tmdb_id; if self .app diff --git a/src/handlers/radarr_handlers/library/movie_details_handler.rs b/src/handlers/radarr_handlers/library/movie_details_handler.rs index d15a213..2397f95 100644 --- a/src/handlers/radarr_handlers/library/movie_details_handler.rs +++ b/src/handlers/radarr_handlers/library/movie_details_handler.rs @@ -464,18 +464,11 @@ fn sort_releases_by_selected_field( ) -> Vec { let cmp_fn: fn(&Release, &Release) -> Ordering = match field { ReleaseField::Source => |release_a, release_b| release_a.protocol.cmp(&release_b.protocol), - ReleaseField::Age => |release_a, release_b| release_a.age.as_u64().cmp(&release_b.age.as_u64()), + ReleaseField::Age => |release_a, release_b| release_a.age.cmp(&release_b.age), ReleaseField::Rejected => |release_a, release_b| release_a.rejected.cmp(&release_b.rejected), ReleaseField::Title => |release_a, release_b| release_a.title.text.cmp(&release_b.title.text), ReleaseField::Indexer => |release_a, release_b| release_a.indexer.cmp(&release_b.indexer), - ReleaseField::Size => |release_a, release_b| { - release_a - .size - .as_u64() - .as_ref() - .unwrap() - .cmp(release_b.size.as_u64().as_ref().unwrap()) - }, + ReleaseField::Size => |release_a, release_b| release_a.size.cmp(&release_b.size), ReleaseField::Peers => |release_a, release_b| { let default_number = Number::from(i64::MAX); let seeder_a = release_a diff --git a/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs b/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs index 75f7b0d..b1e701b 100644 --- a/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs +++ b/src/handlers/radarr_handlers/library/movie_details_handler_tests.rs @@ -1112,10 +1112,10 @@ mod tests { fn release_vec() -> Vec { let release_a = Release { protocol: "Protocol A".to_owned(), - age: Number::from(1), + age: 1, title: HorizontallyScrollableText::from("Title A"), indexer: "Indexer A".to_owned(), - size: Number::from(1), + size: 1, rejected: true, seeders: Some(Number::from(1)), languages: Some(vec![Language { @@ -1130,10 +1130,10 @@ mod tests { }; let release_b = Release { protocol: "Protocol B".to_owned(), - age: Number::from(2), + age: 2, title: HorizontallyScrollableText::from("Title B"), indexer: "Indexer B".to_owned(), - size: Number::from(2), + size: 2, rejected: false, seeders: Some(Number::from(2)), languages: Some(vec![Language { @@ -1148,10 +1148,10 @@ mod tests { }; let release_c = Release { protocol: "Protocol C".to_owned(), - age: Number::from(3), + age: 3, title: HorizontallyScrollableText::from("Title C"), indexer: "Indexer C".to_owned(), - size: Number::from(3), + size: 3, rejected: false, seeders: None, languages: None, diff --git a/src/handlers/radarr_handlers/radarr_handler_test_utils.rs b/src/handlers/radarr_handlers/radarr_handler_test_utils.rs index 7418b9a..a71a3ae 100644 --- a/src/handlers/radarr_handlers/radarr_handler_test_utils.rs +++ b/src/handlers/radarr_handlers/radarr_handler_test_utils.rs @@ -17,7 +17,7 @@ mod utils { radarr_data.movies.set_items(vec![Movie { path: "/nfs/movies/Test".to_owned().into(), monitored: true, - quality_profile_id: Number::from(2222), + quality_profile_id: 2222, minimum_availability: MinimumAvailability::Released, tags: vec![Number::from(1)], ..Movie::default() @@ -133,7 +133,7 @@ mod utils { root_folder_path: "/nfs/movies/Test".to_owned().into(), monitored: true, search_on_add: true, - quality_profile_id: Number::from(2222), + quality_profile_id: 2222, minimum_availability: MinimumAvailability::Released, ..Collection::default() }]); diff --git a/src/main.rs b/src/main.rs index c6bf5cb..8b09cb4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,8 +132,7 @@ fn panic_hook(info: &PanicInfo<'_>) { io::stdout(), LeaveAlternateScreen, Print(format!( - "thread '' panicked at '{}', {}\n\r{}", - msg, location, stacktrace + "thread '' panicked at '{msg}', {location}\n\r{stacktrace}" )), ) .unwrap(); diff --git a/src/models/mod.rs b/src/models/mod.rs index d2ff36c..a195a8b 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -2,7 +2,8 @@ use std::cell::RefCell; use std::fmt::{Debug, Display, Formatter}; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; -use serde::Deserialize; +use serde::{de, Deserialize, Deserializer}; +use serde_json::Number; use tui::widgets::{ListState, TableState}; pub mod radarr_models; @@ -409,3 +410,13 @@ where self.index = index; } } + +pub fn from_i64<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let num: Number = Deserialize::deserialize(deserializer)?; + num.as_i64().ok_or(de::Error::custom(format!( + "Unable to convert Number to i64: {num:?}" + ))) +} diff --git a/src/models/model_tests.rs b/src/models/model_tests.rs index 4305d7a..fc3e6ac 100644 --- a/src/models/model_tests.rs +++ b/src/models/model_tests.rs @@ -3,7 +3,12 @@ mod tests { use std::cell::RefCell; use pretty_assertions::{assert_eq, assert_str_eq}; + use serde::de::value::Error as ValueError; + use serde::de::value::F64Deserializer; + use serde::de::value::I64Deserializer; + use serde::de::IntoDeserializer; + use crate::models::from_i64; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::{ BlockSelectionState, HorizontallyScrollableText, Scrollable, ScrollableText, StatefulList, @@ -715,6 +720,23 @@ mod tests { assert_eq!(block_selection_state.get_active_block(), &blocks[0]); } + #[test] + fn test_from_i64() { + let deserializer: I64Deserializer = 1i64.into_deserializer(); + + assert_eq!(from_i64(deserializer), Ok(1)); + } + + #[test] + fn test_from_i64_error() { + let deserializer: F64Deserializer = 1f64.into_deserializer(); + + assert_eq!( + from_i64(deserializer).unwrap_err().to_string(), + "Unable to convert Number to i64: Number(1.0)" + ); + } + fn create_test_tab_routes() -> Vec { vec![ TabRoute { diff --git a/src/models/radarr_models.rs b/src/models/radarr_models.rs index 94acd47..d0d128e 100644 --- a/src/models/radarr_models.rs +++ b/src/models/radarr_models.rs @@ -15,31 +15,30 @@ mod radarr_models_tests; #[derive(Default, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct AddMovieBody { - pub tmdb_id: u64, + pub tmdb_id: i64, pub title: String, pub root_folder_path: String, - pub quality_profile_id: u64, + pub quality_profile_id: i64, pub minimum_availability: String, pub monitored: bool, - pub tags: Vec, + pub tags: Vec, pub add_options: AddOptions, } -#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)] -#[derivative(Default)] +#[derive(Derivative, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct AddMovieSearchResult { - #[derivative(Default(value = "Number::from(0)"))] - pub tmdb_id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub tmdb_id: i64, pub title: HorizontallyScrollableText, pub original_language: Language, pub status: String, pub overview: String, pub genres: Vec, - #[derivative(Default(value = "Number::from(0)"))] - pub year: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub runtime: Number, + #[serde(deserialize_with = "super::from_i64")] + pub year: i64, + #[serde(deserialize_with = "super::from_i64")] + pub runtime: i64, pub ratings: RatingsList, } @@ -55,12 +54,11 @@ pub struct AddRootFolderBody { pub path: String, } -#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)] -#[derivative(Default)] +#[derive(Deserialize, Derivative, Default, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Collection { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, #[serde(default)] pub title: HorizontallyScrollableText, pub root_folder_path: Option, @@ -68,28 +66,27 @@ pub struct Collection { pub monitored: bool, pub overview: Option, pub minimum_availability: MinimumAvailability, - #[derivative(Default(value = "Number::from(0)"))] - pub quality_profile_id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub quality_profile_id: i64, pub movies: Option>, } -#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)] -#[derivative(Default)] +#[derive(Derivative, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct CollectionMovie { pub title: HorizontallyScrollableText, pub overview: String, - #[derivative(Default(value = "Number::from(0)"))] - pub year: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub runtime: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub tmdb_id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub year: i64, + #[serde(deserialize_with = "super::from_i64")] + pub runtime: i64, + #[serde(deserialize_with = "super::from_i64")] + pub tmdb_id: i64, pub genres: Vec, pub ratings: RatingsList, } -#[derive(Default, Derivative, Serialize, Debug)] +#[derive(Default, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct CommandBody { pub name: String, @@ -117,42 +114,41 @@ pub enum CreditType { #[derive(Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct DiskSpace { - pub free_space: Number, - pub total_space: Number, + #[serde(deserialize_with = "super::from_i64")] + pub free_space: i64, + #[serde(deserialize_with = "super::from_i64")] + pub total_space: i64, } -#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)] -#[derivative(Default)] +#[derive(Derivative, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct DownloadRecord { pub title: String, pub status: String, - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub movie_id: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub size: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub sizeleft: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, + #[serde(deserialize_with = "super::from_i64")] + pub movie_id: i64, + #[serde(deserialize_with = "super::from_i64")] + pub size: i64, + #[serde(deserialize_with = "super::from_i64")] + pub sizeleft: i64, pub output_path: Option, pub indexer: String, pub download_client: String, } -#[derive(Derivative, Deserialize, Debug)] -#[derivative(Default)] +#[derive(Default, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct DownloadsResponse { pub records: Vec, } -#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Indexer { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, pub name: Option, pub implementation: Option, pub implementation_name: Option, @@ -164,19 +160,18 @@ pub struct Indexer { pub enable_automatic_search: bool, pub enable_interactive_search: bool, pub protocol: String, - #[derivative(Default(value = "Number::from(0)"))] - pub priority: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub download_client_id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub priority: i64, + #[serde(deserialize_with = "super::from_i64")] + pub download_client_id: i64, pub tags: Option>, } -#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct IndexerField { - #[derivative(Default(value = "Number::from(0)"))] - pub order: Number, + #[serde(deserialize_with = "super::from_i64")] + pub order: i64, pub name: Option, pub label: Option, pub value: Option, @@ -185,35 +180,33 @@ pub struct IndexerField { pub select_options: Option>, } -#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct IndexerSelectOption { - #[derivative(Default(value = "Number::from(0)"))] - pub value: Number, + #[serde(deserialize_with = "super::from_i64")] + pub value: i64, pub name: Option, - #[derivative(Default(value = "Number::from(0)"))] - pub order: Number, + #[serde(deserialize_with = "super::from_i64")] + pub order: i64, } -#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct IndexerSettings { pub allow_hardcoded_subs: bool, - #[derivative(Default(value = "Number::from(0)"))] - pub availability_delay: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub maximum_size: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub minimum_age: Number, + #[serde(deserialize_with = "super::from_i64")] + pub availability_delay: i64, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, + #[serde(deserialize_with = "super::from_i64")] + pub maximum_size: i64, + #[serde(deserialize_with = "super::from_i64")] + pub minimum_age: i64, pub prefer_indexer_flags: bool, - #[derivative(Default(value = "Number::from(0)"))] - pub retention: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub rss_sync_interval: Number, + #[serde(deserialize_with = "super::from_i64")] + pub retention: i64, + #[serde(deserialize_with = "super::from_i64")] + pub rss_sync_interval: i64, pub whitelisted_hardcoded_subs: String, } @@ -243,18 +236,18 @@ pub struct LogResponse { #[derivative(Default)] #[serde(rename_all = "camelCase")] pub struct MediaInfo { - #[derivative(Default(value = "Number::from(0)"))] - pub audio_bitrate: Number, + #[serde(deserialize_with = "super::from_i64")] + pub audio_bitrate: i64, #[derivative(Default(value = "Number::from(0)"))] pub audio_channels: Number, pub audio_codec: Option, pub audio_languages: Option, - #[derivative(Default(value = "Number::from(0)"))] - pub audio_stream_count: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub video_bit_depth: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub video_bitrate: Number, + #[serde(deserialize_with = "super::from_i64")] + pub audio_stream_count: i64, + #[serde(deserialize_with = "super::from_i64")] + pub video_bit_depth: i64, + #[serde(deserialize_with = "super::from_i64")] + pub video_bitrate: i64, pub video_codec: String, #[derivative(Default(value = "Number::from(0)"))] pub video_fps: Number, @@ -281,7 +274,7 @@ impl Display for MinimumAvailability { MinimumAvailability::InCinemas => "inCinemas", MinimumAvailability::Released => "released", }; - write!(f, "{}", minimum_availability) + write!(f, "{minimum_availability}") } } @@ -311,7 +304,7 @@ impl Display for Monitor { Monitor::MovieAndCollection => "movieAndCollection", Monitor::None => "none", }; - write!(f, "{}", monitor) + write!(f, "{monitor}") } } @@ -329,27 +322,27 @@ impl Monitor { #[derivative(Default)] #[serde(rename_all = "camelCase")] pub struct Movie { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, pub title: HorizontallyScrollableText, pub original_language: Language, - #[derivative(Default(value = "Number::from(0)"))] - pub size_on_disk: Number, + #[serde(deserialize_with = "super::from_i64")] + pub size_on_disk: i64, pub status: String, pub overview: String, pub path: String, pub studio: String, pub genres: Vec, - #[derivative(Default(value = "Number::from(0)"))] - pub year: Number, + #[serde(deserialize_with = "super::from_i64")] + pub year: i64, pub monitored: bool, pub has_file: bool, - #[derivative(Default(value = "Number::from(0)"))] - pub runtime: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub tmdb_id: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub quality_profile_id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub runtime: i64, + #[serde(deserialize_with = "super::from_i64")] + pub tmdb_id: i64, + #[serde(deserialize_with = "super::from_i64")] + pub quality_profile_id: i64, pub minimum_availability: MinimumAvailability, pub certification: Option, pub tags: Vec, @@ -358,11 +351,11 @@ pub struct Movie { pub collection: Option, } -#[derive(Default, Derivative, Serialize, Debug)] +#[derive(Default, Serialize, Debug)] #[serde(rename_all = "camelCase")] pub struct MovieCommandBody { pub name: String, - pub movie_ids: Vec, + pub movie_ids: Vec, } #[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)] @@ -390,11 +383,10 @@ pub struct Quality { pub name: String, } -#[derive(Derivative, Deserialize, Debug)] -#[derivative(Default)] +#[derive(Default, Deserialize, Debug)] pub struct QualityProfile { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, pub name: String, } @@ -431,20 +423,20 @@ pub struct RatingsList { pub rotten_tomatoes: Option, } -#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)] -#[derivative(Default)] +#[derive(Deserialize, Default, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase")] +#[serde(default)] pub struct Release { pub guid: String, pub protocol: String, - #[derivative(Default(value = "Number::from(0)"))] - pub age: Number, + #[serde(deserialize_with = "super::from_i64")] + pub age: i64, pub title: HorizontallyScrollableText, pub indexer: String, - #[derivative(Default(value = "Number::from(0)"))] - pub indexer_id: Number, - #[derivative(Default(value = "Number::from(0)"))] - pub size: Number, + #[serde(deserialize_with = "super::from_i64")] + pub indexer_id: i64, + #[serde(deserialize_with = "super::from_i64")] + pub size: i64, pub rejected: bool, pub rejections: Option>, pub seeders: Option, @@ -457,8 +449,8 @@ pub struct Release { #[serde(rename_all = "camelCase")] pub struct ReleaseDownloadBody { pub guid: String, - pub indexer_id: u64, - pub movie_id: u64, + pub indexer_id: i64, + pub movie_id: i64, } #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, Display)] @@ -475,16 +467,15 @@ pub enum ReleaseField { Quality, } -#[derive(Derivative, Deserialize, Debug, Clone, Eq, PartialEq)] -#[derivative(Default)] +#[derive(Default, Deserialize, Debug, Clone, Eq, PartialEq)] #[serde(rename_all = "camelCase")] pub struct RootFolder { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, pub path: String, pub accessible: bool, - #[derivative(Default(value = "Number::from(0)"))] - pub free_space: Number, + #[serde(deserialize_with = "super::from_i64")] + pub free_space: i64, pub unmapped_folders: Option>, } @@ -495,22 +486,20 @@ pub struct SystemStatus { pub start_time: DateTime, } -#[derive(Derivative, Deserialize, Debug)] -#[derivative(Default)] +#[derive(Default, Deserialize, Debug)] pub struct Tag { - #[derivative(Default(value = "Number::from(0)"))] - pub id: Number, + #[serde(deserialize_with = "super::from_i64")] + pub id: i64, pub label: String, } -#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)] -#[derivative(Default)] +#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(rename_all = "camelCase")] pub struct Task { pub name: String, pub task_name: String, - #[derivative(Default(value = "Number::from(0)"))] - pub interval: Number, + #[serde(deserialize_with = "super::from_i64")] + pub interval: i64, pub last_execution: DateTime, pub last_duration: String, pub next_execution: DateTime, diff --git a/src/models/servarr_data/radarr/modals.rs b/src/models/servarr_data/radarr/modals.rs index fc9fa26..6169b21 100644 --- a/src/models/servarr_data/radarr/modals.rs +++ b/src/models/servarr_data/radarr/modals.rs @@ -58,7 +58,7 @@ impl From<&RadarrData<'_>> for EditMovieModal { .map(|tag_id| { radarr_data .tags_map - .get_by_left(&tag_id.as_u64().unwrap()) + .get_by_left(&tag_id.as_i64().unwrap()) .unwrap() .clone() }) @@ -89,7 +89,7 @@ impl From<&RadarrData<'_>> for EditMovieModal { .set_items(quality_profile_names); let quality_profile_name = radarr_data .quality_profile_map - .get_by_left(&quality_profile_id.as_u64().unwrap()) + .get_by_left(quality_profile_id) .unwrap(); let quality_profile_index = edit_movie_modal .quality_profile_list @@ -193,7 +193,7 @@ impl From<&RadarrData<'_>> for EditCollectionModal { let quality_profile_name = radarr_data .quality_profile_map - .get_by_left(&quality_profile_id.as_u64().unwrap()) + .get_by_left(quality_profile_id) .unwrap(); let quality_profile_index = edit_collection_modal .quality_profile_list diff --git a/src/models/servarr_data/radarr/modals_tests.rs b/src/models/servarr_data/radarr/modals_tests.rs index 60f6c05..a02ec8e 100644 --- a/src/models/servarr_data/radarr/modals_tests.rs +++ b/src/models/servarr_data/radarr/modals_tests.rs @@ -27,7 +27,7 @@ mod test { let movie = Movie { path: "/nfs/movies/Test".to_owned(), monitored: true, - quality_profile_id: Number::from(2222), + quality_profile_id: 2222, minimum_availability: MinimumAvailability::Released, tags: vec![Number::from(1), Number::from(2)], ..Movie::default() @@ -69,10 +69,10 @@ mod test { #[test] fn test_add_movie_modal_from_radarr_data() { let root_folder = RootFolder { - id: Number::from(1), + id: 1, path: "/nfs".to_owned(), accessible: true, - free_space: Number::from(219902325555200u64), + free_space: 219902325555200, unmapped_folders: None, }; let mut radarr_data = RadarrData { @@ -120,7 +120,7 @@ mod test { root_folder_path: Some("/nfs/movies/Test".to_owned()), monitored: true, search_on_add: true, - quality_profile_id: Number::from(2222), + quality_profile_id: 2222, minimum_availability: MinimumAvailability::Released, ..Collection::default() }; diff --git a/src/models/servarr_data/radarr/radarr_data.rs b/src/models/servarr_data/radarr/radarr_data.rs index 5bc73c1..b724421 100644 --- a/src/models/servarr_data/radarr/radarr_data.rs +++ b/src/models/servarr_data/radarr/radarr_data.rs @@ -38,8 +38,8 @@ pub struct RadarrData<'a> { pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>, pub downloads: StatefulTable, pub indexers: StatefulTable, - pub quality_profile_map: BiMap, - pub tags_map: BiMap, + pub quality_profile_map: BiMap, + pub tags_map: BiMap, pub collections: StatefulTable, pub collection_movies: StatefulTable, pub logs: StatefulList, diff --git a/src/network/mod.rs b/src/network/mod.rs index 77d84a8..d98fdd3 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -63,7 +63,7 @@ impl<'a, 'b> Network<'a, 'b> { let request_uri = request_props.uri.clone(); select! { _ = self.cancellation_token.cancelled() => { - warn!("Received Cancel request. Cancelling request to: {}", request_uri); + warn!("Received Cancel request. Cancelling request to: {request_uri}"); let mut app = self.app.lock().await; self.cancellation_token = app.reset_cancellation_token(); app.is_loading = false; @@ -80,12 +80,12 @@ impl<'a, 'b> Network<'a, 'b> { app_update_fn(value, app); } Err(e) => { - error!("Failed to parse response! {:?}", e); + error!("Failed to parse response! {e:?}"); self .app .lock() .await - .handle_error(anyhow!("Failed to parse response! {:?}", e)); + .handle_error(anyhow!("Failed to parse response! {e:?}")); } } } @@ -99,24 +99,17 @@ impl<'a, 'b> Network<'a, 'b> { .replace_all(&response_body.replace('\n', " "), " ") .to_string(); - error!( - "Request failed. Received {} response code with body: {}", - status, response_body - ); - self.app.lock().await.handle_error(anyhow!( - "Request failed. Received {} response code with body: {}", - status, - error_body - )); + error!("Request failed. Received {status} response code with body: {response_body}"); + self.app.lock().await.handle_error(anyhow!("Request failed. Received {status} response code with body: {error_body}")); } } Err(e) => { - error!("Failed to send request. {:?}", e); + error!("Failed to send request. {e:?}"); self .app .lock() .await - .handle_error(anyhow!("Failed to send request. {} ", e)); + .handle_error(anyhow!("Failed to send request. {e} ")); } } } @@ -133,11 +126,8 @@ impl<'a, 'b> Network<'a, 'b> { body, api_token, } = request_props; - debug!("Creating RequestBuilder for resource: {:?}", uri); - debug!( - "Sending {:?} request to {} with body {:?}", - method, uri, body - ); + debug!("Creating RequestBuilder for resource: {uri:?}"); + debug!("Sending {method:?} request to {uri} with body {body:?}"); match method { RequestMethod::Get => self.client.get(uri).header("X-Api-Key", api_token), diff --git a/src/network/radarr_network.rs b/src/network/radarr_network.rs index e9848fd..cc14cbd 100644 --- a/src/network/radarr_network.rs +++ b/src/network/radarr_network.rs @@ -4,7 +4,7 @@ use std::fmt::Debug; use indoc::formatdoc; use log::{debug, info, warn}; use serde::Serialize; -use serde_json::{json, Number, Value}; +use serde_json::{json, Value}; use urlencoding::encode; use crate::app::RadarrConfig; @@ -226,7 +226,7 @@ impl<'a, 'b> Network<'a, 'b> { app.data.radarr_data.add_movie_modal = None; AddMovieBody { - tmdb_id: tmdb_id.as_u64().unwrap(), + tmdb_id, title, root_folder_path: path, minimum_availability, @@ -240,7 +240,7 @@ impl<'a, 'b> Network<'a, 'b> { } }; - debug!("Add movie body: {:?}", body); + debug!("Add movie body: {body:?}"); let request_props = self .radarr_request_props_from( @@ -273,7 +273,7 @@ impl<'a, 'b> Network<'a, 'b> { AddRootFolderBody { path } }; - debug!("Add root folder body: {:?}", body); + debug!("Add root folder body: {body:?}"); let request_props = self .radarr_request_props_from( @@ -301,11 +301,7 @@ impl<'a, 'b> Network<'a, 'b> { self .handle_request::(request_props, |tag, mut app| { - app - .data - .radarr_data - .tags_map - .insert(tag.id.as_u64().unwrap(), tag.label); + app.data.radarr_data.tags_map.insert(tag.id, tag.label); }) .await; } @@ -319,18 +315,13 @@ impl<'a, 'b> Network<'a, 'b> { .radarr_data .downloads .current_selection() - .id - .as_u64() - .unwrap(); + .id; - info!( - "Deleting Radarr download for download with id: {}", - download_id - ); + info!("Deleting Radarr download for download with id: {download_id}"); let request_props = self .radarr_request_props_from( - format!("{}/{}", RadarrEvent::DeleteDownload.resource(), download_id).as_str(), + format!("{}/{download_id}", RadarrEvent::DeleteDownload.resource()).as_str(), RequestMethod::Delete, None::<()>, ) @@ -350,18 +341,13 @@ impl<'a, 'b> Network<'a, 'b> { .radarr_data .indexers .current_selection() - .id - .as_u64() - .unwrap(); + .id; - info!( - "Deleting Radarr indexer for indexer with id: {}", - indexer_id - ); + info!("Deleting Radarr indexer for indexer with id: {indexer_id}"); let request_props = self .radarr_request_props_from( - format!("{}/{}", RadarrEvent::DeleteIndexer.resource(), indexer_id).as_str(), + format!("{}/{indexer_id}", RadarrEvent::DeleteIndexer.resource()).as_str(), RequestMethod::Delete, None::<()>, ) @@ -377,19 +363,13 @@ impl<'a, 'b> Network<'a, 'b> { let delete_files = self.app.lock().await.data.radarr_data.delete_movie_files; let add_import_exclusion = self.app.lock().await.data.radarr_data.add_list_exclusion; - info!( - "Deleting Radarr movie with tmdb_id {} and Radarr id: {} with deleteFiles={} and addImportExclusion={}", - tmdb_id, movie_id, delete_files, add_import_exclusion - ); + info!("Deleting Radarr movie with tmdb_id {tmdb_id} and Radarr id: {movie_id} with deleteFiles={delete_files} and addImportExclusion={add_import_exclusion}"); let request_props = self .radarr_request_props_from( format!( - "{}/{}?deleteFiles={}&addImportExclusion={}", - RadarrEvent::DeleteMovie.resource(), - movie_id, - delete_files, - add_import_exclusion + "{}/{movie_id}?deleteFiles={delete_files}&addImportExclusion={add_import_exclusion}", + RadarrEvent::DeleteMovie.resource() ) .as_str(), RequestMethod::Delete, @@ -419,21 +399,15 @@ impl<'a, 'b> Network<'a, 'b> { .radarr_data .root_folders .current_selection() - .id - .as_u64() - .unwrap(); + .id; - info!( - "Deleting Radarr root folder for folder with id: {}", - root_folder_id - ); + info!("Deleting Radarr root folder for folder with id: {root_folder_id}"); let request_props = self .radarr_request_props_from( format!( - "{}/{}", - RadarrEvent::DeleteRootFolder.resource(), - root_folder_id + "{}/{root_folder_id}", + RadarrEvent::DeleteRootFolder.resource() ) .as_str(), RequestMethod::Delete, @@ -464,10 +438,10 @@ impl<'a, 'b> Network<'a, 'b> { .movie_releases .current_selection(); - (guid.clone(), title.clone(), indexer_id.as_u64().unwrap()) + (guid.clone(), title.clone(), *indexer_id) }; - info!("Downloading release: {}", title); + info!("Downloading release: {title}"); let download_release_body = ReleaseDownloadBody { guid, @@ -495,12 +469,7 @@ impl<'a, 'b> Network<'a, 'b> { let collection_id = self.extract_collection_id().await; let request_props = self .radarr_request_props_from( - format!( - "{}/{}", - RadarrEvent::GetCollections.resource(), - collection_id - ) - .as_str(), + format!("{}/{collection_id}", RadarrEvent::GetCollections.resource()).as_str(), RequestMethod::Get, None::<()>, ) @@ -557,16 +526,11 @@ impl<'a, 'b> Network<'a, 'b> { detailed_collection_body }; - debug!("Edit collection body: {:?}", body); + debug!("Edit collection body: {body:?}"); let request_props = self .radarr_request_props_from( - format!( - "{}/{}", - RadarrEvent::EditCollection.resource(), - collection_id - ) - .as_str(), + format!("{}/{collection_id}", RadarrEvent::EditCollection.resource()).as_str(), RequestMethod::Put, Some(body), ) @@ -585,7 +549,7 @@ impl<'a, 'b> Network<'a, 'b> { let request_props = self .radarr_request_props_from( - format!("{}/{}", RadarrEvent::GetMovieDetails.resource(), movie_id).as_str(), + format!("{}/{movie_id}", RadarrEvent::GetMovieDetails.resource()).as_str(), RequestMethod::Get, None::<()>, ) @@ -648,11 +612,11 @@ impl<'a, 'b> Network<'a, 'b> { detailed_movie_body }; - debug!("Edit movie body: {:?}", body); + debug!("Edit movie body: {body:?}"); let request_props = self .radarr_request_props_from( - format!("{}/{}", RadarrEvent::EditMovie.resource(), movie_id).as_str(), + format!("{}/{movie_id}", RadarrEvent::EditMovie.resource()).as_str(), RequestMethod::Put, Some(body), ) @@ -858,7 +822,7 @@ impl<'a, 'b> Network<'a, 'b> { let request_props = self .radarr_request_props_from( - format!("{}/{}", RadarrEvent::GetMovieDetails.resource(), movie_id).as_str(), + format!("{}/{movie_id}", RadarrEvent::GetMovieDetails.resource()).as_str(), RequestMethod::Get, None::<()>, ) @@ -884,43 +848,43 @@ impl<'a, 'b> Network<'a, 'b> { collection, .. } = movie_response; - let (hours, minutes) = convert_runtime(runtime.as_u64().unwrap()); - let size = convert_to_gb(size_on_disk.as_u64().unwrap()); + let (hours, minutes) = convert_runtime(runtime); + let size = convert_to_gb(size_on_disk); let quality_profile = app .data .radarr_data .quality_profile_map - .get_by_left(&quality_profile_id.as_u64().unwrap()) + .get_by_left(&quality_profile_id) .unwrap() .to_owned(); let imdb_rating = if let Some(rating) = ratings.imdb { if let Some(value) = rating.value.as_f64() { format!("{:.1}", value) } else { - "".to_owned() + String::new() } } else { - "".to_owned() + String::new() }; let tmdb_rating = if let Some(rating) = ratings.tmdb { if let Some(value) = rating.value.as_f64() { format!("{}%", (value * 10f64).ceil()) } else { - "".to_owned() + String::new() } } else { - "".to_owned() + String::new() }; let rotten_tomatoes_rating = if let Some(rating) = ratings.rotten_tomatoes { if let Some(value) = rating.value.as_u64() { format!("{}%", value) } else { - "".to_owned() + String::new() } } else { - "".to_owned() + String::new() }; let status = get_movie_status(has_file, &app.data.radarr_data.downloads.items, id); @@ -928,36 +892,23 @@ impl<'a, 'b> Network<'a, 'b> { let mut movie_details_modal = MovieDetailsModal { movie_details: ScrollableText::with_string(formatdoc!( - "Title: {} - Year: {} - Runtime: {}h {}m + "Title: {title} + Year: {year} + Runtime: {hours}h {minutes}m Rating: {} Collection: {} - Status: {} - Description: {} - TMDB: {} - IMDB: {} - Rotten Tomatoes: {} - Quality Profile: {} - Size: {:.2} GB - Path: {} - Studio: {} + Status: {status} + Description: {overview} + TMDB: {tmdb_rating} + IMDB: {imdb_rating} + Rotten Tomatoes: {rotten_tomatoes_rating} + Quality Profile: {quality_profile} + Size: {size:.2} GB + Path: {path} + Studio: {studio} Genres: {}", - title, - year, - hours, - minutes, certification.unwrap_or_default(), collection.title, - status, - overview, - tmdb_rating, - imdb_rating, - rotten_tomatoes_rating, - quality_profile, - size, - path, - studio, genres.join(", ") )), ..MovieDetailsModal::default() @@ -967,11 +918,10 @@ impl<'a, 'b> Network<'a, 'b> { movie_details_modal.file_details = formatdoc!( "Relative Path: {} Absolute Path: {} - Size: {:.2} GB + Size: {size:.2} GB Date Added: {}", file.relative_path, file.path, - size, file.date_added ); @@ -982,11 +932,11 @@ impl<'a, 'b> Network<'a, 'b> { Codec: {} Languages: {} Stream Count: {}", - media_info.audio_bitrate.as_u64().unwrap(), + media_info.audio_bitrate, media_info.audio_channels.as_f64().unwrap(), media_info.audio_codec.unwrap_or_default(), media_info.audio_languages.unwrap_or_default(), - media_info.audio_stream_count.as_u64().unwrap() + media_info.audio_stream_count ); movie_details_modal.video_details = formatdoc!( @@ -997,8 +947,8 @@ impl<'a, 'b> Network<'a, 'b> { Resolution: {} Scan Type: {} Runtime: {}", - media_info.video_bit_depth.as_u64().unwrap(), - media_info.video_bitrate.as_u64().unwrap(), + media_info.video_bit_depth, + media_info.video_bitrate, media_info.video_codec, media_info.video_fps.as_f64().unwrap(), media_info.resolution, @@ -1073,7 +1023,7 @@ impl<'a, 'b> Network<'a, 'b> { .handle_request::<(), Vec>(request_props, |quality_profiles, mut app| { app.data.radarr_data.quality_profile_map = quality_profiles .into_iter() - .map(|profile| (profile.id.as_u64().unwrap(), profile.name)) + .map(|profile| (profile.id, profile.name)) .collect(); }) .await; @@ -1103,19 +1053,11 @@ impl<'a, 'b> Network<'a, 'b> { async fn get_releases(&mut self) { let (movie_id, tmdb_id) = self.extract_movie_id().await; - info!( - "Fetching releases for movie with TMDB id {} and with Radarr id: {}", - tmdb_id, movie_id - ); + info!("Fetching releases for movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}"); let request_props = self .radarr_request_props_from( - format!( - "{}?movieId={}", - RadarrEvent::GetReleases.resource(), - movie_id - ) - .as_str(), + format!("{}?movieId={movie_id}", RadarrEvent::GetReleases.resource()).as_str(), RequestMethod::Get, None::<()>, ) @@ -1181,7 +1123,7 @@ impl<'a, 'b> Network<'a, 'b> { .handle_request::<(), Vec>(request_props, |tags_vec, mut app| { app.data.radarr_data.tags_map = tags_vec .into_iter() - .map(|tag| (tag.id.as_u64().unwrap(), tag.label)) + .map(|tag| (tag.id, tag.label)) .collect(); }) .await; @@ -1241,56 +1183,46 @@ impl<'a, 'b> Network<'a, 'b> { let vec_to_bullet_points = |vec: Vec| { vec .iter() - .map(|change| format!(" * {}", change)) + .map(|change| format!(" * {change}")) .collect::>() .join("\n") }; let mut update_info = formatdoc!( - "{} - {} {} + "{} - {} {install_status} {}", update.version, update.release_date, - install_status, "-".repeat(200) ); if let Some(new_changes) = update.changes.new { let changes = vec_to_bullet_points(new_changes); update_info = formatdoc!( - "{} + "{update_info} New: - {}", - update_info, - changes + {changes}" ) } if let Some(fixes) = update.changes.fixed { let fixes = vec_to_bullet_points(fixes); update_info = formatdoc!( - "{} + "{update_info} Fixed: - {}", - update_info, - fixes + {fixes}" ); } update_info }) - .reduce(|version_1, version_2| format!("{}\n\n\n{}", version_1, version_2)) + .reduce(|version_1, version_2| format!("{version_1}\n\n\n{version_2}")) .unwrap(); app.data.radarr_data.updates = ScrollableText::with_string(formatdoc!( - "{} + "The latest version of Radarr is {latest_installed} installed - {}", - format!( - "The latest version of Radarr is {} installed", - latest_installed - ), - updates + {updates}" )); }) .await; @@ -1343,10 +1275,9 @@ impl<'a, 'b> Network<'a, 'b> { } Err(e) => { warn!( - "Encountered a race condition: {}\n \ + "Encountered a race condition: {e}\n \ This is most likely caused by the user trying to navigate between modals rapidly. \ - Ignoring search request.", - e + Ignoring search request." ); } } @@ -1364,7 +1295,7 @@ impl<'a, 'b> Network<'a, 'b> { .task_name .clone(); - info!("Starting Radarr task: {}", task_name); + info!("Starting Radarr task: {task_name}"); let body = CommandBody { name: task_name }; @@ -1383,10 +1314,7 @@ impl<'a, 'b> Network<'a, 'b> { async fn trigger_automatic_search(&mut self) { let (movie_id, tmdb_id) = self.extract_movie_id().await; - info!( - "Searching indexers for movie with TMDB id {} and with Radarr id: {}", - tmdb_id, movie_id - ); + info!("Searching indexers for movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}"); let body = MovieCommandBody { name: "MoviesSearch".to_owned(), movie_ids: vec![movie_id], @@ -1427,10 +1355,7 @@ impl<'a, 'b> Network<'a, 'b> { async fn update_and_scan(&mut self) { let (movie_id, tmdb_id) = self.extract_movie_id().await; - info!( - "Updating and scanning movie with TMDB id {} and with Radarr id: {}", - tmdb_id, movie_id - ); + info!("Updating and scanning movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}"); let body = MovieCommandBody { name: "RefreshMovie".to_owned(), movie_ids: vec![movie_id], @@ -1501,7 +1426,7 @@ impl<'a, 'b> Network<'a, 'b> { .unwrap() .clone(); - debug!("Indexer settings body: {:?}", body); + debug!("Indexer settings body: {body:?}"); let request_props = self .radarr_request_props_from( @@ -1530,12 +1455,7 @@ impl<'a, 'b> Network<'a, 'b> { port, api_token, } = &app.config.radarr; - let uri = format!( - "http://{}:{}/api/v3{}", - host, - port.unwrap_or(7878), - resource - ); + let uri = format!("http://{host}:{}/api/v3{resource}", port.unwrap_or(7878)); RequestProps { uri, @@ -1545,7 +1465,7 @@ impl<'a, 'b> Network<'a, 'b> { } } - async fn extract_and_add_tag_ids_vec(&mut self, edit_tags: String) -> Vec { + async fn extract_and_add_tag_ids_vec(&mut self, edit_tags: String) -> Vec { let tags_map = self.app.lock().await.data.radarr_data.tags_map.clone(); let tags = edit_tags.clone(); let missing_tags_vec = edit_tags @@ -1572,7 +1492,7 @@ impl<'a, 'b> Network<'a, 'b> { .collect() } - async fn extract_movie_id(&mut self) -> (u64, u64) { + async fn extract_movie_id(&mut self) -> (i64, i64) { let app = self.app.lock().await; if app.data.radarr_data.filtered_movies.is_some() { ( @@ -1583,9 +1503,7 @@ impl<'a, 'b> Network<'a, 'b> { .as_ref() .unwrap() .current_selection() - .id - .as_u64() - .unwrap(), + .id, app .data .radarr_data @@ -1593,33 +1511,17 @@ impl<'a, 'b> Network<'a, 'b> { .as_ref() .unwrap() .current_selection() - .tmdb_id - .as_u64() - .unwrap(), + .tmdb_id, ) } else { ( - app - .data - .radarr_data - .movies - .current_selection() - .id - .as_u64() - .unwrap(), - app - .data - .radarr_data - .movies - .current_selection() - .tmdb_id - .as_u64() - .unwrap(), + app.data.radarr_data.movies.current_selection().id, + app.data.radarr_data.movies.current_selection().tmdb_id, ) } } - async fn extract_collection_id(&mut self) -> u64 { + async fn extract_collection_id(&mut self) -> i64 { if self .app .lock() @@ -1640,8 +1542,6 @@ impl<'a, 'b> Network<'a, 'b> { .unwrap() .current_selection() .id - .as_u64() - .unwrap() } else { self .app @@ -1652,22 +1552,20 @@ impl<'a, 'b> Network<'a, 'b> { .collections .current_selection() .id - .as_u64() - .unwrap() } } async fn append_movie_id_param(&mut self, resource: &str) -> String { let (movie_id, _) = self.extract_movie_id().await; - format!("{}?movieId={}", resource, movie_id) + format!("{resource}?movieId={movie_id}") } } -fn get_movie_status(has_file: bool, downloads_vec: &[DownloadRecord], movie_id: Number) -> String { +fn get_movie_status(has_file: bool, downloads_vec: &[DownloadRecord], movie_id: i64) -> String { if !has_file { if let Some(download) = downloads_vec .iter() - .find(|&download| download.movie_id.as_u64().unwrap() == movie_id.as_u64().unwrap()) + .find(|&download| download.movie_id == movie_id) { if download.status == "downloading" { return "Downloading".to_owned(); diff --git a/src/network/radarr_network_tests.rs b/src/network/radarr_network_tests.rs index 4f44cbd..7555193 100644 --- a/src/network/radarr_network_tests.rs +++ b/src/network/radarr_network_tests.rs @@ -7,7 +7,7 @@ mod test { use mockito::{Matcher, Mock, Server, ServerGuard}; use pretty_assertions::{assert_eq, assert_str_eq}; use rstest::rstest; - use serde_json::{json, Value}; + use serde_json::{json, Number, Value}; use strum::IntoEnumIterator; use tokio::sync::Mutex; use tokio_util::sync::CancellationToken; @@ -229,12 +229,12 @@ mod test { app_arc.lock().await.data.radarr_data.disk_space_vec, vec![ DiskSpace { - free_space: Number::from(1111), - total_space: Number::from(2222), + free_space: 1111, + total_space: 2222, }, DiskSpace { - free_space: Number::from(3333), - total_space: Number::from(4444), + free_space: 3333, + total_space: 4444, }, ] ); @@ -270,7 +270,7 @@ mod test { let (async_server, app_arc, _server) = mock_radarr_api( RequestMethod::Get, None, - Some(serde_json::from_str(format!("[ {} ]", MOVIE_JSON).as_str()).unwrap()), + Some(serde_json::from_str(format!("[ {MOVIE_JSON} ]").as_str()).unwrap()), RadarrEvent::GetMovies.resource(), ) .await; @@ -463,7 +463,7 @@ mod test { let mut async_server = server .mock( &RequestMethod::Get.to_string().to_uppercase(), - format!("/api/v3{}", resource).as_str(), + format!("/api/v3{resource}").as_str(), ) .match_header("X-Api-Key", "test1234"); async_server = async_server.expect_at_most(0).create_async().await; @@ -1186,7 +1186,7 @@ mod test { async_server.assert_async().await; assert_eq!( app_arc.lock().await.data.radarr_data.quality_profile_map, - BiMap::from_iter([(2222u64, "HD - 1080p".to_owned())]) + BiMap::from_iter([(2222i64, "HD - 1080p".to_owned())]) ); } @@ -1210,7 +1210,7 @@ mod test { async_server.assert_async().await; assert_eq!( app_arc.lock().await.data.radarr_data.tags_map, - BiMap::from_iter([(2222u64, "usenet".to_owned())]) + BiMap::from_iter([(2222i64, "usenet".to_owned())]) ); } @@ -1237,7 +1237,7 @@ mod test { Task { name: "Application Check Update".to_owned(), task_name: "ApplicationCheckUpdate".to_owned(), - interval: Number::from(360), + interval: 360, last_execution: timestamp, next_execution: timestamp, last_duration: "00:00:00.5111547".to_owned(), @@ -1245,7 +1245,7 @@ mod test { Task { name: "Backup".to_owned(), task_name: "Backup".to_owned(), - interval: Number::from(10080), + interval: 10080, last_execution: timestamp, next_execution: timestamp, last_duration: "00:00:00.5111547".to_owned(), @@ -1317,7 +1317,7 @@ mod test { The latest version of Radarr is already installed 4.3.2.1 - 2023-04-15 02:02:53 UTC (Currently Installed) - {} + {line_break} New: * Cool new thing Fixed: @@ -1325,20 +1325,17 @@ mod test { 3.2.1.0 - 2023-04-15 02:02:53 UTC (Previously Installed) - {} + {line_break} New: * Cool new thing (old) * Other cool new thing (old) 2.1.0 - 2023-04-15 02:02:53 UTC - {} + {line_break} Fixed: * Killed bug 1 - * Fixed bug 2", - line_break.clone(), - line_break.clone(), - line_break + * Fixed bug 2" )); let (async_server, app_arc, _server) = mock_radarr_api( RequestMethod::Get, @@ -1569,17 +1566,17 @@ mod test { }; add_movie_modal.root_folder_list.set_items(vec![ RootFolder { - id: Number::from(1), + id: 1, path: "/nfs".to_owned(), accessible: true, - free_space: Number::from(219902325555200u64), + free_space: 219902325555200, unmapped_folders: None, }, RootFolder { - id: Number::from(2), + id: 2, path: "/nfs2".to_owned(), accessible: true, - free_space: Number::from(21990232555520u64), + free_space: 21990232555520, unmapped_folders: None, }, ]); @@ -1655,17 +1652,17 @@ mod test { }; add_movie_modal.root_folder_list.set_items(vec![ RootFolder { - id: Number::from(1), + id: 1, path: "/nfs".to_owned(), accessible: true, - free_space: Number::from(219902325555200u64), + free_space: 219902325555200, unmapped_folders: None, }, RootFolder { - id: Number::from(2), + id: 2, path: "/nfs2".to_owned(), accessible: true, - free_space: Number::from(21990232555520u64), + free_space: 21990232555520, unmapped_folders: None, }, ]); @@ -1685,7 +1682,7 @@ mod test { app.data.radarr_data.tags_map = BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]); let secondary_search_result = AddMovieSearchResult { - tmdb_id: Number::from(5678), + tmdb_id: 5678, ..add_movie_search_result() }; let mut add_searched_movies = StatefulTable::default(); @@ -1715,9 +1712,7 @@ mod test { .as_ref() .unwrap() .current_selection() - .tmdb_id - .as_u64() - .unwrap(), + .tmdb_id, 5678 ); } @@ -2006,8 +2001,8 @@ mod test { .radarr_data .movies .set_items(vec![Movie { - id: Number::from(1), - tmdb_id: Number::from(2), + id: 1, + tmdb_id: 2, ..Movie::default() }]); let mut network = Network::new(&app_arc, CancellationToken::new()); @@ -2020,8 +2015,8 @@ mod test { let app_arc = Arc::new(Mutex::new(App::default())); let mut filtered_movies = StatefulTable::default(); filtered_movies.set_items(vec![Movie { - id: Number::from(1), - tmdb_id: Number::from(2), + id: 1, + tmdb_id: 2, ..Movie::default() }]); app_arc.lock().await.data.radarr_data.filtered_movies = Some(filtered_movies); @@ -2040,7 +2035,7 @@ mod test { .radarr_data .collections .set_items(vec![Collection { - id: Number::from(1), + id: 1, ..Collection::default() }]); let mut network = Network::new(&app_arc, CancellationToken::new()); @@ -2053,7 +2048,7 @@ mod test { let app_arc = Arc::new(Mutex::new(App::default())); let mut filtered_collections = StatefulTable::default(); filtered_collections.set_items(vec![Collection { - id: Number::from(1), + id: 1, ..Collection::default() }]); app_arc.lock().await.data.radarr_data.filtered_collections = Some(filtered_collections); @@ -2072,7 +2067,7 @@ mod test { .radarr_data .movies .set_items(vec![Movie { - id: Number::from(1), + id: 1, ..Movie::default() }]); let mut network = Network::new(&app_arc, CancellationToken::new()); @@ -2127,25 +2122,22 @@ mod test { #[test] fn test_get_movie_status_downloaded() { - assert_str_eq!(get_movie_status(true, &[], Number::from(0)), "Downloaded"); + assert_str_eq!(get_movie_status(true, &[], 0), "Downloaded"); } #[test] fn test_get_movie_status_missing() { let download_record = DownloadRecord { - movie_id: 1.into(), + movie_id: 1, ..DownloadRecord::default() }; assert_str_eq!( - get_movie_status(false, &[download_record.clone()], 0.into()), + get_movie_status(false, &[download_record.clone()], 0), "Missing" ); - assert_str_eq!( - get_movie_status(false, &[download_record], 1.into()), - "Missing" - ); + assert_str_eq!(get_movie_status(false, &[download_record], 1), "Missing"); } #[test] @@ -2154,11 +2146,11 @@ mod test { get_movie_status( false, &[DownloadRecord { - movie_id: 1.into(), + movie_id: 1, status: "downloading".to_owned(), ..DownloadRecord::default() }], - 1.into() + 1 ), "Downloading" ); @@ -2170,11 +2162,11 @@ mod test { get_movie_status( false, &[DownloadRecord { - movie_id: 1.into(), + movie_id: 1, status: "completed".to_owned(), ..DownloadRecord::default() }], - 1.into() + 1 ), "Awaiting Import" ); @@ -2190,7 +2182,7 @@ mod test { let mut async_server = server .mock( &method.to_string().to_uppercase(), - format!("/api/v3{}", resource).as_str(), + format!("/api/v3{resource}").as_str(), ) .match_header("X-Api-Key", "test1234"); @@ -2248,13 +2240,13 @@ mod test { fn media_info() -> MediaInfo { MediaInfo { - audio_bitrate: Number::from(0), + audio_bitrate: 0, audio_channels: Number::from_f64(7.1).unwrap(), audio_codec: Some("AAC".to_owned()), audio_languages: Some("eng".to_owned()), - audio_stream_count: Number::from(1), - video_bit_depth: Number::from(10), - video_bitrate: Number::from(0), + audio_stream_count: 1, + video_bit_depth: 10, + video_bitrate: 0, video_codec: "x265".to_owned(), video_fps: Number::from_f64(23.976).unwrap(), resolution: "1920x804".to_owned(), @@ -2276,9 +2268,9 @@ mod test { CollectionMovie { title: "Test".to_owned().into(), overview: "Collection blah blah blah".to_owned(), - year: Number::from(2023), - runtime: Number::from(120), - tmdb_id: Number::from(1234), + year: 2023, + runtime: 120, + tmdb_id: 1234, genres: genres(), ratings: ratings_list(), } @@ -2286,35 +2278,35 @@ mod test { fn collection() -> Collection { Collection { - id: Number::from(123), + id: 123, title: "Test Collection".to_owned().into(), root_folder_path: Some("/nfs/movies".to_owned()), search_on_add: true, monitored: true, minimum_availability: MinimumAvailability::Released, overview: Some("Collection blah blah blah".to_owned()), - quality_profile_id: Number::from(2222), + quality_profile_id: 2222, movies: Some(vec![collection_movie()]), } } fn movie() -> Movie { Movie { - id: Number::from(1), + id: 1, title: "Test".to_owned().into(), original_language: language(), - size_on_disk: Number::from(3543348019u64), + size_on_disk: 3543348019, status: "Downloaded".to_owned(), overview: "Blah blah blah".to_owned(), path: "/nfs/movies".to_owned(), studio: "21st Century Alex".to_owned(), genres: genres(), - year: Number::from(2023), + year: 2023, monitored: true, has_file: true, - runtime: Number::from(120), - tmdb_id: Number::from(1234), - quality_profile_id: Number::from(2222), + runtime: 120, + tmdb_id: 1234, + quality_profile_id: 2222, minimum_availability: MinimumAvailability::Announced, certification: Some("R".to_owned()), tags: vec![Number::from(1)], @@ -2345,11 +2337,11 @@ mod test { Release { guid: "1234".to_owned(), protocol: "torrent".to_owned(), - age: Number::from(1), + age: 1, title: HorizontallyScrollableText::from("Test Release"), indexer: "kickass torrents".to_owned(), - indexer_id: Number::from(2), - size: Number::from(1234), + indexer_id: 2, + size: 1234, rejected: true, rejections: Some(rejections()), seeders: Some(Number::from(2)), @@ -2361,14 +2353,14 @@ mod test { fn add_movie_search_result() -> AddMovieSearchResult { AddMovieSearchResult { - tmdb_id: Number::from(1234), + tmdb_id: 1234, title: HorizontallyScrollableText::from("Test"), original_language: language(), status: "released".to_owned(), overview: "New movie blah blah blah".to_owned(), genres: genres(), - year: Number::from(2023), - runtime: Number::from(120), + year: 2023, + runtime: 120, ratings: ratings_list(), } } @@ -2387,10 +2379,10 @@ mod test { DownloadRecord { title: "Test Download Title".to_owned(), status: "downloading".to_owned(), - id: Number::from(1), - movie_id: Number::from(1), - size: Number::from(3543348019u64), - sizeleft: Number::from(1771674009u64), + id: 1, + movie_id: 1, + size: 3543348019, + sizeleft: 1771674009, output_path: Some(HorizontallyScrollableText::from("/nfs/movies/Test")), indexer: "kickass torrents".to_owned(), download_client: "transmission".to_owned(), @@ -2405,10 +2397,10 @@ mod test { fn root_folder() -> RootFolder { RootFolder { - id: Number::from(1), + id: 1, path: "/nfs".to_owned(), accessible: true, - free_space: Number::from(219902325555200u64), + free_space: 219902325555200, unmapped_folders: None, } } @@ -2441,17 +2433,17 @@ mod test { supports_rss: true, supports_search: true, protocol: "torrent".to_owned(), - priority: Number::from(25), - download_client_id: Number::from(0), + priority: 25, + download_client_id: 0, name: Some("Test Indexer".to_owned()), implementation_name: Some("Torznab".to_owned()), implementation: Some("Torznab".to_owned()), config_contract: Some("TorznabSettings".to_owned()), tags: Some(vec!["test_tag".to_owned()]), - id: Number::from(1), + id: 1, fields: Some(vec![ IndexerField { - order: Number::from(0), + order: 0, name: Some("valueIsString".to_owned()), label: Some("Value Is String".to_owned()), value: Some(json!("hello")), @@ -2459,19 +2451,19 @@ mod test { select_options: None, }, IndexerField { - order: Number::from(1), + order: 1, name: Some("emptyValueWithSelectOptions".to_owned()), label: Some("Empty Value With Select Options".to_owned()), value: None, field_type: Some("select".to_owned()), select_options: Some(vec![IndexerSelectOption { - value: Number::from(-2), + value: -2, name: Some("Original".to_owned()), - order: Number::from(0), + order: 0, }]), }, IndexerField { - order: Number::from(2), + order: 2, name: Some("valueIsAnArray".to_owned()), label: Some("Value is an array".to_owned()), value: Some(json!([1, 2])), @@ -2484,9 +2476,9 @@ mod test { fn indexer_settings() -> IndexerSettings { IndexerSettings { - rss_sync_interval: Number::from(60), + rss_sync_interval: 60, allow_hardcoded_subs: true, - id: Number::from(1), + id: 1, ..IndexerSettings::default() } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 51b5db3..aebfabf 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -545,7 +545,7 @@ pub fn draw_checkbox_with_label( area, ); - let label_paragraph = Paragraph::new(Text::from(format!("\n{}: ", label))) + let label_paragraph = Paragraph::new(Text::from(format!("\n{label}: "))) .block(borderless_block()) .alignment(Alignment::Right) .style(style_primary()); @@ -605,7 +605,7 @@ pub fn draw_drop_down_menu_button( area, ); - let description_paragraph = Paragraph::new(Text::from(format!("\n{}: ", description))) + let description_paragraph = Paragraph::new(Text::from(format!("\n{description}: "))) .block(borderless_block()) .alignment(Alignment::Right) .style(style_primary()); @@ -676,7 +676,7 @@ fn draw_help_and_get_content_rect( let chunks = vertical_chunks_with_margin(vec![Constraint::Min(0), Constraint::Length(2)], area, 1); - let mut help_test = Text::from(format!(" {}", help_string)); + let mut help_test = Text::from(format!(" {help_string}")); help_test.patch_style(style_help()); let help_paragraph = Paragraph::new(help_test) .block(layout_block_top_border()) @@ -739,7 +739,7 @@ pub fn draw_text_box_with_label( area, ); - let label_paragraph = Paragraph::new(Text::from(format!("\n{}: ", label))) + let label_paragraph = Paragraph::new(Text::from(format!("\n{label}: "))) .block(borderless_block()) .alignment(Alignment::Right) .style(style_primary()); diff --git a/src/ui/radarr_ui/collections/collection_details_ui.rs b/src/ui/radarr_ui/collections/collection_details_ui.rs index 1545d5f..415b1fb 100644 --- a/src/ui/radarr_ui/collections/collection_details_ui.rs +++ b/src/ui/radarr_ui/collections/collection_details_ui.rs @@ -25,7 +25,7 @@ use crate::utils::convert_runtime; #[path = "collection_details_ui_tests.rs"] mod collection_details_ui_tests; -pub(super) struct CollectionDetailsUi {} +pub(super) struct CollectionDetailsUi; impl DrawUi for CollectionDetailsUi { fn accepts(route: Route) -> bool { @@ -90,7 +90,7 @@ pub fn draw_collection_details( .data .radarr_data .quality_profile_map - .get_by_left(&collection_selection.quality_profile_id.as_u64().unwrap()) + .get_by_left(&collection_selection.quality_profile_id) .unwrap() .to_owned(); let current_selection = if app.data.radarr_data.collection_movies.items.is_empty() { @@ -198,7 +198,7 @@ pub fn draw_collection_details( current_selection == *movie, app.tick_count % app.ticks_until_scroll == 0, ); - let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap()); + let (hours, minutes) = convert_runtime(movie.runtime); let imdb_rating = movie .ratings .imdb @@ -218,19 +218,19 @@ pub fn draw_collection_details( let imdb_rating = if imdb_rating == 0.0 { String::new() } else { - format!("{:.1}", imdb_rating) + format!("{imdb_rating:.1}") }; let rotten_tomatoes_rating = if rotten_tomatoes_rating == 0 { String::new() } else { - format!("{}%", rotten_tomatoes_rating) + format!("{rotten_tomatoes_rating}%") }; Row::new(vec![ Cell::from(in_library), Cell::from(movie.title.to_string()), - Cell::from(movie.year.as_u64().unwrap().to_string()), - Cell::from(format!("{}h {}m", hours, minutes)), + Cell::from(movie.year.to_string()), + Cell::from(format!("{hours}h {minutes}m")), Cell::from(imdb_rating), Cell::from(rotten_tomatoes_rating), Cell::from(movie.genres.join(", ")), diff --git a/src/ui/radarr_ui/collections/edit_collection_ui.rs b/src/ui/radarr_ui/collections/edit_collection_ui.rs index ec216be..52ec7d1 100644 --- a/src/ui/radarr_ui/collections/edit_collection_ui.rs +++ b/src/ui/radarr_ui/collections/edit_collection_ui.rs @@ -24,7 +24,7 @@ use crate::ui::{ #[path = "edit_collection_ui_tests.rs"] mod edit_collection_ui_tests; -pub(super) struct EditCollectionUi {} +pub(super) struct EditCollectionUi; impl DrawUi for EditCollectionUi { fn accepts(route: Route) -> bool { @@ -126,7 +126,7 @@ fn draw_edit_collection_confirmation_prompt( .unwrap_or_default(), ) }; - let title = format!("Edit - {}", collection_title); + let title = format!("Edit - {collection_title}"); let yes_no_value = app.data.radarr_data.prompt_confirm; let selected_block = app.data.radarr_data.selected_block.get_active_block(); let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditCollectionConfirmPrompt; diff --git a/src/ui/radarr_ui/collections/mod.rs b/src/ui/radarr_ui/collections/mod.rs index b0075a0..093fcc5 100644 --- a/src/ui/radarr_ui/collections/mod.rs +++ b/src/ui/radarr_ui/collections/mod.rs @@ -23,7 +23,7 @@ mod collection_details_ui; mod collections_ui_tests; mod edit_collection_ui; -pub(super) struct CollectionsUi {} +pub(super) struct CollectionsUi; impl DrawUi for CollectionsUi { fn accepts(route: Route) -> bool { @@ -162,7 +162,7 @@ pub(super) fn draw_collections(f: &mut Frame<'_, B>, app: &mut App<' Cell::from(collection.root_folder_path.clone().unwrap_or_default()), Cell::from( quality_profile_map - .get_by_left(&collection.quality_profile_id.as_u64().unwrap()) + .get_by_left(&collection.quality_profile_id) .unwrap() .to_owned(), ), diff --git a/src/ui/radarr_ui/downloads/mod.rs b/src/ui/radarr_ui/downloads/mod.rs index f1c6d6e..b656eef 100644 --- a/src/ui/radarr_ui/downloads/mod.rs +++ b/src/ui/radarr_ui/downloads/mod.rs @@ -15,7 +15,7 @@ use crate::utils::convert_to_gb; #[path = "downloads_ui_tests.rs"] mod downloads_ui_tests; -pub(super) struct DownloadsUi {} +pub(super) struct DownloadsUi; impl DrawUi for DownloadsUi { fn accepts(route: Route) -> bool { @@ -105,13 +105,13 @@ fn draw_downloads(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rec ); } - let percent = 1f64 - (sizeleft.as_f64().unwrap() / size.as_f64().unwrap()); - let file_size: f64 = convert_to_gb(size.as_u64().unwrap()); + let percent = 1f64 - (*sizeleft as f64 / *size as f64); + let file_size: f64 = convert_to_gb(*size); Row::new(vec![ Cell::from(title.to_owned()), Cell::from(format!("{:.0}%", percent * 100.0)), - Cell::from(format!("{:.2} GB", file_size)), + Cell::from(format!("{file_size:.2} GB")), Cell::from( output_path .as_ref() diff --git a/src/ui/radarr_ui/indexers/indexer_settings_ui.rs b/src/ui/radarr_ui/indexers/indexer_settings_ui.rs index e87a388..334d3c0 100644 --- a/src/ui/radarr_ui/indexers/indexer_settings_ui.rs +++ b/src/ui/radarr_ui/indexers/indexer_settings_ui.rs @@ -21,7 +21,7 @@ use crate::ui::{ #[path = "indexer_settings_ui_tests.rs"] mod indexer_settings_ui_tests; -pub(super) struct IndexerSettingsUi {} +pub(super) struct IndexerSettingsUi; impl DrawUi for IndexerSettingsUi { fn accepts(route: Route) -> bool { diff --git a/src/ui/radarr_ui/indexers/mod.rs b/src/ui/radarr_ui/indexers/mod.rs index 70de7d7..b85dbf4 100644 --- a/src/ui/radarr_ui/indexers/mod.rs +++ b/src/ui/radarr_ui/indexers/mod.rs @@ -18,7 +18,7 @@ mod indexer_settings_ui; #[path = "indexers_ui_tests.rs"] mod indexers_ui_tests; -pub(super) struct IndexersUi {} +pub(super) struct IndexersUi; impl DrawUi for IndexersUi { fn accepts(route: Route) -> bool { @@ -116,7 +116,7 @@ fn draw_indexers(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect Cell::from(rss), Cell::from(automatic_search), Cell::from(interactive_search), - Cell::from(priority.as_u64().unwrap().to_string()), + Cell::from(priority.to_string()), ]) .style(style_primary()) }, diff --git a/src/ui/radarr_ui/library/add_movie_ui.rs b/src/ui/radarr_ui/library/add_movie_ui.rs index e7a9748..95b065e 100644 --- a/src/ui/radarr_ui/library/add_movie_ui.rs +++ b/src/ui/radarr_ui/library/add_movie_ui.rs @@ -29,7 +29,7 @@ use crate::App; #[path = "add_movie_ui_tests.rs"] mod add_movie_ui_tests; -pub(super) struct AddMovieUi {} +pub(super) struct AddMovieUi; impl DrawUi for AddMovieUi { fn accepts(route: Route) -> bool { @@ -201,7 +201,7 @@ fn draw_add_movie_search(f: &mut Frame<'_, B>, app: &mut App<'_>, ar help: None, }, |movie| { - let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap()); + let (hours, minutes) = convert_runtime(movie.runtime); let imdb_rating = movie .ratings .imdb @@ -221,12 +221,12 @@ fn draw_add_movie_search(f: &mut Frame<'_, B>, app: &mut App<'_>, ar let imdb_rating = if imdb_rating == 0.0 { String::new() } else { - format!("{:.1}", imdb_rating) + format!("{imdb_rating:.1}") }; let rotten_tomatoes_rating = if rotten_tomatoes_rating == 0 { String::new() } else { - format!("{}%", rotten_tomatoes_rating) + format!("{rotten_tomatoes_rating}%") }; let in_library = if app .data @@ -250,8 +250,8 @@ fn draw_add_movie_search(f: &mut Frame<'_, B>, app: &mut App<'_>, ar Row::new(vec![ Cell::from(in_library), Cell::from(movie.title.to_string()), - Cell::from(movie.year.as_u64().unwrap().to_string()), - Cell::from(format!("{}h {}m", hours, minutes)), + Cell::from(movie.year.to_string()), + Cell::from(format!("{hours}h {minutes}m")), Cell::from(imdb_rating), Cell::from(rotten_tomatoes_rating), Cell::from(movie.genres.join(", ")), @@ -368,7 +368,7 @@ fn draw_confirmation_prompt( .clone(), ) }; - let title = format!("Add Movie - {}", movie_title); + let title = format!("Add Movie - {movie_title}"); let prompt = movie_overview; let yes_no_value = app.data.radarr_data.prompt_confirm; let selected_block = app.data.radarr_data.selected_block.get_active_block(); diff --git a/src/ui/radarr_ui/library/delete_movie_ui.rs b/src/ui/radarr_ui/library/delete_movie_ui.rs index a5f3dec..3ce00a9 100644 --- a/src/ui/radarr_ui/library/delete_movie_ui.rs +++ b/src/ui/radarr_ui/library/delete_movie_ui.rs @@ -12,7 +12,7 @@ use crate::ui::{draw_prompt_box_with_checkboxes, draw_prompt_popup_over, DrawUi} #[path = "delete_movie_ui_tests.rs"] mod delete_movie_ui_tests; -pub(super) struct DeleteMovieUi {} +pub(super) struct DeleteMovieUi; impl DrawUi for DeleteMovieUi { fn accepts(route: Route) -> bool { diff --git a/src/ui/radarr_ui/library/edit_movie_ui.rs b/src/ui/radarr_ui/library/edit_movie_ui.rs index ca3bb4e..f1473fc 100644 --- a/src/ui/radarr_ui/library/edit_movie_ui.rs +++ b/src/ui/radarr_ui/library/edit_movie_ui.rs @@ -25,7 +25,7 @@ use crate::ui::{ #[path = "edit_movie_ui_tests.rs"] mod edit_movie_ui_tests; -pub(super) struct EditMovieUi {} +pub(super) struct EditMovieUi; impl DrawUi for EditMovieUi { fn accepts(route: Route) -> bool { @@ -118,7 +118,7 @@ fn draw_edit_movie_confirmation_prompt( .clone(), ) }; - let title = format!("Edit - {}", movie_title); + let title = format!("Edit - {movie_title}"); let yes_no_value = app.data.radarr_data.prompt_confirm; let selected_block = app.data.radarr_data.selected_block.get_active_block(); let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditMovieConfirmPrompt; diff --git a/src/ui/radarr_ui/library/mod.rs b/src/ui/radarr_ui/library/mod.rs index ce531b7..22598e1 100644 --- a/src/ui/radarr_ui/library/mod.rs +++ b/src/ui/radarr_ui/library/mod.rs @@ -28,7 +28,7 @@ mod movie_details_ui; #[path = "library_ui_tests.rs"] mod library_ui_tests; -pub(super) struct LibraryUi {} +pub(super) struct LibraryUi; impl DrawUi for LibraryUi { fn accepts(route: Route) -> bool { @@ -168,11 +168,11 @@ pub(super) fn draw_library(f: &mut Frame<'_, B>, app: &mut App<'_>, app.tick_count % app.ticks_until_scroll == 0, ); let monitored = if movie.monitored { "🏷" } else { "" }; - let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap()); - let file_size: f64 = convert_to_gb(movie.size_on_disk.as_u64().unwrap()); - let certification = movie.certification.clone().unwrap_or_else(|| "".to_owned()); + let (hours, minutes) = convert_runtime(movie.runtime); + let file_size: f64 = convert_to_gb(movie.size_on_disk); + let certification = movie.certification.clone().unwrap_or_default(); let quality_profile = quality_profile_map - .get_by_left(&movie.quality_profile_id.as_u64().unwrap()) + .get_by_left(&movie.quality_profile_id) .unwrap() .to_owned(); let tags = movie @@ -180,7 +180,7 @@ pub(super) fn draw_library(f: &mut Frame<'_, B>, app: &mut App<'_>, .iter() .map(|tag_id| { tags_map - .get_by_left(&tag_id.as_u64().unwrap()) + .get_by_left(&tag_id.as_i64().unwrap()) .unwrap() .clone() }) @@ -191,10 +191,10 @@ pub(super) fn draw_library(f: &mut Frame<'_, B>, app: &mut App<'_>, Cell::from(movie.title.to_string()), Cell::from(movie.year.to_string()), Cell::from(movie.studio.to_string()), - Cell::from(format!("{}h {}m", hours, minutes)), + Cell::from(format!("{hours}h {minutes}m")), Cell::from(certification), Cell::from(movie.original_language.name.to_owned()), - Cell::from(format!("{:.2} GB", file_size)), + Cell::from(format!("{file_size:.2} GB")), Cell::from(quality_profile), Cell::from(monitored.to_owned()), Cell::from(tags), diff --git a/src/ui/radarr_ui/library/movie_details_ui.rs b/src/ui/radarr_ui/library/movie_details_ui.rs index 2035ada..df65e0d 100644 --- a/src/ui/radarr_ui/library/movie_details_ui.rs +++ b/src/ui/radarr_ui/library/movie_details_ui.rs @@ -28,7 +28,7 @@ use crate::utils::convert_to_gb; #[path = "movie_details_ui_tests.rs"] mod movie_details_ui_tests; -pub(super) struct MovieDetailsUi {} +pub(super) struct MovieDetailsUi; impl DrawUi for MovieDetailsUi { fn accepts(route: Route) -> bool { @@ -504,21 +504,21 @@ fn draw_movie_releases(f: &mut Frame<'_, B>, app: &mut App<'_>, cont quality, .. } = release; - let age = format!("{} days", age.as_u64().unwrap_or(0)); + let age = format!("{age} days"); title.scroll_left_or_reset( get_width_from_percentage(content_area, 30), current_selection == *release && current_route != ActiveRadarrBlock::ManualSearchConfirmPrompt.into(), app.tick_count % app.ticks_until_scroll == 0, ); - let size = convert_to_gb(size.as_u64().unwrap()); + let size = convert_to_gb(*size); let rejected_str = if *rejected { "⛔" } else { "" }; let peers = if seeders.is_none() || leechers.is_none() { Text::default() } else { let seeders = seeders.clone().unwrap().as_u64().unwrap(); let leechers = leechers.clone().unwrap().as_u64().unwrap(); - let mut text = Text::from(format!("{} / {}", seeders, leechers)); + let mut text = Text::from(format!("{seeders} / {leechers}")); text.patch_style(determine_peer_style(seeders, leechers)); text @@ -537,7 +537,7 @@ fn draw_movie_releases(f: &mut Frame<'_, B>, app: &mut App<'_>, cont Cell::from(rejected_str), Cell::from(title.to_string()), Cell::from(indexer.clone()), - Cell::from(format!("{:.1} GB", size)), + Cell::from(format!("{size:.1} GB")), Cell::from(peers), Cell::from(language), Cell::from(quality), @@ -589,7 +589,7 @@ fn draw_manual_search_confirm_prompt( .clone() .unwrap_or_default() .iter() - .map(|item| Line::from(vec![Span::styled(format!("• {}", item), style_primary())])) + .map(|item| Line::from(vec![Span::styled(format!("• {item}"), style_primary())])) .collect::>>(); lines_vec.append(&mut rejections_spans); diff --git a/src/ui/radarr_ui/mod.rs b/src/ui/radarr_ui/mod.rs index 2ba672d..0de6756 100644 --- a/src/ui/radarr_ui/mod.rs +++ b/src/ui/radarr_ui/mod.rs @@ -41,7 +41,7 @@ mod system; #[path = "radarr_ui_tests.rs"] mod radarr_ui_tests; -pub(super) struct RadarrUi {} +pub(super) struct RadarrUi; impl DrawUi for RadarrUi { fn accepts(route: Route) -> bool { @@ -119,11 +119,7 @@ fn draw_stats_context(f: &mut Frame<'_, B>, app: &App<'_>, area: Rec let seconds = (hour_difference - Duration::minutes(minutes)).num_seconds(); let uptime_paragraph = Paragraph::new(Text::from(format!( - "Uptime: {}d {:0width$}:{:0width$}:{:0width$}", - days, - hours, - minutes, - seconds, + "Uptime: {days}d {hours:0width$}:{minutes:0width$}:{seconds:0width$}", width = 2 ))) .block(borderless_block()) @@ -144,10 +140,10 @@ fn draw_stats_context(f: &mut Frame<'_, B>, app: &App<'_>, area: Rec total_space, } = &disk_space_vec[i]; let title = format!("Disk {}", i + 1); - let ratio = if total_space.as_u64().unwrap() == 0 { + let ratio = if *total_space == 0 { 0f64 } else { - 1f64 - (free_space.as_u64().unwrap() as f64 / total_space.as_u64().unwrap() as f64) + 1f64 - (*free_space as f64 / *total_space as f64) }; let space_gauge = line_gauge_with_label(title.as_str(), ratio); @@ -161,8 +157,8 @@ fn draw_stats_context(f: &mut Frame<'_, B>, app: &App<'_>, area: Rec let RootFolder { path, free_space, .. } = &root_folders.items[i]; - let space: f64 = convert_to_gb(free_space.as_u64().unwrap()); - let root_folder_space = Paragraph::new(format!("{}: {:.2} GB free", path.to_owned(), space)) + let space: f64 = convert_to_gb(*free_space); + let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free")) .block(borderless_block()) .style(style_default()); @@ -193,7 +189,7 @@ fn draw_downloads_context(f: &mut Frame<'_, B>, app: &App<'_>, area: size, .. } = &downloads_vec[i]; - let percent = 1f64 - (sizeleft.as_f64().unwrap() / size.as_f64().unwrap()); + let percent = 1f64 - (*sizeleft as f64 / *size as f64); let download_gauge = line_gauge_with_title(title, percent); f.render_widget(download_gauge, chunks[i]); diff --git a/src/ui/radarr_ui/radarr_ui_utils.rs b/src/ui/radarr_ui/radarr_ui_utils.rs index e3cd4c9..7bc8fa7 100644 --- a/src/ui/radarr_ui/radarr_ui_utils.rs +++ b/src/ui/radarr_ui/radarr_ui_utils.rs @@ -22,23 +22,23 @@ pub(super) fn convert_to_minutes_hours_days(time: i64) -> String { if time == 0 { "now".to_owned() } else if time == 1 { - format!("{} minute", time) + format!("{time} minute") } else { - format!("{} minutes", time) + format!("{time} minutes") } } else if time / 60 < 24 { let hours = time / 60; if hours == 1 { - format!("{} hour", hours) + format!("{hours} hour") } else { - format!("{} hours", hours) + format!("{hours} hours") } } else { let days = time / (60 * 24); if days == 1 { - format!("{} day", days) + format!("{days} day") } else { - format!("{} days", days) + format!("{days} days") } } } diff --git a/src/ui/radarr_ui/root_folders/mod.rs b/src/ui/radarr_ui/root_folders/mod.rs index 765e671..b4eae24 100644 --- a/src/ui/radarr_ui/root_folders/mod.rs +++ b/src/ui/radarr_ui/root_folders/mod.rs @@ -18,7 +18,7 @@ use crate::utils::convert_to_gb; #[path = "root_folders_ui_tests.rs"] mod root_folders_ui_tests; -pub(super) struct RootFoldersUi {} +pub(super) struct RootFoldersUi; impl DrawUi for RootFoldersUi { fn accepts(route: Route) -> bool { @@ -83,11 +83,11 @@ fn draw_root_folders(f: &mut Frame<'_, B>, app: &mut App<'_>, area: .. } = root_folders; - let space: f64 = convert_to_gb(free_space.as_u64().unwrap()); + let space: f64 = convert_to_gb(*free_space); Row::new(vec![ Cell::from(path.to_owned()), - Cell::from(format!("{:.2} GB", space)), + Cell::from(format!("{space:.2} GB")), Cell::from( unmapped_folders .as_ref() diff --git a/src/ui/radarr_ui/system/mod.rs b/src/ui/radarr_ui/system/mod.rs index ca38ce8..4e7a626 100644 --- a/src/ui/radarr_ui/system/mod.rs +++ b/src/ui/radarr_ui/system/mod.rs @@ -51,7 +51,7 @@ pub(super) const TASK_TABLE_CONSTRAINTS: [Constraint; 5] = [ Constraint::Percentage(22), ]; -pub(super) struct SystemUi {} +pub(super) struct SystemUi; impl DrawUi for SystemUi { fn accepts(route: Route) -> bool { @@ -151,7 +151,7 @@ pub(super) fn draw_queued_events(f: &mut Frame<'_, B>, app: &mut App |event| { let queued = convert_to_minutes_hours_days(Utc::now().sub(event.queued).num_minutes()); let queued_string = if queued != "now" { - format!("{} ago", queued) + format!("{queued} ago") } else { queued }; @@ -160,7 +160,7 @@ pub(super) fn draw_queued_events(f: &mut Frame<'_, B>, app: &mut App convert_to_minutes_hours_days(Utc::now().sub(event.started.unwrap()).num_minutes()); if started != "now" { - format!("{} ago", started) + format!("{started} ago") } else { started } @@ -237,14 +237,14 @@ pub(super) struct TaskProps { } pub(super) fn extract_task_props(task: &Task) -> TaskProps { - let interval = convert_to_minutes_hours_days(*task.interval.as_i64().as_ref().unwrap()); + let interval = convert_to_minutes_hours_days(task.interval); let last_duration = &task.last_duration[..8]; let next_execution = convert_to_minutes_hours_days((task.next_execution - Utc::now()).num_minutes()); let last_execution = convert_to_minutes_hours_days((Utc::now() - task.last_execution).num_minutes()); let last_execution_string = if last_execution != "now" { - format!("{} ago", last_execution) + format!("{last_execution} ago") } else { last_execution }; diff --git a/src/ui/radarr_ui/system/system_details_ui.rs b/src/ui/radarr_ui/system/system_details_ui.rs index bff2e31..561fdf6 100644 --- a/src/ui/radarr_ui/system/system_details_ui.rs +++ b/src/ui/radarr_ui/system/system_details_ui.rs @@ -24,7 +24,7 @@ use crate::ui::{ #[path = "system_details_ui_tests.rs"] mod system_details_ui_tests; -pub(super) struct SystemDetailsUi {} +pub(super) struct SystemDetailsUi; impl DrawUi for SystemDetailsUi { fn accepts(route: Route) -> bool { diff --git a/src/ui/utils.rs b/src/ui/utils.rs index 4c72819..410cb51 100644 --- a/src/ui/utils.rs +++ b/src/ui/utils.rs @@ -206,7 +206,7 @@ pub fn style_block_highlight(is_selected: bool) -> Style { } pub fn title_style(title: &str) -> Span<'_> { - Span::styled(format!(" {} ", title), style_bold()) + Span::styled(format!(" {title} "), style_bold()) } pub fn title_block(title: &str) -> Block<'_> { @@ -265,7 +265,7 @@ pub fn line_gauge_with_label(title: &str, ratio: f64) -> LineGauge<'_> { .gauge_style(Style::default().fg(COLOR_CYAN)) .line_set(symbols::line::THICK) .ratio(ratio) - .label(Line::from(format!("{}: {:.0}%", title, ratio * 100.0))) + .label(Line::from(format!("{title}: {:.0}%", ratio * 100.0))) } pub fn show_cursor(f: &mut Frame<'_, B>, area: Rect, offset: usize, string: &str) { diff --git a/src/utils.rs b/src/utils.rs index ccd9adb..8c7a774 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -27,11 +27,11 @@ pub fn init_logging_config() -> log4rs::Config { .unwrap() } -pub fn convert_to_gb(bytes: u64) -> f64 { +pub fn convert_to_gb(bytes: i64) -> f64 { bytes as f64 / 1024f64.powi(3) } -pub fn convert_runtime(runtime: u64) -> (u64, u64) { +pub fn convert_runtime(runtime: i64) -> (i64, i64) { let hours = runtime / 60; let minutes = runtime % 60;