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;