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:
+3
-3
@@ -17,7 +17,7 @@ backtrace = "0.3.67"
|
|||||||
bimap = "0.6.3"
|
bimap = "0.6.3"
|
||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
confy = { version = "0.5.1", default_features = false, features = ["yaml_conf"] }
|
confy = { version = "0.5.1", default_features = false, features = ["yaml_conf"] }
|
||||||
crossterm = "0.26.1"
|
crossterm = "0.27.0"
|
||||||
derivative = "2.2.0"
|
derivative = "2.2.0"
|
||||||
human-panic = "1.1.3"
|
human-panic = "1.1.3"
|
||||||
indoc = "2.0.0"
|
indoc = "2.0.0"
|
||||||
@@ -32,14 +32,14 @@ strum = {version = "0.25.0", features = ["derive"] }
|
|||||||
strum_macros = "0.25.0"
|
strum_macros = "0.25.0"
|
||||||
tokio = { version = "1.29.0", features = ["full"] }
|
tokio = { version = "1.29.0", features = ["full"] }
|
||||||
tokio-util = "0.7.8"
|
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"
|
urlencoding = "2.1.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cargo-husky = { version = "1.5.0", default_features = false, features = ["user-hooks"] }
|
cargo-husky = { version = "1.5.0", default_features = false, features = ["user-hooks"] }
|
||||||
mockito = "1.0.0"
|
mockito = "1.0.0"
|
||||||
pretty_assertions = "1.3.0"
|
pretty_assertions = "1.3.0"
|
||||||
rstest = "0.17.0"
|
rstest = "0.18.2"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
bench = false
|
bench = false
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ run:
|
|||||||
@CARGO_INCREMENTAL=1 cargo fmt && make lint && cargo run
|
@CARGO_INCREMENTAL=1 cargo fmt && make lint && cargo run
|
||||||
|
|
||||||
lint:
|
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:
|
lint-fix:
|
||||||
@cargo fix
|
@cargo fix
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "1.72.0"
|
||||||
@@ -9,7 +9,7 @@ pub(in crate::app) type ContextClue = (KeyBinding, &'static str);
|
|||||||
pub fn build_context_clue_string(context_clues: &[(KeyBinding, &str)]) -> String {
|
pub fn build_context_clue_string(context_clues: &[(KeyBinding, &str)]) -> String {
|
||||||
context_clues
|
context_clues
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key_binding, desc)| format!("{} {}", key_binding.key, desc))
|
.map(|(key_binding, desc)| format!("{} {desc}", key_binding.key))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(" | ")
|
.join(" | ")
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -54,13 +54,13 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn dispatch_network_event(&mut self, action: NetworkEvent) {
|
pub async fn dispatch_network_event(&mut self, action: NetworkEvent) {
|
||||||
debug!("Dispatching network event: {:?}", action);
|
debug!("Dispatching network event: {action:?}");
|
||||||
|
|
||||||
self.is_loading = true;
|
self.is_loading = true;
|
||||||
if let Some(network_tx) = &self.network_tx {
|
if let Some(network_tx) = &self.network_tx {
|
||||||
if let Err(e) = network_tx.send(action).await {
|
if let Err(e) = network_tx.send(action).await {
|
||||||
self.is_loading = false;
|
self.is_loading = false;
|
||||||
error!("Failed to send event. {:?}", e);
|
error!("Failed to send event. {e:?}");
|
||||||
self.handle_error(anyhow!(e));
|
self.handle_error(anyhow!(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -28,8 +28,8 @@ pub enum Key {
|
|||||||
impl Display for Key {
|
impl Display for Key {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Key::Char(c) => write!(f, "<{}>", c),
|
Key::Char(c) => write!(f, "<{c}>"),
|
||||||
Key::Ctrl(c) => write!(f, "<ctrl-{}>", c),
|
Key::Ctrl(c) => write!(f, "<ctrl-{c}>"),
|
||||||
Key::Up => write!(f, "<↑>"),
|
Key::Up => write!(f, "<↑>"),
|
||||||
Key::Down => write!(f, "<↓>"),
|
Key::Down => write!(f, "<↓>"),
|
||||||
Key::Left => write!(f, "<←>"),
|
Key::Left => write!(f, "<←>"),
|
||||||
@@ -41,7 +41,7 @@ impl Display for Key {
|
|||||||
Key::End => write!(f, "<end>"),
|
Key::End => write!(f, "<end>"),
|
||||||
Key::Tab => write!(f, "<tab>"),
|
Key::Tab => write!(f, "<tab>"),
|
||||||
Key::Delete => write!(f, "<del>"),
|
Key::Delete => write!(f, "<del>"),
|
||||||
_ => write!(f, "<{:?}>", self),
|
_ => write!(f, "<{self:?}>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ mod tests {
|
|||||||
#[case(Key::Char('q'), "q")]
|
#[case(Key::Char('q'), "q")]
|
||||||
#[case(Key::Ctrl('q'), "ctrl-q")]
|
#[case(Key::Ctrl('q'), "ctrl-q")]
|
||||||
fn test_key_formatter(#[case] key: Key, #[case] expected_str: &str) {
|
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]
|
#[test]
|
||||||
|
|||||||
@@ -83,8 +83,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.collection_movies
|
.collection_movies
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.tmdb_id
|
.tmdb_id;
|
||||||
.clone();
|
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.app
|
.app
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ mod tests {
|
|||||||
mod test_handle_key_char {
|
mod test_handle_key_char {
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use serde_json::Number;
|
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::models::radarr_models::{Collection, MinimumAvailability};
|
use crate::models::radarr_models::{Collection, MinimumAvailability};
|
||||||
|
|||||||
@@ -796,7 +796,7 @@ mod tests {
|
|||||||
mod test_handle_key_char {
|
mod test_handle_key_char {
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use serde_json::Number;
|
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::models::radarr_models::MinimumAvailability;
|
use crate::models::radarr_models::MinimumAvailability;
|
||||||
|
|||||||
@@ -336,8 +336,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.tmdb_id
|
.tmdb_id;
|
||||||
.clone();
|
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.app
|
.app
|
||||||
|
|||||||
@@ -464,18 +464,11 @@ fn sort_releases_by_selected_field(
|
|||||||
) -> Vec<Release> {
|
) -> Vec<Release> {
|
||||||
let cmp_fn: fn(&Release, &Release) -> Ordering = match field {
|
let cmp_fn: fn(&Release, &Release) -> Ordering = match field {
|
||||||
ReleaseField::Source => |release_a, release_b| release_a.protocol.cmp(&release_b.protocol),
|
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::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::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::Indexer => |release_a, release_b| release_a.indexer.cmp(&release_b.indexer),
|
||||||
ReleaseField::Size => |release_a, release_b| {
|
ReleaseField::Size => |release_a, release_b| release_a.size.cmp(&release_b.size),
|
||||||
release_a
|
|
||||||
.size
|
|
||||||
.as_u64()
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.cmp(release_b.size.as_u64().as_ref().unwrap())
|
|
||||||
},
|
|
||||||
ReleaseField::Peers => |release_a, release_b| {
|
ReleaseField::Peers => |release_a, release_b| {
|
||||||
let default_number = Number::from(i64::MAX);
|
let default_number = Number::from(i64::MAX);
|
||||||
let seeder_a = release_a
|
let seeder_a = release_a
|
||||||
|
|||||||
@@ -1112,10 +1112,10 @@ mod tests {
|
|||||||
fn release_vec() -> Vec<Release> {
|
fn release_vec() -> Vec<Release> {
|
||||||
let release_a = Release {
|
let release_a = Release {
|
||||||
protocol: "Protocol A".to_owned(),
|
protocol: "Protocol A".to_owned(),
|
||||||
age: Number::from(1),
|
age: 1,
|
||||||
title: HorizontallyScrollableText::from("Title A"),
|
title: HorizontallyScrollableText::from("Title A"),
|
||||||
indexer: "Indexer A".to_owned(),
|
indexer: "Indexer A".to_owned(),
|
||||||
size: Number::from(1),
|
size: 1,
|
||||||
rejected: true,
|
rejected: true,
|
||||||
seeders: Some(Number::from(1)),
|
seeders: Some(Number::from(1)),
|
||||||
languages: Some(vec![Language {
|
languages: Some(vec![Language {
|
||||||
@@ -1130,10 +1130,10 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let release_b = Release {
|
let release_b = Release {
|
||||||
protocol: "Protocol B".to_owned(),
|
protocol: "Protocol B".to_owned(),
|
||||||
age: Number::from(2),
|
age: 2,
|
||||||
title: HorizontallyScrollableText::from("Title B"),
|
title: HorizontallyScrollableText::from("Title B"),
|
||||||
indexer: "Indexer B".to_owned(),
|
indexer: "Indexer B".to_owned(),
|
||||||
size: Number::from(2),
|
size: 2,
|
||||||
rejected: false,
|
rejected: false,
|
||||||
seeders: Some(Number::from(2)),
|
seeders: Some(Number::from(2)),
|
||||||
languages: Some(vec![Language {
|
languages: Some(vec![Language {
|
||||||
@@ -1148,10 +1148,10 @@ mod tests {
|
|||||||
};
|
};
|
||||||
let release_c = Release {
|
let release_c = Release {
|
||||||
protocol: "Protocol C".to_owned(),
|
protocol: "Protocol C".to_owned(),
|
||||||
age: Number::from(3),
|
age: 3,
|
||||||
title: HorizontallyScrollableText::from("Title C"),
|
title: HorizontallyScrollableText::from("Title C"),
|
||||||
indexer: "Indexer C".to_owned(),
|
indexer: "Indexer C".to_owned(),
|
||||||
size: Number::from(3),
|
size: 3,
|
||||||
rejected: false,
|
rejected: false,
|
||||||
seeders: None,
|
seeders: None,
|
||||||
languages: None,
|
languages: None,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ mod utils {
|
|||||||
radarr_data.movies.set_items(vec![Movie {
|
radarr_data.movies.set_items(vec![Movie {
|
||||||
path: "/nfs/movies/Test".to_owned().into(),
|
path: "/nfs/movies/Test".to_owned().into(),
|
||||||
monitored: true,
|
monitored: true,
|
||||||
quality_profile_id: Number::from(2222),
|
quality_profile_id: 2222,
|
||||||
minimum_availability: MinimumAvailability::Released,
|
minimum_availability: MinimumAvailability::Released,
|
||||||
tags: vec![Number::from(1)],
|
tags: vec![Number::from(1)],
|
||||||
..Movie::default()
|
..Movie::default()
|
||||||
@@ -133,7 +133,7 @@ mod utils {
|
|||||||
root_folder_path: "/nfs/movies/Test".to_owned().into(),
|
root_folder_path: "/nfs/movies/Test".to_owned().into(),
|
||||||
monitored: true,
|
monitored: true,
|
||||||
search_on_add: true,
|
search_on_add: true,
|
||||||
quality_profile_id: Number::from(2222),
|
quality_profile_id: 2222,
|
||||||
minimum_availability: MinimumAvailability::Released,
|
minimum_availability: MinimumAvailability::Released,
|
||||||
..Collection::default()
|
..Collection::default()
|
||||||
}]);
|
}]);
|
||||||
|
|||||||
+1
-2
@@ -132,8 +132,7 @@ fn panic_hook(info: &PanicInfo<'_>) {
|
|||||||
io::stdout(),
|
io::stdout(),
|
||||||
LeaveAlternateScreen,
|
LeaveAlternateScreen,
|
||||||
Print(format!(
|
Print(format!(
|
||||||
"thread '<unnamed>' panicked at '{}', {}\n\r{}",
|
"thread '<unnamed>' panicked at '{msg}', {location}\n\r{stacktrace}"
|
||||||
msg, location, stacktrace
|
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
+12
-1
@@ -2,7 +2,8 @@ use std::cell::RefCell;
|
|||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
|
|
||||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
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};
|
use tui::widgets::{ListState, TableState};
|
||||||
|
|
||||||
pub mod radarr_models;
|
pub mod radarr_models;
|
||||||
@@ -409,3 +410,13 @@ where
|
|||||||
self.index = index;
|
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 std::cell::RefCell;
|
||||||
|
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
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::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
BlockSelectionState, HorizontallyScrollableText, Scrollable, ScrollableText, StatefulList,
|
BlockSelectionState, HorizontallyScrollableText, Scrollable, ScrollableText, StatefulList,
|
||||||
@@ -715,6 +720,23 @@ mod tests {
|
|||||||
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
|
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> {
|
fn create_test_tab_routes() -> Vec<TabRoute> {
|
||||||
vec![
|
vec![
|
||||||
TabRoute {
|
TabRoute {
|
||||||
|
|||||||
+113
-124
@@ -15,31 +15,30 @@ mod radarr_models_tests;
|
|||||||
#[derive(Default, Serialize, Debug)]
|
#[derive(Default, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AddMovieBody {
|
pub struct AddMovieBody {
|
||||||
pub tmdb_id: u64,
|
pub tmdb_id: i64,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub root_folder_path: String,
|
pub root_folder_path: String,
|
||||||
pub quality_profile_id: u64,
|
pub quality_profile_id: i64,
|
||||||
pub minimum_availability: String,
|
pub minimum_availability: String,
|
||||||
pub monitored: bool,
|
pub monitored: bool,
|
||||||
pub tags: Vec<u64>,
|
pub tags: Vec<i64>,
|
||||||
pub add_options: AddOptions,
|
pub add_options: AddOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Derivative, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AddMovieSearchResult {
|
pub struct AddMovieSearchResult {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub tmdb_id: Number,
|
pub tmdb_id: i64,
|
||||||
pub title: HorizontallyScrollableText,
|
pub title: HorizontallyScrollableText,
|
||||||
pub original_language: Language,
|
pub original_language: Language,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
pub overview: String,
|
pub overview: String,
|
||||||
pub genres: Vec<String>,
|
pub genres: Vec<String>,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub year: Number,
|
pub year: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub runtime: Number,
|
pub runtime: i64,
|
||||||
pub ratings: RatingsList,
|
pub ratings: RatingsList,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,12 +54,11 @@ pub struct AddRootFolderBody {
|
|||||||
pub path: String,
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)]
|
#[derive(Deserialize, Derivative, Default, Clone, Debug, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Collection {
|
pub struct Collection {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub title: HorizontallyScrollableText,
|
pub title: HorizontallyScrollableText,
|
||||||
pub root_folder_path: Option<String>,
|
pub root_folder_path: Option<String>,
|
||||||
@@ -68,28 +66,27 @@ pub struct Collection {
|
|||||||
pub monitored: bool,
|
pub monitored: bool,
|
||||||
pub overview: Option<String>,
|
pub overview: Option<String>,
|
||||||
pub minimum_availability: MinimumAvailability,
|
pub minimum_availability: MinimumAvailability,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub quality_profile_id: Number,
|
pub quality_profile_id: i64,
|
||||||
pub movies: Option<Vec<CollectionMovie>>,
|
pub movies: Option<Vec<CollectionMovie>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Derivative, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CollectionMovie {
|
pub struct CollectionMovie {
|
||||||
pub title: HorizontallyScrollableText,
|
pub title: HorizontallyScrollableText,
|
||||||
pub overview: String,
|
pub overview: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub year: Number,
|
pub year: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub runtime: Number,
|
pub runtime: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub tmdb_id: Number,
|
pub tmdb_id: i64,
|
||||||
pub genres: Vec<String>,
|
pub genres: Vec<String>,
|
||||||
pub ratings: RatingsList,
|
pub ratings: RatingsList,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Derivative, Serialize, Debug)]
|
#[derive(Default, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CommandBody {
|
pub struct CommandBody {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -117,42 +114,41 @@ pub enum CreditType {
|
|||||||
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DiskSpace {
|
pub struct DiskSpace {
|
||||||
pub free_space: Number,
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub total_space: Number,
|
pub free_space: i64,
|
||||||
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
|
pub total_space: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Derivative, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DownloadRecord {
|
pub struct DownloadRecord {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub movie_id: Number,
|
pub movie_id: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub size: Number,
|
pub size: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub sizeleft: Number,
|
pub sizeleft: i64,
|
||||||
pub output_path: Option<HorizontallyScrollableText>,
|
pub output_path: Option<HorizontallyScrollableText>,
|
||||||
pub indexer: String,
|
pub indexer: String,
|
||||||
pub download_client: String,
|
pub download_client: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug)]
|
#[derive(Default, Deserialize, Debug)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DownloadsResponse {
|
pub struct DownloadsResponse {
|
||||||
pub records: Vec<DownloadRecord>,
|
pub records: Vec<DownloadRecord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Indexer {
|
pub struct Indexer {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub implementation: Option<String>,
|
pub implementation: Option<String>,
|
||||||
pub implementation_name: Option<String>,
|
pub implementation_name: Option<String>,
|
||||||
@@ -164,19 +160,18 @@ pub struct Indexer {
|
|||||||
pub enable_automatic_search: bool,
|
pub enable_automatic_search: bool,
|
||||||
pub enable_interactive_search: bool,
|
pub enable_interactive_search: bool,
|
||||||
pub protocol: String,
|
pub protocol: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub priority: Number,
|
pub priority: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub download_client_id: Number,
|
pub download_client_id: i64,
|
||||||
pub tags: Option<Vec<String>>,
|
pub tags: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct IndexerField {
|
pub struct IndexerField {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub order: Number,
|
pub order: i64,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub label: Option<String>,
|
pub label: Option<String>,
|
||||||
pub value: Option<Value>,
|
pub value: Option<Value>,
|
||||||
@@ -185,35 +180,33 @@ pub struct IndexerField {
|
|||||||
pub select_options: Option<Vec<IndexerSelectOption>>,
|
pub select_options: Option<Vec<IndexerSelectOption>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct IndexerSelectOption {
|
pub struct IndexerSelectOption {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub value: Number,
|
pub value: i64,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub order: Number,
|
pub order: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct IndexerSettings {
|
pub struct IndexerSettings {
|
||||||
pub allow_hardcoded_subs: bool,
|
pub allow_hardcoded_subs: bool,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub availability_delay: Number,
|
pub availability_delay: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub maximum_size: Number,
|
pub maximum_size: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub minimum_age: Number,
|
pub minimum_age: i64,
|
||||||
pub prefer_indexer_flags: bool,
|
pub prefer_indexer_flags: bool,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub retention: Number,
|
pub retention: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub rss_sync_interval: Number,
|
pub rss_sync_interval: i64,
|
||||||
pub whitelisted_hardcoded_subs: String,
|
pub whitelisted_hardcoded_subs: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,18 +236,18 @@ pub struct LogResponse {
|
|||||||
#[derivative(Default)]
|
#[derivative(Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MediaInfo {
|
pub struct MediaInfo {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub audio_bitrate: Number,
|
pub audio_bitrate: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub audio_channels: Number,
|
pub audio_channels: Number,
|
||||||
pub audio_codec: Option<String>,
|
pub audio_codec: Option<String>,
|
||||||
pub audio_languages: Option<String>,
|
pub audio_languages: Option<String>,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub audio_stream_count: Number,
|
pub audio_stream_count: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub video_bit_depth: Number,
|
pub video_bit_depth: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub video_bitrate: Number,
|
pub video_bitrate: i64,
|
||||||
pub video_codec: String,
|
pub video_codec: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub video_fps: Number,
|
pub video_fps: Number,
|
||||||
@@ -281,7 +274,7 @@ impl Display for MinimumAvailability {
|
|||||||
MinimumAvailability::InCinemas => "inCinemas",
|
MinimumAvailability::InCinemas => "inCinemas",
|
||||||
MinimumAvailability::Released => "released",
|
MinimumAvailability::Released => "released",
|
||||||
};
|
};
|
||||||
write!(f, "{}", minimum_availability)
|
write!(f, "{minimum_availability}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +304,7 @@ impl Display for Monitor {
|
|||||||
Monitor::MovieAndCollection => "movieAndCollection",
|
Monitor::MovieAndCollection => "movieAndCollection",
|
||||||
Monitor::None => "none",
|
Monitor::None => "none",
|
||||||
};
|
};
|
||||||
write!(f, "{}", monitor)
|
write!(f, "{monitor}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,27 +322,27 @@ impl Monitor {
|
|||||||
#[derivative(Default)]
|
#[derivative(Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Movie {
|
pub struct Movie {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
pub title: HorizontallyScrollableText,
|
pub title: HorizontallyScrollableText,
|
||||||
pub original_language: Language,
|
pub original_language: Language,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub size_on_disk: Number,
|
pub size_on_disk: i64,
|
||||||
pub status: String,
|
pub status: String,
|
||||||
pub overview: String,
|
pub overview: String,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub studio: String,
|
pub studio: String,
|
||||||
pub genres: Vec<String>,
|
pub genres: Vec<String>,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub year: Number,
|
pub year: i64,
|
||||||
pub monitored: bool,
|
pub monitored: bool,
|
||||||
pub has_file: bool,
|
pub has_file: bool,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub runtime: Number,
|
pub runtime: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub tmdb_id: Number,
|
pub tmdb_id: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub quality_profile_id: Number,
|
pub quality_profile_id: i64,
|
||||||
pub minimum_availability: MinimumAvailability,
|
pub minimum_availability: MinimumAvailability,
|
||||||
pub certification: Option<String>,
|
pub certification: Option<String>,
|
||||||
pub tags: Vec<Number>,
|
pub tags: Vec<Number>,
|
||||||
@@ -358,11 +351,11 @@ pub struct Movie {
|
|||||||
pub collection: Option<Collection>,
|
pub collection: Option<Collection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Derivative, Serialize, Debug)]
|
#[derive(Default, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MovieCommandBody {
|
pub struct MovieCommandBody {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub movie_ids: Vec<u64>,
|
pub movie_ids: Vec<i64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
#[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -390,11 +383,10 @@ pub struct Quality {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug)]
|
#[derive(Default, Deserialize, Debug)]
|
||||||
#[derivative(Default)]
|
|
||||||
pub struct QualityProfile {
|
pub struct QualityProfile {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,20 +423,20 @@ pub struct RatingsList {
|
|||||||
pub rotten_tomatoes: Option<Rating>,
|
pub rotten_tomatoes: Option<Rating>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)]
|
#[derive(Deserialize, Default, Clone, Debug, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[serde(default)]
|
||||||
pub struct Release {
|
pub struct Release {
|
||||||
pub guid: String,
|
pub guid: String,
|
||||||
pub protocol: String,
|
pub protocol: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub age: Number,
|
pub age: i64,
|
||||||
pub title: HorizontallyScrollableText,
|
pub title: HorizontallyScrollableText,
|
||||||
pub indexer: String,
|
pub indexer: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub indexer_id: Number,
|
pub indexer_id: i64,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub size: Number,
|
pub size: i64,
|
||||||
pub rejected: bool,
|
pub rejected: bool,
|
||||||
pub rejections: Option<Vec<String>>,
|
pub rejections: Option<Vec<String>>,
|
||||||
pub seeders: Option<Number>,
|
pub seeders: Option<Number>,
|
||||||
@@ -457,8 +449,8 @@ pub struct Release {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ReleaseDownloadBody {
|
pub struct ReleaseDownloadBody {
|
||||||
pub guid: String,
|
pub guid: String,
|
||||||
pub indexer_id: u64,
|
pub indexer_id: i64,
|
||||||
pub movie_id: u64,
|
pub movie_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, Display)]
|
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, Display)]
|
||||||
@@ -475,16 +467,15 @@ pub enum ReleaseField {
|
|||||||
Quality,
|
Quality,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RootFolder {
|
pub struct RootFolder {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
pub accessible: bool,
|
pub accessible: bool,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub free_space: Number,
|
pub free_space: i64,
|
||||||
pub unmapped_folders: Option<Vec<UnmappedFolder>>,
|
pub unmapped_folders: Option<Vec<UnmappedFolder>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,22 +486,20 @@ pub struct SystemStatus {
|
|||||||
pub start_time: DateTime<Utc>,
|
pub start_time: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug)]
|
#[derive(Default, Deserialize, Debug)]
|
||||||
#[derivative(Default)]
|
|
||||||
pub struct Tag {
|
pub struct Tag {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub id: Number,
|
pub id: i64,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub task_name: String,
|
pub task_name: String,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[serde(deserialize_with = "super::from_i64")]
|
||||||
pub interval: Number,
|
pub interval: i64,
|
||||||
pub last_execution: DateTime<Utc>,
|
pub last_execution: DateTime<Utc>,
|
||||||
pub last_duration: String,
|
pub last_duration: String,
|
||||||
pub next_execution: DateTime<Utc>,
|
pub next_execution: DateTime<Utc>,
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ impl From<&RadarrData<'_>> for EditMovieModal {
|
|||||||
.map(|tag_id| {
|
.map(|tag_id| {
|
||||||
radarr_data
|
radarr_data
|
||||||
.tags_map
|
.tags_map
|
||||||
.get_by_left(&tag_id.as_u64().unwrap())
|
.get_by_left(&tag_id.as_i64().unwrap())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone()
|
.clone()
|
||||||
})
|
})
|
||||||
@@ -89,7 +89,7 @@ impl From<&RadarrData<'_>> for EditMovieModal {
|
|||||||
.set_items(quality_profile_names);
|
.set_items(quality_profile_names);
|
||||||
let quality_profile_name = radarr_data
|
let quality_profile_name = radarr_data
|
||||||
.quality_profile_map
|
.quality_profile_map
|
||||||
.get_by_left(&quality_profile_id.as_u64().unwrap())
|
.get_by_left(quality_profile_id)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quality_profile_index = edit_movie_modal
|
let quality_profile_index = edit_movie_modal
|
||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
@@ -193,7 +193,7 @@ impl From<&RadarrData<'_>> for EditCollectionModal {
|
|||||||
|
|
||||||
let quality_profile_name = radarr_data
|
let quality_profile_name = radarr_data
|
||||||
.quality_profile_map
|
.quality_profile_map
|
||||||
.get_by_left(&quality_profile_id.as_u64().unwrap())
|
.get_by_left(quality_profile_id)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let quality_profile_index = edit_collection_modal
|
let quality_profile_index = edit_collection_modal
|
||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ mod test {
|
|||||||
let movie = Movie {
|
let movie = Movie {
|
||||||
path: "/nfs/movies/Test".to_owned(),
|
path: "/nfs/movies/Test".to_owned(),
|
||||||
monitored: true,
|
monitored: true,
|
||||||
quality_profile_id: Number::from(2222),
|
quality_profile_id: 2222,
|
||||||
minimum_availability: MinimumAvailability::Released,
|
minimum_availability: MinimumAvailability::Released,
|
||||||
tags: vec![Number::from(1), Number::from(2)],
|
tags: vec![Number::from(1), Number::from(2)],
|
||||||
..Movie::default()
|
..Movie::default()
|
||||||
@@ -69,10 +69,10 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_add_movie_modal_from_radarr_data() {
|
fn test_add_movie_modal_from_radarr_data() {
|
||||||
let root_folder = RootFolder {
|
let root_folder = RootFolder {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
path: "/nfs".to_owned(),
|
path: "/nfs".to_owned(),
|
||||||
accessible: true,
|
accessible: true,
|
||||||
free_space: Number::from(219902325555200u64),
|
free_space: 219902325555200,
|
||||||
unmapped_folders: None,
|
unmapped_folders: None,
|
||||||
};
|
};
|
||||||
let mut radarr_data = RadarrData {
|
let mut radarr_data = RadarrData {
|
||||||
@@ -120,7 +120,7 @@ mod test {
|
|||||||
root_folder_path: Some("/nfs/movies/Test".to_owned()),
|
root_folder_path: Some("/nfs/movies/Test".to_owned()),
|
||||||
monitored: true,
|
monitored: true,
|
||||||
search_on_add: true,
|
search_on_add: true,
|
||||||
quality_profile_id: Number::from(2222),
|
quality_profile_id: 2222,
|
||||||
minimum_availability: MinimumAvailability::Released,
|
minimum_availability: MinimumAvailability::Released,
|
||||||
..Collection::default()
|
..Collection::default()
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ pub struct RadarrData<'a> {
|
|||||||
pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>,
|
pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>,
|
||||||
pub downloads: StatefulTable<DownloadRecord>,
|
pub downloads: StatefulTable<DownloadRecord>,
|
||||||
pub indexers: StatefulTable<Indexer>,
|
pub indexers: StatefulTable<Indexer>,
|
||||||
pub quality_profile_map: BiMap<u64, String>,
|
pub quality_profile_map: BiMap<i64, String>,
|
||||||
pub tags_map: BiMap<u64, String>,
|
pub tags_map: BiMap<i64, String>,
|
||||||
pub collections: StatefulTable<Collection>,
|
pub collections: StatefulTable<Collection>,
|
||||||
pub collection_movies: StatefulTable<CollectionMovie>,
|
pub collection_movies: StatefulTable<CollectionMovie>,
|
||||||
pub logs: StatefulList<HorizontallyScrollableText>,
|
pub logs: StatefulList<HorizontallyScrollableText>,
|
||||||
|
|||||||
+9
-19
@@ -63,7 +63,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
let request_uri = request_props.uri.clone();
|
let request_uri = request_props.uri.clone();
|
||||||
select! {
|
select! {
|
||||||
_ = self.cancellation_token.cancelled() => {
|
_ = 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;
|
let mut app = self.app.lock().await;
|
||||||
self.cancellation_token = app.reset_cancellation_token();
|
self.cancellation_token = app.reset_cancellation_token();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
@@ -80,12 +80,12 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
app_update_fn(value, app);
|
app_update_fn(value, app);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to parse response! {:?}", e);
|
error!("Failed to parse response! {e:?}");
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.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', " "), " ")
|
.replace_all(&response_body.replace('\n', " "), " ")
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
error!(
|
error!("Request failed. Received {status} response code with body: {response_body}");
|
||||||
"Request failed. Received {} response code with body: {}",
|
self.app.lock().await.handle_error(anyhow!("Request failed. Received {status} response code with body: {error_body}"));
|
||||||
status, response_body
|
|
||||||
);
|
|
||||||
self.app.lock().await.handle_error(anyhow!(
|
|
||||||
"Request failed. Received {} response code with body: {}",
|
|
||||||
status,
|
|
||||||
error_body
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to send request. {:?}", e);
|
error!("Failed to send request. {e:?}");
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.lock()
|
.lock()
|
||||||
.await
|
.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,
|
body,
|
||||||
api_token,
|
api_token,
|
||||||
} = request_props;
|
} = request_props;
|
||||||
debug!("Creating RequestBuilder for resource: {:?}", uri);
|
debug!("Creating RequestBuilder for resource: {uri:?}");
|
||||||
debug!(
|
debug!("Sending {method:?} request to {uri} with body {body:?}");
|
||||||
"Sending {:?} request to {} with body {:?}",
|
|
||||||
method, uri, body
|
|
||||||
);
|
|
||||||
|
|
||||||
match method {
|
match method {
|
||||||
RequestMethod::Get => self.client.get(uri).header("X-Api-Key", api_token),
|
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 indoc::formatdoc;
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{json, Number, Value};
|
use serde_json::{json, Value};
|
||||||
use urlencoding::encode;
|
use urlencoding::encode;
|
||||||
|
|
||||||
use crate::app::RadarrConfig;
|
use crate::app::RadarrConfig;
|
||||||
@@ -226,7 +226,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
app.data.radarr_data.add_movie_modal = None;
|
app.data.radarr_data.add_movie_modal = None;
|
||||||
|
|
||||||
AddMovieBody {
|
AddMovieBody {
|
||||||
tmdb_id: tmdb_id.as_u64().unwrap(),
|
tmdb_id,
|
||||||
title,
|
title,
|
||||||
root_folder_path: path,
|
root_folder_path: path,
|
||||||
minimum_availability,
|
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
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
@@ -273,7 +273,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
AddRootFolderBody { path }
|
AddRootFolderBody { path }
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("Add root folder body: {:?}", body);
|
debug!("Add root folder body: {body:?}");
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
@@ -301,11 +301,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
|
|
||||||
self
|
self
|
||||||
.handle_request::<Value, Tag>(request_props, |tag, mut app| {
|
.handle_request::<Value, Tag>(request_props, |tag, mut app| {
|
||||||
app
|
app.data.radarr_data.tags_map.insert(tag.id, tag.label);
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.tags_map
|
|
||||||
.insert(tag.id.as_u64().unwrap(), tag.label);
|
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
@@ -319,18 +315,13 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.downloads
|
.downloads
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.id
|
.id;
|
||||||
.as_u64()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
info!(
|
info!("Deleting Radarr download for download with id: {download_id}");
|
||||||
"Deleting Radarr download for download with id: {}",
|
|
||||||
download_id
|
|
||||||
);
|
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!("{}/{}", RadarrEvent::DeleteDownload.resource(), download_id).as_str(),
|
format!("{}/{download_id}", RadarrEvent::DeleteDownload.resource()).as_str(),
|
||||||
RequestMethod::Delete,
|
RequestMethod::Delete,
|
||||||
None::<()>,
|
None::<()>,
|
||||||
)
|
)
|
||||||
@@ -350,18 +341,13 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.indexers
|
.indexers
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.id
|
.id;
|
||||||
.as_u64()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
info!(
|
info!("Deleting Radarr indexer for indexer with id: {indexer_id}");
|
||||||
"Deleting Radarr indexer for indexer with id: {}",
|
|
||||||
indexer_id
|
|
||||||
);
|
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!("{}/{}", RadarrEvent::DeleteIndexer.resource(), indexer_id).as_str(),
|
format!("{}/{indexer_id}", RadarrEvent::DeleteIndexer.resource()).as_str(),
|
||||||
RequestMethod::Delete,
|
RequestMethod::Delete,
|
||||||
None::<()>,
|
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 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;
|
let add_import_exclusion = self.app.lock().await.data.radarr_data.add_list_exclusion;
|
||||||
|
|
||||||
info!(
|
info!("Deleting Radarr movie with tmdb_id {tmdb_id} and Radarr id: {movie_id} with deleteFiles={delete_files} and addImportExclusion={add_import_exclusion}");
|
||||||
"Deleting Radarr movie with tmdb_id {} and Radarr id: {} with deleteFiles={} and addImportExclusion={}",
|
|
||||||
tmdb_id, movie_id, delete_files, add_import_exclusion
|
|
||||||
);
|
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!(
|
format!(
|
||||||
"{}/{}?deleteFiles={}&addImportExclusion={}",
|
"{}/{movie_id}?deleteFiles={delete_files}&addImportExclusion={add_import_exclusion}",
|
||||||
RadarrEvent::DeleteMovie.resource(),
|
RadarrEvent::DeleteMovie.resource()
|
||||||
movie_id,
|
|
||||||
delete_files,
|
|
||||||
add_import_exclusion
|
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
RequestMethod::Delete,
|
RequestMethod::Delete,
|
||||||
@@ -419,21 +399,15 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.root_folders
|
.root_folders
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.id
|
.id;
|
||||||
.as_u64()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
info!(
|
info!("Deleting Radarr root folder for folder with id: {root_folder_id}");
|
||||||
"Deleting Radarr root folder for folder with id: {}",
|
|
||||||
root_folder_id
|
|
||||||
);
|
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!(
|
format!(
|
||||||
"{}/{}",
|
"{}/{root_folder_id}",
|
||||||
RadarrEvent::DeleteRootFolder.resource(),
|
RadarrEvent::DeleteRootFolder.resource()
|
||||||
root_folder_id
|
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
RequestMethod::Delete,
|
RequestMethod::Delete,
|
||||||
@@ -464,10 +438,10 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.movie_releases
|
.movie_releases
|
||||||
.current_selection();
|
.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 {
|
let download_release_body = ReleaseDownloadBody {
|
||||||
guid,
|
guid,
|
||||||
@@ -495,12 +469,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
let collection_id = self.extract_collection_id().await;
|
let collection_id = self.extract_collection_id().await;
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!(
|
format!("{}/{collection_id}", RadarrEvent::GetCollections.resource()).as_str(),
|
||||||
"{}/{}",
|
|
||||||
RadarrEvent::GetCollections.resource(),
|
|
||||||
collection_id
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
RequestMethod::Get,
|
RequestMethod::Get,
|
||||||
None::<()>,
|
None::<()>,
|
||||||
)
|
)
|
||||||
@@ -557,16 +526,11 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
detailed_collection_body
|
detailed_collection_body
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("Edit collection body: {:?}", body);
|
debug!("Edit collection body: {body:?}");
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!(
|
format!("{}/{collection_id}", RadarrEvent::EditCollection.resource()).as_str(),
|
||||||
"{}/{}",
|
|
||||||
RadarrEvent::EditCollection.resource(),
|
|
||||||
collection_id
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
RequestMethod::Put,
|
RequestMethod::Put,
|
||||||
Some(body),
|
Some(body),
|
||||||
)
|
)
|
||||||
@@ -585,7 +549,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!("{}/{}", RadarrEvent::GetMovieDetails.resource(), movie_id).as_str(),
|
format!("{}/{movie_id}", RadarrEvent::GetMovieDetails.resource()).as_str(),
|
||||||
RequestMethod::Get,
|
RequestMethod::Get,
|
||||||
None::<()>,
|
None::<()>,
|
||||||
)
|
)
|
||||||
@@ -648,11 +612,11 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
detailed_movie_body
|
detailed_movie_body
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("Edit movie body: {:?}", body);
|
debug!("Edit movie body: {body:?}");
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!("{}/{}", RadarrEvent::EditMovie.resource(), movie_id).as_str(),
|
format!("{}/{movie_id}", RadarrEvent::EditMovie.resource()).as_str(),
|
||||||
RequestMethod::Put,
|
RequestMethod::Put,
|
||||||
Some(body),
|
Some(body),
|
||||||
)
|
)
|
||||||
@@ -858,7 +822,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!("{}/{}", RadarrEvent::GetMovieDetails.resource(), movie_id).as_str(),
|
format!("{}/{movie_id}", RadarrEvent::GetMovieDetails.resource()).as_str(),
|
||||||
RequestMethod::Get,
|
RequestMethod::Get,
|
||||||
None::<()>,
|
None::<()>,
|
||||||
)
|
)
|
||||||
@@ -884,43 +848,43 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
collection,
|
collection,
|
||||||
..
|
..
|
||||||
} = movie_response;
|
} = movie_response;
|
||||||
let (hours, minutes) = convert_runtime(runtime.as_u64().unwrap());
|
let (hours, minutes) = convert_runtime(runtime);
|
||||||
let size = convert_to_gb(size_on_disk.as_u64().unwrap());
|
let size = convert_to_gb(size_on_disk);
|
||||||
let quality_profile = app
|
let quality_profile = app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.quality_profile_map
|
.quality_profile_map
|
||||||
.get_by_left(&quality_profile_id.as_u64().unwrap())
|
.get_by_left(&quality_profile_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let imdb_rating = if let Some(rating) = ratings.imdb {
|
let imdb_rating = if let Some(rating) = ratings.imdb {
|
||||||
if let Some(value) = rating.value.as_f64() {
|
if let Some(value) = rating.value.as_f64() {
|
||||||
format!("{:.1}", value)
|
format!("{:.1}", value)
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
String::new()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let tmdb_rating = if let Some(rating) = ratings.tmdb {
|
let tmdb_rating = if let Some(rating) = ratings.tmdb {
|
||||||
if let Some(value) = rating.value.as_f64() {
|
if let Some(value) = rating.value.as_f64() {
|
||||||
format!("{}%", (value * 10f64).ceil())
|
format!("{}%", (value * 10f64).ceil())
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
String::new()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let rotten_tomatoes_rating = if let Some(rating) = ratings.rotten_tomatoes {
|
let rotten_tomatoes_rating = if let Some(rating) = ratings.rotten_tomatoes {
|
||||||
if let Some(value) = rating.value.as_u64() {
|
if let Some(value) = rating.value.as_u64() {
|
||||||
format!("{}%", value)
|
format!("{}%", value)
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
String::new()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"".to_owned()
|
String::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = get_movie_status(has_file, &app.data.radarr_data.downloads.items, id);
|
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 {
|
let mut movie_details_modal = MovieDetailsModal {
|
||||||
movie_details: ScrollableText::with_string(formatdoc!(
|
movie_details: ScrollableText::with_string(formatdoc!(
|
||||||
"Title: {}
|
"Title: {title}
|
||||||
Year: {}
|
Year: {year}
|
||||||
Runtime: {}h {}m
|
Runtime: {hours}h {minutes}m
|
||||||
Rating: {}
|
Rating: {}
|
||||||
Collection: {}
|
Collection: {}
|
||||||
Status: {}
|
Status: {status}
|
||||||
Description: {}
|
Description: {overview}
|
||||||
TMDB: {}
|
TMDB: {tmdb_rating}
|
||||||
IMDB: {}
|
IMDB: {imdb_rating}
|
||||||
Rotten Tomatoes: {}
|
Rotten Tomatoes: {rotten_tomatoes_rating}
|
||||||
Quality Profile: {}
|
Quality Profile: {quality_profile}
|
||||||
Size: {:.2} GB
|
Size: {size:.2} GB
|
||||||
Path: {}
|
Path: {path}
|
||||||
Studio: {}
|
Studio: {studio}
|
||||||
Genres: {}",
|
Genres: {}",
|
||||||
title,
|
|
||||||
year,
|
|
||||||
hours,
|
|
||||||
minutes,
|
|
||||||
certification.unwrap_or_default(),
|
certification.unwrap_or_default(),
|
||||||
collection.title,
|
collection.title,
|
||||||
status,
|
|
||||||
overview,
|
|
||||||
tmdb_rating,
|
|
||||||
imdb_rating,
|
|
||||||
rotten_tomatoes_rating,
|
|
||||||
quality_profile,
|
|
||||||
size,
|
|
||||||
path,
|
|
||||||
studio,
|
|
||||||
genres.join(", ")
|
genres.join(", ")
|
||||||
)),
|
)),
|
||||||
..MovieDetailsModal::default()
|
..MovieDetailsModal::default()
|
||||||
@@ -967,11 +918,10 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
movie_details_modal.file_details = formatdoc!(
|
movie_details_modal.file_details = formatdoc!(
|
||||||
"Relative Path: {}
|
"Relative Path: {}
|
||||||
Absolute Path: {}
|
Absolute Path: {}
|
||||||
Size: {:.2} GB
|
Size: {size:.2} GB
|
||||||
Date Added: {}",
|
Date Added: {}",
|
||||||
file.relative_path,
|
file.relative_path,
|
||||||
file.path,
|
file.path,
|
||||||
size,
|
|
||||||
file.date_added
|
file.date_added
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -982,11 +932,11 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
Codec: {}
|
Codec: {}
|
||||||
Languages: {}
|
Languages: {}
|
||||||
Stream Count: {}",
|
Stream Count: {}",
|
||||||
media_info.audio_bitrate.as_u64().unwrap(),
|
media_info.audio_bitrate,
|
||||||
media_info.audio_channels.as_f64().unwrap(),
|
media_info.audio_channels.as_f64().unwrap(),
|
||||||
media_info.audio_codec.unwrap_or_default(),
|
media_info.audio_codec.unwrap_or_default(),
|
||||||
media_info.audio_languages.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!(
|
movie_details_modal.video_details = formatdoc!(
|
||||||
@@ -997,8 +947,8 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
Resolution: {}
|
Resolution: {}
|
||||||
Scan Type: {}
|
Scan Type: {}
|
||||||
Runtime: {}",
|
Runtime: {}",
|
||||||
media_info.video_bit_depth.as_u64().unwrap(),
|
media_info.video_bit_depth,
|
||||||
media_info.video_bitrate.as_u64().unwrap(),
|
media_info.video_bitrate,
|
||||||
media_info.video_codec,
|
media_info.video_codec,
|
||||||
media_info.video_fps.as_f64().unwrap(),
|
media_info.video_fps.as_f64().unwrap(),
|
||||||
media_info.resolution,
|
media_info.resolution,
|
||||||
@@ -1073,7 +1023,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.handle_request::<(), Vec<QualityProfile>>(request_props, |quality_profiles, mut app| {
|
.handle_request::<(), Vec<QualityProfile>>(request_props, |quality_profiles, mut app| {
|
||||||
app.data.radarr_data.quality_profile_map = quality_profiles
|
app.data.radarr_data.quality_profile_map = quality_profiles
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|profile| (profile.id.as_u64().unwrap(), profile.name))
|
.map(|profile| (profile.id, profile.name))
|
||||||
.collect();
|
.collect();
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@@ -1103,19 +1053,11 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
|
|
||||||
async fn get_releases(&mut self) {
|
async fn get_releases(&mut self) {
|
||||||
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
||||||
info!(
|
info!("Fetching releases for movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}");
|
||||||
"Fetching releases for movie with TMDB id {} and with Radarr id: {}",
|
|
||||||
tmdb_id, movie_id
|
|
||||||
);
|
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
format!(
|
format!("{}?movieId={movie_id}", RadarrEvent::GetReleases.resource()).as_str(),
|
||||||
"{}?movieId={}",
|
|
||||||
RadarrEvent::GetReleases.resource(),
|
|
||||||
movie_id
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
RequestMethod::Get,
|
RequestMethod::Get,
|
||||||
None::<()>,
|
None::<()>,
|
||||||
)
|
)
|
||||||
@@ -1181,7 +1123,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.handle_request::<(), Vec<Tag>>(request_props, |tags_vec, mut app| {
|
.handle_request::<(), Vec<Tag>>(request_props, |tags_vec, mut app| {
|
||||||
app.data.radarr_data.tags_map = tags_vec
|
app.data.radarr_data.tags_map = tags_vec
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|tag| (tag.id.as_u64().unwrap(), tag.label))
|
.map(|tag| (tag.id, tag.label))
|
||||||
.collect();
|
.collect();
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@@ -1241,56 +1183,46 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
let vec_to_bullet_points = |vec: Vec<String>| {
|
let vec_to_bullet_points = |vec: Vec<String>| {
|
||||||
vec
|
vec
|
||||||
.iter()
|
.iter()
|
||||||
.map(|change| format!(" * {}", change))
|
.map(|change| format!(" * {change}"))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join("\n")
|
.join("\n")
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut update_info = formatdoc!(
|
let mut update_info = formatdoc!(
|
||||||
"{} - {} {}
|
"{} - {} {install_status}
|
||||||
{}",
|
{}",
|
||||||
update.version,
|
update.version,
|
||||||
update.release_date,
|
update.release_date,
|
||||||
install_status,
|
|
||||||
"-".repeat(200)
|
"-".repeat(200)
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(new_changes) = update.changes.new {
|
if let Some(new_changes) = update.changes.new {
|
||||||
let changes = vec_to_bullet_points(new_changes);
|
let changes = vec_to_bullet_points(new_changes);
|
||||||
update_info = formatdoc!(
|
update_info = formatdoc!(
|
||||||
"{}
|
"{update_info}
|
||||||
New:
|
New:
|
||||||
{}",
|
{changes}"
|
||||||
update_info,
|
|
||||||
changes
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(fixes) = update.changes.fixed {
|
if let Some(fixes) = update.changes.fixed {
|
||||||
let fixes = vec_to_bullet_points(fixes);
|
let fixes = vec_to_bullet_points(fixes);
|
||||||
update_info = formatdoc!(
|
update_info = formatdoc!(
|
||||||
"{}
|
"{update_info}
|
||||||
Fixed:
|
Fixed:
|
||||||
{}",
|
{fixes}"
|
||||||
update_info,
|
|
||||||
fixes
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
update_info
|
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();
|
.unwrap();
|
||||||
|
|
||||||
app.data.radarr_data.updates = ScrollableText::with_string(formatdoc!(
|
app.data.radarr_data.updates = ScrollableText::with_string(formatdoc!(
|
||||||
"{}
|
"The latest version of Radarr is {latest_installed} installed
|
||||||
|
|
||||||
{}",
|
{updates}"
|
||||||
format!(
|
|
||||||
"The latest version of Radarr is {} installed",
|
|
||||||
latest_installed
|
|
||||||
),
|
|
||||||
updates
|
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@@ -1343,10 +1275,9 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!(
|
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. \
|
This is most likely caused by the user trying to navigate between modals rapidly. \
|
||||||
Ignoring search request.",
|
Ignoring search request."
|
||||||
e
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1364,7 +1295,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.task_name
|
.task_name
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
info!("Starting Radarr task: {}", task_name);
|
info!("Starting Radarr task: {task_name}");
|
||||||
|
|
||||||
let body = CommandBody { name: 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) {
|
async fn trigger_automatic_search(&mut self) {
|
||||||
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
||||||
info!(
|
info!("Searching indexers for movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}");
|
||||||
"Searching indexers for movie with TMDB id {} and with Radarr id: {}",
|
|
||||||
tmdb_id, movie_id
|
|
||||||
);
|
|
||||||
let body = MovieCommandBody {
|
let body = MovieCommandBody {
|
||||||
name: "MoviesSearch".to_owned(),
|
name: "MoviesSearch".to_owned(),
|
||||||
movie_ids: vec![movie_id],
|
movie_ids: vec![movie_id],
|
||||||
@@ -1427,10 +1355,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
|
|
||||||
async fn update_and_scan(&mut self) {
|
async fn update_and_scan(&mut self) {
|
||||||
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
let (movie_id, tmdb_id) = self.extract_movie_id().await;
|
||||||
info!(
|
info!("Updating and scanning movie with TMDB id {tmdb_id} and with Radarr id: {movie_id}");
|
||||||
"Updating and scanning movie with TMDB id {} and with Radarr id: {}",
|
|
||||||
tmdb_id, movie_id
|
|
||||||
);
|
|
||||||
let body = MovieCommandBody {
|
let body = MovieCommandBody {
|
||||||
name: "RefreshMovie".to_owned(),
|
name: "RefreshMovie".to_owned(),
|
||||||
movie_ids: vec![movie_id],
|
movie_ids: vec![movie_id],
|
||||||
@@ -1501,7 +1426,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
debug!("Indexer settings body: {:?}", body);
|
debug!("Indexer settings body: {body:?}");
|
||||||
|
|
||||||
let request_props = self
|
let request_props = self
|
||||||
.radarr_request_props_from(
|
.radarr_request_props_from(
|
||||||
@@ -1530,12 +1455,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
port,
|
port,
|
||||||
api_token,
|
api_token,
|
||||||
} = &app.config.radarr;
|
} = &app.config.radarr;
|
||||||
let uri = format!(
|
let uri = format!("http://{host}:{}/api/v3{resource}", port.unwrap_or(7878));
|
||||||
"http://{}:{}/api/v3{}",
|
|
||||||
host,
|
|
||||||
port.unwrap_or(7878),
|
|
||||||
resource
|
|
||||||
);
|
|
||||||
|
|
||||||
RequestProps {
|
RequestProps {
|
||||||
uri,
|
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_map = self.app.lock().await.data.radarr_data.tags_map.clone();
|
||||||
let tags = edit_tags.clone();
|
let tags = edit_tags.clone();
|
||||||
let missing_tags_vec = edit_tags
|
let missing_tags_vec = edit_tags
|
||||||
@@ -1572,7 +1492,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.collect()
|
.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;
|
let app = self.app.lock().await;
|
||||||
if app.data.radarr_data.filtered_movies.is_some() {
|
if app.data.radarr_data.filtered_movies.is_some() {
|
||||||
(
|
(
|
||||||
@@ -1583,9 +1503,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.id
|
.id,
|
||||||
.as_u64()
|
|
||||||
.unwrap(),
|
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -1593,33 +1511,17 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.tmdb_id
|
.tmdb_id,
|
||||||
.as_u64()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
app
|
app.data.radarr_data.movies.current_selection().id,
|
||||||
.data
|
app.data.radarr_data.movies.current_selection().tmdb_id,
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.current_selection()
|
|
||||||
.id
|
|
||||||
.as_u64()
|
|
||||||
.unwrap(),
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.current_selection()
|
|
||||||
.tmdb_id
|
|
||||||
.as_u64()
|
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn extract_collection_id(&mut self) -> u64 {
|
async fn extract_collection_id(&mut self) -> i64 {
|
||||||
if self
|
if self
|
||||||
.app
|
.app
|
||||||
.lock()
|
.lock()
|
||||||
@@ -1640,8 +1542,6 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.id
|
.id
|
||||||
.as_u64()
|
|
||||||
.unwrap()
|
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
@@ -1652,22 +1552,20 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.collections
|
.collections
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.id
|
.id
|
||||||
.as_u64()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn append_movie_id_param(&mut self, resource: &str) -> String {
|
async fn append_movie_id_param(&mut self, resource: &str) -> String {
|
||||||
let (movie_id, _) = self.extract_movie_id().await;
|
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 !has_file {
|
||||||
if let Some(download) = downloads_vec
|
if let Some(download) = downloads_vec
|
||||||
.iter()
|
.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" {
|
if download.status == "downloading" {
|
||||||
return "Downloading".to_owned();
|
return "Downloading".to_owned();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ mod test {
|
|||||||
use mockito::{Matcher, Mock, Server, ServerGuard};
|
use mockito::{Matcher, Mock, Server, ServerGuard};
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Number, Value};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
@@ -229,12 +229,12 @@ mod test {
|
|||||||
app_arc.lock().await.data.radarr_data.disk_space_vec,
|
app_arc.lock().await.data.radarr_data.disk_space_vec,
|
||||||
vec![
|
vec![
|
||||||
DiskSpace {
|
DiskSpace {
|
||||||
free_space: Number::from(1111),
|
free_space: 1111,
|
||||||
total_space: Number::from(2222),
|
total_space: 2222,
|
||||||
},
|
},
|
||||||
DiskSpace {
|
DiskSpace {
|
||||||
free_space: Number::from(3333),
|
free_space: 3333,
|
||||||
total_space: Number::from(4444),
|
total_space: 4444,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@@ -270,7 +270,7 @@ mod test {
|
|||||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||||
RequestMethod::Get,
|
RequestMethod::Get,
|
||||||
None,
|
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(),
|
RadarrEvent::GetMovies.resource(),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@@ -463,7 +463,7 @@ mod test {
|
|||||||
let mut async_server = server
|
let mut async_server = server
|
||||||
.mock(
|
.mock(
|
||||||
&RequestMethod::Get.to_string().to_uppercase(),
|
&RequestMethod::Get.to_string().to_uppercase(),
|
||||||
format!("/api/v3{}", resource).as_str(),
|
format!("/api/v3{resource}").as_str(),
|
||||||
)
|
)
|
||||||
.match_header("X-Api-Key", "test1234");
|
.match_header("X-Api-Key", "test1234");
|
||||||
async_server = async_server.expect_at_most(0).create_async().await;
|
async_server = async_server.expect_at_most(0).create_async().await;
|
||||||
@@ -1186,7 +1186,7 @@ mod test {
|
|||||||
async_server.assert_async().await;
|
async_server.assert_async().await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app_arc.lock().await.data.radarr_data.quality_profile_map,
|
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;
|
async_server.assert_async().await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app_arc.lock().await.data.radarr_data.tags_map,
|
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 {
|
Task {
|
||||||
name: "Application Check Update".to_owned(),
|
name: "Application Check Update".to_owned(),
|
||||||
task_name: "ApplicationCheckUpdate".to_owned(),
|
task_name: "ApplicationCheckUpdate".to_owned(),
|
||||||
interval: Number::from(360),
|
interval: 360,
|
||||||
last_execution: timestamp,
|
last_execution: timestamp,
|
||||||
next_execution: timestamp,
|
next_execution: timestamp,
|
||||||
last_duration: "00:00:00.5111547".to_owned(),
|
last_duration: "00:00:00.5111547".to_owned(),
|
||||||
@@ -1245,7 +1245,7 @@ mod test {
|
|||||||
Task {
|
Task {
|
||||||
name: "Backup".to_owned(),
|
name: "Backup".to_owned(),
|
||||||
task_name: "Backup".to_owned(),
|
task_name: "Backup".to_owned(),
|
||||||
interval: Number::from(10080),
|
interval: 10080,
|
||||||
last_execution: timestamp,
|
last_execution: timestamp,
|
||||||
next_execution: timestamp,
|
next_execution: timestamp,
|
||||||
last_duration: "00:00:00.5111547".to_owned(),
|
last_duration: "00:00:00.5111547".to_owned(),
|
||||||
@@ -1317,7 +1317,7 @@ mod test {
|
|||||||
The latest version of Radarr is already installed
|
The latest version of Radarr is already installed
|
||||||
|
|
||||||
4.3.2.1 - 2023-04-15 02:02:53 UTC (Currently Installed)
|
4.3.2.1 - 2023-04-15 02:02:53 UTC (Currently Installed)
|
||||||
{}
|
{line_break}
|
||||||
New:
|
New:
|
||||||
* Cool new thing
|
* Cool new thing
|
||||||
Fixed:
|
Fixed:
|
||||||
@@ -1325,20 +1325,17 @@ mod test {
|
|||||||
|
|
||||||
|
|
||||||
3.2.1.0 - 2023-04-15 02:02:53 UTC (Previously Installed)
|
3.2.1.0 - 2023-04-15 02:02:53 UTC (Previously Installed)
|
||||||
{}
|
{line_break}
|
||||||
New:
|
New:
|
||||||
* Cool new thing (old)
|
* Cool new thing (old)
|
||||||
* Other cool new thing (old)
|
* Other cool new thing (old)
|
||||||
|
|
||||||
|
|
||||||
2.1.0 - 2023-04-15 02:02:53 UTC
|
2.1.0 - 2023-04-15 02:02:53 UTC
|
||||||
{}
|
{line_break}
|
||||||
Fixed:
|
Fixed:
|
||||||
* Killed bug 1
|
* Killed bug 1
|
||||||
* Fixed bug 2",
|
* Fixed bug 2"
|
||||||
line_break.clone(),
|
|
||||||
line_break.clone(),
|
|
||||||
line_break
|
|
||||||
));
|
));
|
||||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||||
RequestMethod::Get,
|
RequestMethod::Get,
|
||||||
@@ -1569,17 +1566,17 @@ mod test {
|
|||||||
};
|
};
|
||||||
add_movie_modal.root_folder_list.set_items(vec![
|
add_movie_modal.root_folder_list.set_items(vec![
|
||||||
RootFolder {
|
RootFolder {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
path: "/nfs".to_owned(),
|
path: "/nfs".to_owned(),
|
||||||
accessible: true,
|
accessible: true,
|
||||||
free_space: Number::from(219902325555200u64),
|
free_space: 219902325555200,
|
||||||
unmapped_folders: None,
|
unmapped_folders: None,
|
||||||
},
|
},
|
||||||
RootFolder {
|
RootFolder {
|
||||||
id: Number::from(2),
|
id: 2,
|
||||||
path: "/nfs2".to_owned(),
|
path: "/nfs2".to_owned(),
|
||||||
accessible: true,
|
accessible: true,
|
||||||
free_space: Number::from(21990232555520u64),
|
free_space: 21990232555520,
|
||||||
unmapped_folders: None,
|
unmapped_folders: None,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -1655,17 +1652,17 @@ mod test {
|
|||||||
};
|
};
|
||||||
add_movie_modal.root_folder_list.set_items(vec![
|
add_movie_modal.root_folder_list.set_items(vec![
|
||||||
RootFolder {
|
RootFolder {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
path: "/nfs".to_owned(),
|
path: "/nfs".to_owned(),
|
||||||
accessible: true,
|
accessible: true,
|
||||||
free_space: Number::from(219902325555200u64),
|
free_space: 219902325555200,
|
||||||
unmapped_folders: None,
|
unmapped_folders: None,
|
||||||
},
|
},
|
||||||
RootFolder {
|
RootFolder {
|
||||||
id: Number::from(2),
|
id: 2,
|
||||||
path: "/nfs2".to_owned(),
|
path: "/nfs2".to_owned(),
|
||||||
accessible: true,
|
accessible: true,
|
||||||
free_space: Number::from(21990232555520u64),
|
free_space: 21990232555520,
|
||||||
unmapped_folders: None,
|
unmapped_folders: None,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -1685,7 +1682,7 @@ mod test {
|
|||||||
app.data.radarr_data.tags_map =
|
app.data.radarr_data.tags_map =
|
||||||
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
|
BiMap::from_iter([(1, "usenet".to_owned()), (2, "testing".to_owned())]);
|
||||||
let secondary_search_result = AddMovieSearchResult {
|
let secondary_search_result = AddMovieSearchResult {
|
||||||
tmdb_id: Number::from(5678),
|
tmdb_id: 5678,
|
||||||
..add_movie_search_result()
|
..add_movie_search_result()
|
||||||
};
|
};
|
||||||
let mut add_searched_movies = StatefulTable::default();
|
let mut add_searched_movies = StatefulTable::default();
|
||||||
@@ -1715,9 +1712,7 @@ mod test {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.tmdb_id
|
.tmdb_id,
|
||||||
.as_u64()
|
|
||||||
.unwrap(),
|
|
||||||
5678
|
5678
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2006,8 +2001,8 @@ mod test {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.movies
|
.movies
|
||||||
.set_items(vec![Movie {
|
.set_items(vec![Movie {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
tmdb_id: Number::from(2),
|
tmdb_id: 2,
|
||||||
..Movie::default()
|
..Movie::default()
|
||||||
}]);
|
}]);
|
||||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
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 app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
let mut filtered_movies = StatefulTable::default();
|
let mut filtered_movies = StatefulTable::default();
|
||||||
filtered_movies.set_items(vec![Movie {
|
filtered_movies.set_items(vec![Movie {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
tmdb_id: Number::from(2),
|
tmdb_id: 2,
|
||||||
..Movie::default()
|
..Movie::default()
|
||||||
}]);
|
}]);
|
||||||
app_arc.lock().await.data.radarr_data.filtered_movies = Some(filtered_movies);
|
app_arc.lock().await.data.radarr_data.filtered_movies = Some(filtered_movies);
|
||||||
@@ -2040,7 +2035,7 @@ mod test {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.collections
|
.collections
|
||||||
.set_items(vec![Collection {
|
.set_items(vec![Collection {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
..Collection::default()
|
..Collection::default()
|
||||||
}]);
|
}]);
|
||||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
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 app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
let mut filtered_collections = StatefulTable::default();
|
let mut filtered_collections = StatefulTable::default();
|
||||||
filtered_collections.set_items(vec![Collection {
|
filtered_collections.set_items(vec![Collection {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
..Collection::default()
|
..Collection::default()
|
||||||
}]);
|
}]);
|
||||||
app_arc.lock().await.data.radarr_data.filtered_collections = Some(filtered_collections);
|
app_arc.lock().await.data.radarr_data.filtered_collections = Some(filtered_collections);
|
||||||
@@ -2072,7 +2067,7 @@ mod test {
|
|||||||
.radarr_data
|
.radarr_data
|
||||||
.movies
|
.movies
|
||||||
.set_items(vec![Movie {
|
.set_items(vec![Movie {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
..Movie::default()
|
..Movie::default()
|
||||||
}]);
|
}]);
|
||||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
let mut network = Network::new(&app_arc, CancellationToken::new());
|
||||||
@@ -2127,25 +2122,22 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_movie_status_downloaded() {
|
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]
|
#[test]
|
||||||
fn test_get_movie_status_missing() {
|
fn test_get_movie_status_missing() {
|
||||||
let download_record = DownloadRecord {
|
let download_record = DownloadRecord {
|
||||||
movie_id: 1.into(),
|
movie_id: 1,
|
||||||
..DownloadRecord::default()
|
..DownloadRecord::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
get_movie_status(false, &[download_record.clone()], 0.into()),
|
get_movie_status(false, &[download_record.clone()], 0),
|
||||||
"Missing"
|
"Missing"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(get_movie_status(false, &[download_record], 1), "Missing");
|
||||||
get_movie_status(false, &[download_record], 1.into()),
|
|
||||||
"Missing"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -2154,11 +2146,11 @@ mod test {
|
|||||||
get_movie_status(
|
get_movie_status(
|
||||||
false,
|
false,
|
||||||
&[DownloadRecord {
|
&[DownloadRecord {
|
||||||
movie_id: 1.into(),
|
movie_id: 1,
|
||||||
status: "downloading".to_owned(),
|
status: "downloading".to_owned(),
|
||||||
..DownloadRecord::default()
|
..DownloadRecord::default()
|
||||||
}],
|
}],
|
||||||
1.into()
|
1
|
||||||
),
|
),
|
||||||
"Downloading"
|
"Downloading"
|
||||||
);
|
);
|
||||||
@@ -2170,11 +2162,11 @@ mod test {
|
|||||||
get_movie_status(
|
get_movie_status(
|
||||||
false,
|
false,
|
||||||
&[DownloadRecord {
|
&[DownloadRecord {
|
||||||
movie_id: 1.into(),
|
movie_id: 1,
|
||||||
status: "completed".to_owned(),
|
status: "completed".to_owned(),
|
||||||
..DownloadRecord::default()
|
..DownloadRecord::default()
|
||||||
}],
|
}],
|
||||||
1.into()
|
1
|
||||||
),
|
),
|
||||||
"Awaiting Import"
|
"Awaiting Import"
|
||||||
);
|
);
|
||||||
@@ -2190,7 +2182,7 @@ mod test {
|
|||||||
let mut async_server = server
|
let mut async_server = server
|
||||||
.mock(
|
.mock(
|
||||||
&method.to_string().to_uppercase(),
|
&method.to_string().to_uppercase(),
|
||||||
format!("/api/v3{}", resource).as_str(),
|
format!("/api/v3{resource}").as_str(),
|
||||||
)
|
)
|
||||||
.match_header("X-Api-Key", "test1234");
|
.match_header("X-Api-Key", "test1234");
|
||||||
|
|
||||||
@@ -2248,13 +2240,13 @@ mod test {
|
|||||||
|
|
||||||
fn media_info() -> MediaInfo {
|
fn media_info() -> MediaInfo {
|
||||||
MediaInfo {
|
MediaInfo {
|
||||||
audio_bitrate: Number::from(0),
|
audio_bitrate: 0,
|
||||||
audio_channels: Number::from_f64(7.1).unwrap(),
|
audio_channels: Number::from_f64(7.1).unwrap(),
|
||||||
audio_codec: Some("AAC".to_owned()),
|
audio_codec: Some("AAC".to_owned()),
|
||||||
audio_languages: Some("eng".to_owned()),
|
audio_languages: Some("eng".to_owned()),
|
||||||
audio_stream_count: Number::from(1),
|
audio_stream_count: 1,
|
||||||
video_bit_depth: Number::from(10),
|
video_bit_depth: 10,
|
||||||
video_bitrate: Number::from(0),
|
video_bitrate: 0,
|
||||||
video_codec: "x265".to_owned(),
|
video_codec: "x265".to_owned(),
|
||||||
video_fps: Number::from_f64(23.976).unwrap(),
|
video_fps: Number::from_f64(23.976).unwrap(),
|
||||||
resolution: "1920x804".to_owned(),
|
resolution: "1920x804".to_owned(),
|
||||||
@@ -2276,9 +2268,9 @@ mod test {
|
|||||||
CollectionMovie {
|
CollectionMovie {
|
||||||
title: "Test".to_owned().into(),
|
title: "Test".to_owned().into(),
|
||||||
overview: "Collection blah blah blah".to_owned(),
|
overview: "Collection blah blah blah".to_owned(),
|
||||||
year: Number::from(2023),
|
year: 2023,
|
||||||
runtime: Number::from(120),
|
runtime: 120,
|
||||||
tmdb_id: Number::from(1234),
|
tmdb_id: 1234,
|
||||||
genres: genres(),
|
genres: genres(),
|
||||||
ratings: ratings_list(),
|
ratings: ratings_list(),
|
||||||
}
|
}
|
||||||
@@ -2286,35 +2278,35 @@ mod test {
|
|||||||
|
|
||||||
fn collection() -> Collection {
|
fn collection() -> Collection {
|
||||||
Collection {
|
Collection {
|
||||||
id: Number::from(123),
|
id: 123,
|
||||||
title: "Test Collection".to_owned().into(),
|
title: "Test Collection".to_owned().into(),
|
||||||
root_folder_path: Some("/nfs/movies".to_owned()),
|
root_folder_path: Some("/nfs/movies".to_owned()),
|
||||||
search_on_add: true,
|
search_on_add: true,
|
||||||
monitored: true,
|
monitored: true,
|
||||||
minimum_availability: MinimumAvailability::Released,
|
minimum_availability: MinimumAvailability::Released,
|
||||||
overview: Some("Collection blah blah blah".to_owned()),
|
overview: Some("Collection blah blah blah".to_owned()),
|
||||||
quality_profile_id: Number::from(2222),
|
quality_profile_id: 2222,
|
||||||
movies: Some(vec![collection_movie()]),
|
movies: Some(vec![collection_movie()]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn movie() -> Movie {
|
fn movie() -> Movie {
|
||||||
Movie {
|
Movie {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
title: "Test".to_owned().into(),
|
title: "Test".to_owned().into(),
|
||||||
original_language: language(),
|
original_language: language(),
|
||||||
size_on_disk: Number::from(3543348019u64),
|
size_on_disk: 3543348019,
|
||||||
status: "Downloaded".to_owned(),
|
status: "Downloaded".to_owned(),
|
||||||
overview: "Blah blah blah".to_owned(),
|
overview: "Blah blah blah".to_owned(),
|
||||||
path: "/nfs/movies".to_owned(),
|
path: "/nfs/movies".to_owned(),
|
||||||
studio: "21st Century Alex".to_owned(),
|
studio: "21st Century Alex".to_owned(),
|
||||||
genres: genres(),
|
genres: genres(),
|
||||||
year: Number::from(2023),
|
year: 2023,
|
||||||
monitored: true,
|
monitored: true,
|
||||||
has_file: true,
|
has_file: true,
|
||||||
runtime: Number::from(120),
|
runtime: 120,
|
||||||
tmdb_id: Number::from(1234),
|
tmdb_id: 1234,
|
||||||
quality_profile_id: Number::from(2222),
|
quality_profile_id: 2222,
|
||||||
minimum_availability: MinimumAvailability::Announced,
|
minimum_availability: MinimumAvailability::Announced,
|
||||||
certification: Some("R".to_owned()),
|
certification: Some("R".to_owned()),
|
||||||
tags: vec![Number::from(1)],
|
tags: vec![Number::from(1)],
|
||||||
@@ -2345,11 +2337,11 @@ mod test {
|
|||||||
Release {
|
Release {
|
||||||
guid: "1234".to_owned(),
|
guid: "1234".to_owned(),
|
||||||
protocol: "torrent".to_owned(),
|
protocol: "torrent".to_owned(),
|
||||||
age: Number::from(1),
|
age: 1,
|
||||||
title: HorizontallyScrollableText::from("Test Release"),
|
title: HorizontallyScrollableText::from("Test Release"),
|
||||||
indexer: "kickass torrents".to_owned(),
|
indexer: "kickass torrents".to_owned(),
|
||||||
indexer_id: Number::from(2),
|
indexer_id: 2,
|
||||||
size: Number::from(1234),
|
size: 1234,
|
||||||
rejected: true,
|
rejected: true,
|
||||||
rejections: Some(rejections()),
|
rejections: Some(rejections()),
|
||||||
seeders: Some(Number::from(2)),
|
seeders: Some(Number::from(2)),
|
||||||
@@ -2361,14 +2353,14 @@ mod test {
|
|||||||
|
|
||||||
fn add_movie_search_result() -> AddMovieSearchResult {
|
fn add_movie_search_result() -> AddMovieSearchResult {
|
||||||
AddMovieSearchResult {
|
AddMovieSearchResult {
|
||||||
tmdb_id: Number::from(1234),
|
tmdb_id: 1234,
|
||||||
title: HorizontallyScrollableText::from("Test"),
|
title: HorizontallyScrollableText::from("Test"),
|
||||||
original_language: language(),
|
original_language: language(),
|
||||||
status: "released".to_owned(),
|
status: "released".to_owned(),
|
||||||
overview: "New movie blah blah blah".to_owned(),
|
overview: "New movie blah blah blah".to_owned(),
|
||||||
genres: genres(),
|
genres: genres(),
|
||||||
year: Number::from(2023),
|
year: 2023,
|
||||||
runtime: Number::from(120),
|
runtime: 120,
|
||||||
ratings: ratings_list(),
|
ratings: ratings_list(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2387,10 +2379,10 @@ mod test {
|
|||||||
DownloadRecord {
|
DownloadRecord {
|
||||||
title: "Test Download Title".to_owned(),
|
title: "Test Download Title".to_owned(),
|
||||||
status: "downloading".to_owned(),
|
status: "downloading".to_owned(),
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
movie_id: Number::from(1),
|
movie_id: 1,
|
||||||
size: Number::from(3543348019u64),
|
size: 3543348019,
|
||||||
sizeleft: Number::from(1771674009u64),
|
sizeleft: 1771674009,
|
||||||
output_path: Some(HorizontallyScrollableText::from("/nfs/movies/Test")),
|
output_path: Some(HorizontallyScrollableText::from("/nfs/movies/Test")),
|
||||||
indexer: "kickass torrents".to_owned(),
|
indexer: "kickass torrents".to_owned(),
|
||||||
download_client: "transmission".to_owned(),
|
download_client: "transmission".to_owned(),
|
||||||
@@ -2405,10 +2397,10 @@ mod test {
|
|||||||
|
|
||||||
fn root_folder() -> RootFolder {
|
fn root_folder() -> RootFolder {
|
||||||
RootFolder {
|
RootFolder {
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
path: "/nfs".to_owned(),
|
path: "/nfs".to_owned(),
|
||||||
accessible: true,
|
accessible: true,
|
||||||
free_space: Number::from(219902325555200u64),
|
free_space: 219902325555200,
|
||||||
unmapped_folders: None,
|
unmapped_folders: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2441,17 +2433,17 @@ mod test {
|
|||||||
supports_rss: true,
|
supports_rss: true,
|
||||||
supports_search: true,
|
supports_search: true,
|
||||||
protocol: "torrent".to_owned(),
|
protocol: "torrent".to_owned(),
|
||||||
priority: Number::from(25),
|
priority: 25,
|
||||||
download_client_id: Number::from(0),
|
download_client_id: 0,
|
||||||
name: Some("Test Indexer".to_owned()),
|
name: Some("Test Indexer".to_owned()),
|
||||||
implementation_name: Some("Torznab".to_owned()),
|
implementation_name: Some("Torznab".to_owned()),
|
||||||
implementation: Some("Torznab".to_owned()),
|
implementation: Some("Torznab".to_owned()),
|
||||||
config_contract: Some("TorznabSettings".to_owned()),
|
config_contract: Some("TorznabSettings".to_owned()),
|
||||||
tags: Some(vec!["test_tag".to_owned()]),
|
tags: Some(vec!["test_tag".to_owned()]),
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
fields: Some(vec![
|
fields: Some(vec![
|
||||||
IndexerField {
|
IndexerField {
|
||||||
order: Number::from(0),
|
order: 0,
|
||||||
name: Some("valueIsString".to_owned()),
|
name: Some("valueIsString".to_owned()),
|
||||||
label: Some("Value Is String".to_owned()),
|
label: Some("Value Is String".to_owned()),
|
||||||
value: Some(json!("hello")),
|
value: Some(json!("hello")),
|
||||||
@@ -2459,19 +2451,19 @@ mod test {
|
|||||||
select_options: None,
|
select_options: None,
|
||||||
},
|
},
|
||||||
IndexerField {
|
IndexerField {
|
||||||
order: Number::from(1),
|
order: 1,
|
||||||
name: Some("emptyValueWithSelectOptions".to_owned()),
|
name: Some("emptyValueWithSelectOptions".to_owned()),
|
||||||
label: Some("Empty Value With Select Options".to_owned()),
|
label: Some("Empty Value With Select Options".to_owned()),
|
||||||
value: None,
|
value: None,
|
||||||
field_type: Some("select".to_owned()),
|
field_type: Some("select".to_owned()),
|
||||||
select_options: Some(vec![IndexerSelectOption {
|
select_options: Some(vec![IndexerSelectOption {
|
||||||
value: Number::from(-2),
|
value: -2,
|
||||||
name: Some("Original".to_owned()),
|
name: Some("Original".to_owned()),
|
||||||
order: Number::from(0),
|
order: 0,
|
||||||
}]),
|
}]),
|
||||||
},
|
},
|
||||||
IndexerField {
|
IndexerField {
|
||||||
order: Number::from(2),
|
order: 2,
|
||||||
name: Some("valueIsAnArray".to_owned()),
|
name: Some("valueIsAnArray".to_owned()),
|
||||||
label: Some("Value is an array".to_owned()),
|
label: Some("Value is an array".to_owned()),
|
||||||
value: Some(json!([1, 2])),
|
value: Some(json!([1, 2])),
|
||||||
@@ -2484,9 +2476,9 @@ mod test {
|
|||||||
|
|
||||||
fn indexer_settings() -> IndexerSettings {
|
fn indexer_settings() -> IndexerSettings {
|
||||||
IndexerSettings {
|
IndexerSettings {
|
||||||
rss_sync_interval: Number::from(60),
|
rss_sync_interval: 60,
|
||||||
allow_hardcoded_subs: true,
|
allow_hardcoded_subs: true,
|
||||||
id: Number::from(1),
|
id: 1,
|
||||||
..IndexerSettings::default()
|
..IndexerSettings::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -545,7 +545,7 @@ pub fn draw_checkbox_with_label<B: Backend>(
|
|||||||
area,
|
area,
|
||||||
);
|
);
|
||||||
|
|
||||||
let label_paragraph = Paragraph::new(Text::from(format!("\n{}: ", label)))
|
let label_paragraph = Paragraph::new(Text::from(format!("\n{label}: ")))
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
.alignment(Alignment::Right)
|
.alignment(Alignment::Right)
|
||||||
.style(style_primary());
|
.style(style_primary());
|
||||||
@@ -605,7 +605,7 @@ pub fn draw_drop_down_menu_button<B: Backend>(
|
|||||||
area,
|
area,
|
||||||
);
|
);
|
||||||
|
|
||||||
let description_paragraph = Paragraph::new(Text::from(format!("\n{}: ", description)))
|
let description_paragraph = Paragraph::new(Text::from(format!("\n{description}: ")))
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
.alignment(Alignment::Right)
|
.alignment(Alignment::Right)
|
||||||
.style(style_primary());
|
.style(style_primary());
|
||||||
@@ -676,7 +676,7 @@ fn draw_help_and_get_content_rect<B: Backend>(
|
|||||||
let chunks =
|
let chunks =
|
||||||
vertical_chunks_with_margin(vec![Constraint::Min(0), Constraint::Length(2)], area, 1);
|
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());
|
help_test.patch_style(style_help());
|
||||||
let help_paragraph = Paragraph::new(help_test)
|
let help_paragraph = Paragraph::new(help_test)
|
||||||
.block(layout_block_top_border())
|
.block(layout_block_top_border())
|
||||||
@@ -739,7 +739,7 @@ pub fn draw_text_box_with_label<B: Backend>(
|
|||||||
area,
|
area,
|
||||||
);
|
);
|
||||||
|
|
||||||
let label_paragraph = Paragraph::new(Text::from(format!("\n{}: ", label)))
|
let label_paragraph = Paragraph::new(Text::from(format!("\n{label}: ")))
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
.alignment(Alignment::Right)
|
.alignment(Alignment::Right)
|
||||||
.style(style_primary());
|
.style(style_primary());
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use crate::utils::convert_runtime;
|
|||||||
#[path = "collection_details_ui_tests.rs"]
|
#[path = "collection_details_ui_tests.rs"]
|
||||||
mod collection_details_ui_tests;
|
mod collection_details_ui_tests;
|
||||||
|
|
||||||
pub(super) struct CollectionDetailsUi {}
|
pub(super) struct CollectionDetailsUi;
|
||||||
|
|
||||||
impl DrawUi for CollectionDetailsUi {
|
impl DrawUi for CollectionDetailsUi {
|
||||||
fn accepts(route: Route) -> bool {
|
fn accepts(route: Route) -> bool {
|
||||||
@@ -90,7 +90,7 @@ pub fn draw_collection_details<B: Backend>(
|
|||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.quality_profile_map
|
.quality_profile_map
|
||||||
.get_by_left(&collection_selection.quality_profile_id.as_u64().unwrap())
|
.get_by_left(&collection_selection.quality_profile_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let current_selection = if app.data.radarr_data.collection_movies.items.is_empty() {
|
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,
|
current_selection == *movie,
|
||||||
app.tick_count % app.ticks_until_scroll == 0,
|
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
|
let imdb_rating = movie
|
||||||
.ratings
|
.ratings
|
||||||
.imdb
|
.imdb
|
||||||
@@ -218,19 +218,19 @@ pub fn draw_collection_details<B: Backend>(
|
|||||||
let imdb_rating = if imdb_rating == 0.0 {
|
let imdb_rating = if imdb_rating == 0.0 {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{:.1}", imdb_rating)
|
format!("{imdb_rating:.1}")
|
||||||
};
|
};
|
||||||
let rotten_tomatoes_rating = if rotten_tomatoes_rating == 0 {
|
let rotten_tomatoes_rating = if rotten_tomatoes_rating == 0 {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{}%", rotten_tomatoes_rating)
|
format!("{rotten_tomatoes_rating}%")
|
||||||
};
|
};
|
||||||
|
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(in_library),
|
Cell::from(in_library),
|
||||||
Cell::from(movie.title.to_string()),
|
Cell::from(movie.title.to_string()),
|
||||||
Cell::from(movie.year.as_u64().unwrap().to_string()),
|
Cell::from(movie.year.to_string()),
|
||||||
Cell::from(format!("{}h {}m", hours, minutes)),
|
Cell::from(format!("{hours}h {minutes}m")),
|
||||||
Cell::from(imdb_rating),
|
Cell::from(imdb_rating),
|
||||||
Cell::from(rotten_tomatoes_rating),
|
Cell::from(rotten_tomatoes_rating),
|
||||||
Cell::from(movie.genres.join(", ")),
|
Cell::from(movie.genres.join(", ")),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use crate::ui::{
|
|||||||
#[path = "edit_collection_ui_tests.rs"]
|
#[path = "edit_collection_ui_tests.rs"]
|
||||||
mod edit_collection_ui_tests;
|
mod edit_collection_ui_tests;
|
||||||
|
|
||||||
pub(super) struct EditCollectionUi {}
|
pub(super) struct EditCollectionUi;
|
||||||
|
|
||||||
impl DrawUi for EditCollectionUi {
|
impl DrawUi for EditCollectionUi {
|
||||||
fn accepts(route: Route) -> bool {
|
fn accepts(route: Route) -> bool {
|
||||||
@@ -126,7 +126,7 @@ fn draw_edit_collection_confirmation_prompt<B: Backend>(
|
|||||||
.unwrap_or_default(),
|
.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 yes_no_value = app.data.radarr_data.prompt_confirm;
|
||||||
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
||||||
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditCollectionConfirmPrompt;
|
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditCollectionConfirmPrompt;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ mod collection_details_ui;
|
|||||||
mod collections_ui_tests;
|
mod collections_ui_tests;
|
||||||
mod edit_collection_ui;
|
mod edit_collection_ui;
|
||||||
|
|
||||||
pub(super) struct CollectionsUi {}
|
pub(super) struct CollectionsUi;
|
||||||
|
|
||||||
impl DrawUi for CollectionsUi {
|
impl DrawUi for CollectionsUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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(collection.root_folder_path.clone().unwrap_or_default()),
|
||||||
Cell::from(
|
Cell::from(
|
||||||
quality_profile_map
|
quality_profile_map
|
||||||
.get_by_left(&collection.quality_profile_id.as_u64().unwrap())
|
.get_by_left(&collection.quality_profile_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::utils::convert_to_gb;
|
|||||||
#[path = "downloads_ui_tests.rs"]
|
#[path = "downloads_ui_tests.rs"]
|
||||||
mod downloads_ui_tests;
|
mod downloads_ui_tests;
|
||||||
|
|
||||||
pub(super) struct DownloadsUi {}
|
pub(super) struct DownloadsUi;
|
||||||
|
|
||||||
impl DrawUi for DownloadsUi {
|
impl DrawUi for DownloadsUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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 percent = 1f64 - (*sizeleft as f64 / *size as f64);
|
||||||
let file_size: f64 = convert_to_gb(size.as_u64().unwrap());
|
let file_size: f64 = convert_to_gb(*size);
|
||||||
|
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(title.to_owned()),
|
Cell::from(title.to_owned()),
|
||||||
Cell::from(format!("{:.0}%", percent * 100.0)),
|
Cell::from(format!("{:.0}%", percent * 100.0)),
|
||||||
Cell::from(format!("{:.2} GB", file_size)),
|
Cell::from(format!("{file_size:.2} GB")),
|
||||||
Cell::from(
|
Cell::from(
|
||||||
output_path
|
output_path
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use crate::ui::{
|
|||||||
#[path = "indexer_settings_ui_tests.rs"]
|
#[path = "indexer_settings_ui_tests.rs"]
|
||||||
mod indexer_settings_ui_tests;
|
mod indexer_settings_ui_tests;
|
||||||
|
|
||||||
pub(super) struct IndexerSettingsUi {}
|
pub(super) struct IndexerSettingsUi;
|
||||||
|
|
||||||
impl DrawUi for IndexerSettingsUi {
|
impl DrawUi for IndexerSettingsUi {
|
||||||
fn accepts(route: Route) -> bool {
|
fn accepts(route: Route) -> bool {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ mod indexer_settings_ui;
|
|||||||
#[path = "indexers_ui_tests.rs"]
|
#[path = "indexers_ui_tests.rs"]
|
||||||
mod indexers_ui_tests;
|
mod indexers_ui_tests;
|
||||||
|
|
||||||
pub(super) struct IndexersUi {}
|
pub(super) struct IndexersUi;
|
||||||
|
|
||||||
impl DrawUi for IndexersUi {
|
impl DrawUi for IndexersUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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(rss),
|
||||||
Cell::from(automatic_search),
|
Cell::from(automatic_search),
|
||||||
Cell::from(interactive_search),
|
Cell::from(interactive_search),
|
||||||
Cell::from(priority.as_u64().unwrap().to_string()),
|
Cell::from(priority.to_string()),
|
||||||
])
|
])
|
||||||
.style(style_primary())
|
.style(style_primary())
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ use crate::App;
|
|||||||
#[path = "add_movie_ui_tests.rs"]
|
#[path = "add_movie_ui_tests.rs"]
|
||||||
mod add_movie_ui_tests;
|
mod add_movie_ui_tests;
|
||||||
|
|
||||||
pub(super) struct AddMovieUi {}
|
pub(super) struct AddMovieUi;
|
||||||
|
|
||||||
impl DrawUi for AddMovieUi {
|
impl DrawUi for AddMovieUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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,
|
help: None,
|
||||||
},
|
},
|
||||||
|movie| {
|
|movie| {
|
||||||
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
let (hours, minutes) = convert_runtime(movie.runtime);
|
||||||
let imdb_rating = movie
|
let imdb_rating = movie
|
||||||
.ratings
|
.ratings
|
||||||
.imdb
|
.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 {
|
let imdb_rating = if imdb_rating == 0.0 {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{:.1}", imdb_rating)
|
format!("{imdb_rating:.1}")
|
||||||
};
|
};
|
||||||
let rotten_tomatoes_rating = if rotten_tomatoes_rating == 0 {
|
let rotten_tomatoes_rating = if rotten_tomatoes_rating == 0 {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{}%", rotten_tomatoes_rating)
|
format!("{rotten_tomatoes_rating}%")
|
||||||
};
|
};
|
||||||
let in_library = if app
|
let in_library = if app
|
||||||
.data
|
.data
|
||||||
@@ -250,8 +250,8 @@ fn draw_add_movie_search<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, ar
|
|||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(in_library),
|
Cell::from(in_library),
|
||||||
Cell::from(movie.title.to_string()),
|
Cell::from(movie.title.to_string()),
|
||||||
Cell::from(movie.year.as_u64().unwrap().to_string()),
|
Cell::from(movie.year.to_string()),
|
||||||
Cell::from(format!("{}h {}m", hours, minutes)),
|
Cell::from(format!("{hours}h {minutes}m")),
|
||||||
Cell::from(imdb_rating),
|
Cell::from(imdb_rating),
|
||||||
Cell::from(rotten_tomatoes_rating),
|
Cell::from(rotten_tomatoes_rating),
|
||||||
Cell::from(movie.genres.join(", ")),
|
Cell::from(movie.genres.join(", ")),
|
||||||
@@ -368,7 +368,7 @@ fn draw_confirmation_prompt<B: Backend>(
|
|||||||
.clone(),
|
.clone(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let title = format!("Add Movie - {}", movie_title);
|
let title = format!("Add Movie - {movie_title}");
|
||||||
let prompt = movie_overview;
|
let prompt = movie_overview;
|
||||||
let yes_no_value = app.data.radarr_data.prompt_confirm;
|
let yes_no_value = app.data.radarr_data.prompt_confirm;
|
||||||
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
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"]
|
#[path = "delete_movie_ui_tests.rs"]
|
||||||
mod delete_movie_ui_tests;
|
mod delete_movie_ui_tests;
|
||||||
|
|
||||||
pub(super) struct DeleteMovieUi {}
|
pub(super) struct DeleteMovieUi;
|
||||||
|
|
||||||
impl DrawUi for DeleteMovieUi {
|
impl DrawUi for DeleteMovieUi {
|
||||||
fn accepts(route: Route) -> bool {
|
fn accepts(route: Route) -> bool {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use crate::ui::{
|
|||||||
#[path = "edit_movie_ui_tests.rs"]
|
#[path = "edit_movie_ui_tests.rs"]
|
||||||
mod edit_movie_ui_tests;
|
mod edit_movie_ui_tests;
|
||||||
|
|
||||||
pub(super) struct EditMovieUi {}
|
pub(super) struct EditMovieUi;
|
||||||
|
|
||||||
impl DrawUi for EditMovieUi {
|
impl DrawUi for EditMovieUi {
|
||||||
fn accepts(route: Route) -> bool {
|
fn accepts(route: Route) -> bool {
|
||||||
@@ -118,7 +118,7 @@ fn draw_edit_movie_confirmation_prompt<B: Backend>(
|
|||||||
.clone(),
|
.clone(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let title = format!("Edit - {}", movie_title);
|
let title = format!("Edit - {movie_title}");
|
||||||
let yes_no_value = app.data.radarr_data.prompt_confirm;
|
let yes_no_value = app.data.radarr_data.prompt_confirm;
|
||||||
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
let selected_block = app.data.radarr_data.selected_block.get_active_block();
|
||||||
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditMovieConfirmPrompt;
|
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditMovieConfirmPrompt;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ mod movie_details_ui;
|
|||||||
#[path = "library_ui_tests.rs"]
|
#[path = "library_ui_tests.rs"]
|
||||||
mod library_ui_tests;
|
mod library_ui_tests;
|
||||||
|
|
||||||
pub(super) struct LibraryUi {}
|
pub(super) struct LibraryUi;
|
||||||
|
|
||||||
impl DrawUi for LibraryUi {
|
impl DrawUi for LibraryUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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,
|
app.tick_count % app.ticks_until_scroll == 0,
|
||||||
);
|
);
|
||||||
let monitored = if movie.monitored { "🏷" } else { "" };
|
let monitored = if movie.monitored { "🏷" } else { "" };
|
||||||
let (hours, minutes) = convert_runtime(movie.runtime.as_u64().unwrap());
|
let (hours, minutes) = convert_runtime(movie.runtime);
|
||||||
let file_size: f64 = convert_to_gb(movie.size_on_disk.as_u64().unwrap());
|
let file_size: f64 = convert_to_gb(movie.size_on_disk);
|
||||||
let certification = movie.certification.clone().unwrap_or_else(|| "".to_owned());
|
let certification = movie.certification.clone().unwrap_or_default();
|
||||||
let quality_profile = quality_profile_map
|
let quality_profile = quality_profile_map
|
||||||
.get_by_left(&movie.quality_profile_id.as_u64().unwrap())
|
.get_by_left(&movie.quality_profile_id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let tags = movie
|
let tags = movie
|
||||||
@@ -180,7 +180,7 @@ pub(super) fn draw_library<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>,
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|tag_id| {
|
.map(|tag_id| {
|
||||||
tags_map
|
tags_map
|
||||||
.get_by_left(&tag_id.as_u64().unwrap())
|
.get_by_left(&tag_id.as_i64().unwrap())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone()
|
.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.title.to_string()),
|
||||||
Cell::from(movie.year.to_string()),
|
Cell::from(movie.year.to_string()),
|
||||||
Cell::from(movie.studio.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(certification),
|
||||||
Cell::from(movie.original_language.name.to_owned()),
|
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(quality_profile),
|
||||||
Cell::from(monitored.to_owned()),
|
Cell::from(monitored.to_owned()),
|
||||||
Cell::from(tags),
|
Cell::from(tags),
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ use crate::utils::convert_to_gb;
|
|||||||
#[path = "movie_details_ui_tests.rs"]
|
#[path = "movie_details_ui_tests.rs"]
|
||||||
mod movie_details_ui_tests;
|
mod movie_details_ui_tests;
|
||||||
|
|
||||||
pub(super) struct MovieDetailsUi {}
|
pub(super) struct MovieDetailsUi;
|
||||||
|
|
||||||
impl DrawUi for MovieDetailsUi {
|
impl DrawUi for MovieDetailsUi {
|
||||||
fn accepts(route: Route) -> bool {
|
fn accepts(route: Route) -> bool {
|
||||||
@@ -504,21 +504,21 @@ fn draw_movie_releases<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, cont
|
|||||||
quality,
|
quality,
|
||||||
..
|
..
|
||||||
} = release;
|
} = release;
|
||||||
let age = format!("{} days", age.as_u64().unwrap_or(0));
|
let age = format!("{age} days");
|
||||||
title.scroll_left_or_reset(
|
title.scroll_left_or_reset(
|
||||||
get_width_from_percentage(content_area, 30),
|
get_width_from_percentage(content_area, 30),
|
||||||
current_selection == *release
|
current_selection == *release
|
||||||
&& current_route != ActiveRadarrBlock::ManualSearchConfirmPrompt.into(),
|
&& current_route != ActiveRadarrBlock::ManualSearchConfirmPrompt.into(),
|
||||||
app.tick_count % app.ticks_until_scroll == 0,
|
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 rejected_str = if *rejected { "⛔" } else { "" };
|
||||||
let peers = if seeders.is_none() || leechers.is_none() {
|
let peers = if seeders.is_none() || leechers.is_none() {
|
||||||
Text::default()
|
Text::default()
|
||||||
} else {
|
} else {
|
||||||
let seeders = seeders.clone().unwrap().as_u64().unwrap();
|
let seeders = seeders.clone().unwrap().as_u64().unwrap();
|
||||||
let leechers = leechers.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.patch_style(determine_peer_style(seeders, leechers));
|
||||||
|
|
||||||
text
|
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(rejected_str),
|
||||||
Cell::from(title.to_string()),
|
Cell::from(title.to_string()),
|
||||||
Cell::from(indexer.clone()),
|
Cell::from(indexer.clone()),
|
||||||
Cell::from(format!("{:.1} GB", size)),
|
Cell::from(format!("{size:.1} GB")),
|
||||||
Cell::from(peers),
|
Cell::from(peers),
|
||||||
Cell::from(language),
|
Cell::from(language),
|
||||||
Cell::from(quality),
|
Cell::from(quality),
|
||||||
@@ -589,7 +589,7 @@ fn draw_manual_search_confirm_prompt<B: Backend>(
|
|||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.iter()
|
.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<'_>>>();
|
.collect::<Vec<Line<'_>>>();
|
||||||
lines_vec.append(&mut rejections_spans);
|
lines_vec.append(&mut rejections_spans);
|
||||||
|
|
||||||
|
|||||||
+7
-11
@@ -41,7 +41,7 @@ mod system;
|
|||||||
#[path = "radarr_ui_tests.rs"]
|
#[path = "radarr_ui_tests.rs"]
|
||||||
mod radarr_ui_tests;
|
mod radarr_ui_tests;
|
||||||
|
|
||||||
pub(super) struct RadarrUi {}
|
pub(super) struct RadarrUi;
|
||||||
|
|
||||||
impl DrawUi for RadarrUi {
|
impl DrawUi for RadarrUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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 seconds = (hour_difference - Duration::minutes(minutes)).num_seconds();
|
||||||
|
|
||||||
let uptime_paragraph = Paragraph::new(Text::from(format!(
|
let uptime_paragraph = Paragraph::new(Text::from(format!(
|
||||||
"Uptime: {}d {:0width$}:{:0width$}:{:0width$}",
|
"Uptime: {days}d {hours:0width$}:{minutes:0width$}:{seconds:0width$}",
|
||||||
days,
|
|
||||||
hours,
|
|
||||||
minutes,
|
|
||||||
seconds,
|
|
||||||
width = 2
|
width = 2
|
||||||
)))
|
)))
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
@@ -144,10 +140,10 @@ fn draw_stats_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area: Rec
|
|||||||
total_space,
|
total_space,
|
||||||
} = &disk_space_vec[i];
|
} = &disk_space_vec[i];
|
||||||
let title = format!("Disk {}", i + 1);
|
let title = format!("Disk {}", i + 1);
|
||||||
let ratio = if total_space.as_u64().unwrap() == 0 {
|
let ratio = if *total_space == 0 {
|
||||||
0f64
|
0f64
|
||||||
} else {
|
} 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);
|
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 {
|
let RootFolder {
|
||||||
path, free_space, ..
|
path, free_space, ..
|
||||||
} = &root_folders.items[i];
|
} = &root_folders.items[i];
|
||||||
let space: f64 = convert_to_gb(free_space.as_u64().unwrap());
|
let space: f64 = convert_to_gb(*free_space);
|
||||||
let root_folder_space = Paragraph::new(format!("{}: {:.2} GB free", path.to_owned(), space))
|
let root_folder_space = Paragraph::new(format!("{path}: {space:.2} GB free"))
|
||||||
.block(borderless_block())
|
.block(borderless_block())
|
||||||
.style(style_default());
|
.style(style_default());
|
||||||
|
|
||||||
@@ -193,7 +189,7 @@ fn draw_downloads_context<B: Backend>(f: &mut Frame<'_, B>, app: &App<'_>, area:
|
|||||||
size,
|
size,
|
||||||
..
|
..
|
||||||
} = &downloads_vec[i];
|
} = &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);
|
let download_gauge = line_gauge_with_title(title, percent);
|
||||||
|
|
||||||
f.render_widget(download_gauge, chunks[i]);
|
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 {
|
if time == 0 {
|
||||||
"now".to_owned()
|
"now".to_owned()
|
||||||
} else if time == 1 {
|
} else if time == 1 {
|
||||||
format!("{} minute", time)
|
format!("{time} minute")
|
||||||
} else {
|
} else {
|
||||||
format!("{} minutes", time)
|
format!("{time} minutes")
|
||||||
}
|
}
|
||||||
} else if time / 60 < 24 {
|
} else if time / 60 < 24 {
|
||||||
let hours = time / 60;
|
let hours = time / 60;
|
||||||
if hours == 1 {
|
if hours == 1 {
|
||||||
format!("{} hour", hours)
|
format!("{hours} hour")
|
||||||
} else {
|
} else {
|
||||||
format!("{} hours", hours)
|
format!("{hours} hours")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let days = time / (60 * 24);
|
let days = time / (60 * 24);
|
||||||
if days == 1 {
|
if days == 1 {
|
||||||
format!("{} day", days)
|
format!("{days} day")
|
||||||
} else {
|
} else {
|
||||||
format!("{} days", days)
|
format!("{days} days")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::utils::convert_to_gb;
|
|||||||
#[path = "root_folders_ui_tests.rs"]
|
#[path = "root_folders_ui_tests.rs"]
|
||||||
mod root_folders_ui_tests;
|
mod root_folders_ui_tests;
|
||||||
|
|
||||||
pub(super) struct RootFoldersUi {}
|
pub(super) struct RootFoldersUi;
|
||||||
|
|
||||||
impl DrawUi for RootFoldersUi {
|
impl DrawUi for RootFoldersUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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;
|
} = root_folders;
|
||||||
|
|
||||||
let space: f64 = convert_to_gb(free_space.as_u64().unwrap());
|
let space: f64 = convert_to_gb(*free_space);
|
||||||
|
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
Cell::from(path.to_owned()),
|
Cell::from(path.to_owned()),
|
||||||
Cell::from(format!("{:.2} GB", space)),
|
Cell::from(format!("{space:.2} GB")),
|
||||||
Cell::from(
|
Cell::from(
|
||||||
unmapped_folders
|
unmapped_folders
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ pub(super) const TASK_TABLE_CONSTRAINTS: [Constraint; 5] = [
|
|||||||
Constraint::Percentage(22),
|
Constraint::Percentage(22),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub(super) struct SystemUi {}
|
pub(super) struct SystemUi;
|
||||||
|
|
||||||
impl DrawUi for SystemUi {
|
impl DrawUi for SystemUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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| {
|
|event| {
|
||||||
let queued = convert_to_minutes_hours_days(Utc::now().sub(event.queued).num_minutes());
|
let queued = convert_to_minutes_hours_days(Utc::now().sub(event.queued).num_minutes());
|
||||||
let queued_string = if queued != "now" {
|
let queued_string = if queued != "now" {
|
||||||
format!("{} ago", queued)
|
format!("{queued} ago")
|
||||||
} else {
|
} else {
|
||||||
queued
|
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());
|
convert_to_minutes_hours_days(Utc::now().sub(event.started.unwrap()).num_minutes());
|
||||||
|
|
||||||
if started != "now" {
|
if started != "now" {
|
||||||
format!("{} ago", started)
|
format!("{started} ago")
|
||||||
} else {
|
} else {
|
||||||
started
|
started
|
||||||
}
|
}
|
||||||
@@ -237,14 +237,14 @@ pub(super) struct TaskProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn extract_task_props(task: &Task) -> 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 last_duration = &task.last_duration[..8];
|
||||||
let next_execution =
|
let next_execution =
|
||||||
convert_to_minutes_hours_days((task.next_execution - Utc::now()).num_minutes());
|
convert_to_minutes_hours_days((task.next_execution - Utc::now()).num_minutes());
|
||||||
let last_execution =
|
let last_execution =
|
||||||
convert_to_minutes_hours_days((Utc::now() - task.last_execution).num_minutes());
|
convert_to_minutes_hours_days((Utc::now() - task.last_execution).num_minutes());
|
||||||
let last_execution_string = if last_execution != "now" {
|
let last_execution_string = if last_execution != "now" {
|
||||||
format!("{} ago", last_execution)
|
format!("{last_execution} ago")
|
||||||
} else {
|
} else {
|
||||||
last_execution
|
last_execution
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use crate::ui::{
|
|||||||
#[path = "system_details_ui_tests.rs"]
|
#[path = "system_details_ui_tests.rs"]
|
||||||
mod system_details_ui_tests;
|
mod system_details_ui_tests;
|
||||||
|
|
||||||
pub(super) struct SystemDetailsUi {}
|
pub(super) struct SystemDetailsUi;
|
||||||
|
|
||||||
impl DrawUi for SystemDetailsUi {
|
impl DrawUi for SystemDetailsUi {
|
||||||
fn accepts(route: Route) -> bool {
|
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<'_> {
|
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<'_> {
|
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))
|
.gauge_style(Style::default().fg(COLOR_CYAN))
|
||||||
.line_set(symbols::line::THICK)
|
.line_set(symbols::line::THICK)
|
||||||
.ratio(ratio)
|
.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) {
|
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()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_to_gb(bytes: u64) -> f64 {
|
pub fn convert_to_gb(bytes: i64) -> f64 {
|
||||||
bytes as f64 / 1024f64.powi(3)
|
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 hours = runtime / 60;
|
||||||
let minutes = runtime % 60;
|
let minutes = runtime % 60;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user