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
This commit is contained in:
@@ -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::<Vec<String>>()
|
||||
.join(" | ")
|
||||
}
|
||||
|
||||
+2
-2
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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, "<ctrl-{}>", c),
|
||||
Key::Char(c) => write!(f, "<{c}>"),
|
||||
Key::Ctrl(c) => write!(f, "<ctrl-{c}>"),
|
||||
Key::Up => write!(f, "<↑>"),
|
||||
Key::Down => write!(f, "<↓>"),
|
||||
Key::Left => write!(f, "<←>"),
|
||||
@@ -41,7 +41,7 @@ impl Display for Key {
|
||||
Key::End => write!(f, "<end>"),
|
||||
Key::Tab => write!(f, "<tab>"),
|
||||
Key::Delete => write!(f, "<del>"),
|
||||
_ => write!(f, "<{:?}>", self),
|
||||
_ => write!(f, "<{self:?}>"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -464,18 +464,11 @@ fn sort_releases_by_selected_field(
|
||||
) -> Vec<Release> {
|
||||
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
|
||||
|
||||
@@ -1112,10 +1112,10 @@ mod tests {
|
||||
fn release_vec() -> Vec<Release> {
|
||||
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,
|
||||
|
||||
@@ -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()
|
||||
}]);
|
||||
|
||||
+1
-2
@@ -132,8 +132,7 @@ fn panic_hook(info: &PanicInfo<'_>) {
|
||||
io::stdout(),
|
||||
LeaveAlternateScreen,
|
||||
Print(format!(
|
||||
"thread '<unnamed>' panicked at '{}', {}\n\r{}",
|
||||
msg, location, stacktrace
|
||||
"thread '<unnamed>' panicked at '{msg}', {location}\n\r{stacktrace}"
|
||||
)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
+12
-1
@@ -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<i64, D::Error>
|
||||
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:?}"
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -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<ValueError> = 1i64.into_deserializer();
|
||||
|
||||
assert_eq!(from_i64(deserializer), Ok(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_i64_error() {
|
||||
let deserializer: F64Deserializer<ValueError> = 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<TabRoute> {
|
||||
vec![
|
||||
TabRoute {
|
||||
|
||||
+113
-124
@@ -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<u64>,
|
||||
pub tags: Vec<i64>,
|
||||
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<String>,
|
||||
#[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<String>,
|
||||
@@ -68,28 +66,27 @@ pub struct Collection {
|
||||
pub monitored: bool,
|
||||
pub overview: Option<String>,
|
||||
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<Vec<CollectionMovie>>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
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<HorizontallyScrollableText>,
|
||||
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<DownloadRecord>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
pub implementation: Option<String>,
|
||||
pub implementation_name: Option<String>,
|
||||
@@ -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<Vec<String>>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
pub label: Option<String>,
|
||||
pub value: Option<Value>,
|
||||
@@ -185,35 +180,33 @@ pub struct IndexerField {
|
||||
pub select_options: Option<Vec<IndexerSelectOption>>,
|
||||
}
|
||||
|
||||
#[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<String>,
|
||||
#[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<String>,
|
||||
pub audio_languages: Option<String>,
|
||||
#[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<String>,
|
||||
#[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<String>,
|
||||
pub tags: Vec<Number>,
|
||||
@@ -358,11 +351,11 @@ pub struct Movie {
|
||||
pub collection: Option<Collection>,
|
||||
}
|
||||
|
||||
#[derive(Default, Derivative, Serialize, Debug)]
|
||||
#[derive(Default, Serialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MovieCommandBody {
|
||||
pub name: String,
|
||||
pub movie_ids: Vec<u64>,
|
||||
pub movie_ids: Vec<i64>,
|
||||
}
|
||||
|
||||
#[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<Rating>,
|
||||
}
|
||||
|
||||
#[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<Vec<String>>,
|
||||
pub seeders: Option<Number>,
|
||||
@@ -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<Vec<UnmappedFolder>>,
|
||||
}
|
||||
|
||||
@@ -495,22 +486,20 @@ pub struct SystemStatus {
|
||||
pub start_time: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[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<Utc>,
|
||||
pub last_duration: String,
|
||||
pub next_execution: DateTime<Utc>,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
|
||||
@@ -38,8 +38,8 @@ pub struct RadarrData<'a> {
|
||||
pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>,
|
||||
pub downloads: StatefulTable<DownloadRecord>,
|
||||
pub indexers: StatefulTable<Indexer>,
|
||||
pub quality_profile_map: BiMap<u64, String>,
|
||||
pub tags_map: BiMap<u64, String>,
|
||||
pub quality_profile_map: BiMap<i64, String>,
|
||||
pub tags_map: BiMap<i64, String>,
|
||||
pub collections: StatefulTable<Collection>,
|
||||
pub collection_movies: StatefulTable<CollectionMovie>,
|
||||
pub logs: StatefulList<HorizontallyScrollableText>,
|
||||
|
||||
+9
-19
@@ -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),
|
||||
|
||||
+83
-185
@@ -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::<Value, Tag>(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<QualityProfile>>(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<Tag>>(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<String>| {
|
||||
vec
|
||||
.iter()
|
||||
.map(|change| format!(" * {}", change))
|
||||
.map(|change| format!(" * {change}"))
|
||||
.collect::<Vec<String>>()
|
||||
.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<u64> {
|
||||
async fn extract_and_add_tag_ids_vec(&mut self, edit_tags: String) -> Vec<i64> {
|
||||
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();
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -545,7 +545,7 @@ pub fn draw_checkbox_with_label<B: Backend>(
|
||||
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<B: Backend>(
|
||||
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<B: Backend>(
|
||||
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<B: Backend>(
|
||||
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());
|
||||
|
||||
@@ -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<B: Backend>(
|
||||
.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<B: Backend>(
|
||||
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<B: Backend>(
|
||||
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(", ")),
|
||||
|
||||
@@ -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<B: Backend>(
|
||||
.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;
|
||||
|
||||
@@ -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<B: Backend>(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(),
|
||||
),
|
||||
|
||||
@@ -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<B: Backend>(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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<B: Backend>(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())
|
||||
},
|
||||
|
||||
@@ -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<B: Backend>(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<B: Backend>(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<B: Backend>(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<B: Backend>(
|
||||
.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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<B: Backend>(
|
||||
.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;
|
||||
|
||||
@@ -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<B: Backend>(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<B: Backend>(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<B: Backend>(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),
|
||||
|
||||
@@ -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<B: Backend>(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<B: Backend>(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<B: Backend>(
|
||||
.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::<Vec<Line<'_>>>();
|
||||
lines_vec.append(&mut rejections_spans);
|
||||
|
||||
|
||||
+7
-11
@@ -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<B: Backend>(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<B: Backend>(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<B: Backend>(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<B: Backend>(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]);
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<B: Backend>(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()
|
||||
|
||||
@@ -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<B: Backend>(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<B: Backend>(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
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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<B: Backend>(f: &mut Frame<'_, B>, area: Rect, offset: usize, string: &str) {
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user