Implemented the ability to view indexers
This commit is contained in:
+15
-1
@@ -4,7 +4,7 @@ use strum::IntoEnumIterator;
|
|||||||
|
|
||||||
use crate::app::{App, Route};
|
use crate::app::{App, Route};
|
||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
AddMovieSearchResult, Collection, CollectionMovie, Credit, DiskSpace, DownloadRecord,
|
AddMovieSearchResult, Collection, CollectionMovie, Credit, DiskSpace, DownloadRecord, Indexer,
|
||||||
MinimumAvailability, Monitor, Movie, MovieHistoryItem, QueueEvent, Release, ReleaseField,
|
MinimumAvailability, Monitor, Movie, MovieHistoryItem, QueueEvent, Release, ReleaseField,
|
||||||
RootFolder, Task,
|
RootFolder, Task,
|
||||||
};
|
};
|
||||||
@@ -36,6 +36,7 @@ pub struct RadarrData<'a> {
|
|||||||
pub root_folder_list: StatefulList<RootFolder>,
|
pub root_folder_list: StatefulList<RootFolder>,
|
||||||
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 quality_profile_map: BiMap<u64, String>,
|
pub quality_profile_map: BiMap<u64, String>,
|
||||||
pub tags_map: BiMap<u64, String>,
|
pub tags_map: BiMap<u64, String>,
|
||||||
pub movie_details: ScrollableText,
|
pub movie_details: ScrollableText,
|
||||||
@@ -261,6 +262,7 @@ impl<'a> Default for RadarrData<'a> {
|
|||||||
selected_block: BlockSelectionState::default(),
|
selected_block: BlockSelectionState::default(),
|
||||||
filtered_movies: StatefulTable::default(),
|
filtered_movies: StatefulTable::default(),
|
||||||
downloads: StatefulTable::default(),
|
downloads: StatefulTable::default(),
|
||||||
|
indexers: StatefulTable::default(),
|
||||||
quality_profile_map: BiMap::default(),
|
quality_profile_map: BiMap::default(),
|
||||||
tags_map: BiMap::default(),
|
tags_map: BiMap::default(),
|
||||||
file_details: String::default(),
|
file_details: String::default(),
|
||||||
@@ -318,6 +320,12 @@ impl<'a> Default for RadarrData<'a> {
|
|||||||
help: "",
|
help: "",
|
||||||
contextual_help: Some("<a> add | <del> delete | <r> refresh"),
|
contextual_help: Some("<a> add | <del> delete | <r> refresh"),
|
||||||
},
|
},
|
||||||
|
TabRoute {
|
||||||
|
title: "Indexers",
|
||||||
|
route: ActiveRadarrBlock::Indexers.into(),
|
||||||
|
help: "",
|
||||||
|
contextual_help: Some("<r> refresh"),
|
||||||
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "System",
|
title: "System",
|
||||||
route: ActiveRadarrBlock::System.into(),
|
route: ActiveRadarrBlock::System.into(),
|
||||||
@@ -410,6 +418,7 @@ pub enum ActiveRadarrBlock {
|
|||||||
FileInfo,
|
FileInfo,
|
||||||
FilterCollections,
|
FilterCollections,
|
||||||
FilterMovies,
|
FilterMovies,
|
||||||
|
Indexers,
|
||||||
ManualSearch,
|
ManualSearch,
|
||||||
ManualSearchSortPrompt,
|
ManualSearchSortPrompt,
|
||||||
ManualSearchConfirmPrompt,
|
ManualSearchConfirmPrompt,
|
||||||
@@ -573,6 +582,11 @@ impl<'a> App<'a> {
|
|||||||
.dispatch_network_event(RadarrEvent::GetDownloads.into())
|
.dispatch_network_event(RadarrEvent::GetDownloads.into())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
ActiveRadarrBlock::Indexers => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetIndexers.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
ActiveRadarrBlock::System => {
|
ActiveRadarrBlock::System => {
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetTasks.into())
|
.dispatch_network_event(RadarrEvent::GetTasks.into())
|
||||||
|
|||||||
+32
-3
@@ -273,6 +273,7 @@ mod tests {
|
|||||||
assert_eq!(radarr_data.selected_block, BlockSelectionState::default());
|
assert_eq!(radarr_data.selected_block, BlockSelectionState::default());
|
||||||
assert!(radarr_data.filtered_movies.items.is_empty());
|
assert!(radarr_data.filtered_movies.items.is_empty());
|
||||||
assert!(radarr_data.downloads.items.is_empty());
|
assert!(radarr_data.downloads.items.is_empty());
|
||||||
|
assert!(radarr_data.indexers.items.is_empty());
|
||||||
assert!(radarr_data.quality_profile_map.is_empty());
|
assert!(radarr_data.quality_profile_map.is_empty());
|
||||||
assert!(radarr_data.tags_map.is_empty());
|
assert!(radarr_data.tags_map.is_empty());
|
||||||
assert!(radarr_data.file_details.is_empty());
|
assert!(radarr_data.file_details.is_empty());
|
||||||
@@ -306,7 +307,7 @@ mod tests {
|
|||||||
assert!(!radarr_data.delete_movie_files);
|
assert!(!radarr_data.delete_movie_files);
|
||||||
assert!(!radarr_data.add_list_exclusion);
|
assert!(!radarr_data.add_list_exclusion);
|
||||||
|
|
||||||
assert_eq!(radarr_data.main_tabs.tabs.len(), 5);
|
assert_eq!(radarr_data.main_tabs.tabs.len(), 6);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[0].title, "Library");
|
assert_str_eq!(radarr_data.main_tabs.tabs[0].title, "Library");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -348,14 +349,25 @@ mod tests {
|
|||||||
Some("<a> add | <del> delete | <r> refresh")
|
Some("<a> add | <del> delete | <r> refresh")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "System");
|
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "Indexers");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[4].route,
|
radarr_data.main_tabs.tabs[4].route,
|
||||||
ActiveRadarrBlock::System.into()
|
ActiveRadarrBlock::Indexers.into()
|
||||||
);
|
);
|
||||||
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[4].contextual_help,
|
radarr_data.main_tabs.tabs[4].contextual_help,
|
||||||
|
Some("<r> refresh")
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "System");
|
||||||
|
assert_eq!(
|
||||||
|
radarr_data.main_tabs.tabs[5].route,
|
||||||
|
ActiveRadarrBlock::System.into()
|
||||||
|
);
|
||||||
|
assert!(radarr_data.main_tabs.tabs[5].help.is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
radarr_data.main_tabs.tabs[5].contextual_help,
|
||||||
Some("<t> open tasks | <z> open queue | <l> open logs | <u> open updates | <r> refresh")
|
Some("<t> open tasks | <z> open queue | <l> open logs | <u> open updates | <r> refresh")
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -684,6 +696,23 @@ mod tests {
|
|||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_indexers_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_radarr_block(&ActiveRadarrBlock::Indexers)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetIndexers.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_system_block() {
|
async fn test_dispatch_by_system_block() {
|
||||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_up(),
|
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_up(),
|
||||||
|
ActiveRadarrBlock::Indexers => self.app.data.radarr_data.indexers.scroll_up(),
|
||||||
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_up(),
|
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_up(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -145,6 +146,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_down(),
|
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_down(),
|
||||||
|
ActiveRadarrBlock::Indexers => self.app.data.radarr_data.indexers.scroll_down(),
|
||||||
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_down(),
|
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_down(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -179,6 +181,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_to_top(),
|
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_to_top(),
|
||||||
|
ActiveRadarrBlock::Indexers => self.app.data.radarr_data.indexers.scroll_to_top(),
|
||||||
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_to_top(),
|
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_to_top(),
|
||||||
ActiveRadarrBlock::SearchMovie | ActiveRadarrBlock::SearchCollection => {
|
ActiveRadarrBlock::SearchMovie | ActiveRadarrBlock::SearchCollection => {
|
||||||
self.app.data.radarr_data.search.scroll_home()
|
self.app.data.radarr_data.search.scroll_home()
|
||||||
@@ -220,6 +223,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_to_bottom(),
|
ActiveRadarrBlock::Downloads => self.app.data.radarr_data.downloads.scroll_to_bottom(),
|
||||||
|
ActiveRadarrBlock::Indexers => self.app.data.radarr_data.indexers.scroll_to_bottom(),
|
||||||
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_to_bottom(),
|
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_to_bottom(),
|
||||||
ActiveRadarrBlock::SearchMovie | ActiveRadarrBlock::SearchCollection => {
|
ActiveRadarrBlock::SearchMovie | ActiveRadarrBlock::SearchCollection => {
|
||||||
self.app.data.radarr_data.search.reset_offset()
|
self.app.data.radarr_data.search.reset_offset()
|
||||||
@@ -257,6 +261,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
| ActiveRadarrBlock::Downloads
|
| ActiveRadarrBlock::Downloads
|
||||||
| ActiveRadarrBlock::Collections
|
| ActiveRadarrBlock::Collections
|
||||||
| ActiveRadarrBlock::RootFolders
|
| ActiveRadarrBlock::RootFolders
|
||||||
|
| ActiveRadarrBlock::Indexers
|
||||||
| ActiveRadarrBlock::System => match self.key {
|
| ActiveRadarrBlock::System => match self.key {
|
||||||
_ if *self.key == DEFAULT_KEYBINDINGS.left.key => {
|
_ if *self.key == DEFAULT_KEYBINDINGS.left.key => {
|
||||||
self.app.data.radarr_data.main_tabs.previous();
|
self.app.data.radarr_data.main_tabs.previous();
|
||||||
@@ -521,6 +526,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
|
ActiveRadarrBlock::Indexers => match self.key {
|
||||||
|
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
ActiveRadarrBlock::Collections => match self.key {
|
ActiveRadarrBlock::Collections => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.search.key => {
|
_ if *key == DEFAULT_KEYBINDINGS.search.key => {
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ mod tests {
|
|||||||
mod test_handle_scroll_up_and_down {
|
mod test_handle_scroll_up_and_down {
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::models::radarr_models::{DownloadRecord, RootFolder};
|
use crate::models::radarr_models::{DownloadRecord, Indexer, RootFolder};
|
||||||
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -75,6 +75,16 @@ mod tests {
|
|||||||
title
|
title
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_iterable_scroll!(
|
||||||
|
test_indexers_scroll,
|
||||||
|
RadarrHandler,
|
||||||
|
indexers,
|
||||||
|
simple_stateful_iterable_vec!(Indexer, String, protocol),
|
||||||
|
ActiveRadarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
protocol
|
||||||
|
);
|
||||||
|
|
||||||
test_iterable_scroll!(
|
test_iterable_scroll!(
|
||||||
test_root_folders_scroll,
|
test_root_folders_scroll,
|
||||||
RadarrHandler,
|
RadarrHandler,
|
||||||
@@ -89,7 +99,7 @@ mod tests {
|
|||||||
mod test_handle_home_end {
|
mod test_handle_home_end {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::models::radarr_models::{DownloadRecord, RootFolder};
|
use crate::models::radarr_models::{DownloadRecord, Indexer, RootFolder};
|
||||||
use crate::{
|
use crate::{
|
||||||
extended_stateful_iterable_vec, test_iterable_home_and_end, test_text_box_home_end_keys,
|
extended_stateful_iterable_vec, test_iterable_home_and_end, test_text_box_home_end_keys,
|
||||||
};
|
};
|
||||||
@@ -150,6 +160,16 @@ mod tests {
|
|||||||
title
|
title
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_iterable_home_and_end!(
|
||||||
|
test_indexers_home_end,
|
||||||
|
RadarrHandler,
|
||||||
|
indexers,
|
||||||
|
extended_stateful_iterable_vec!(Indexer, String, protocol),
|
||||||
|
ActiveRadarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
protocol
|
||||||
|
);
|
||||||
|
|
||||||
test_iterable_home_and_end!(
|
test_iterable_home_and_end!(
|
||||||
test_root_folders_home_end,
|
test_root_folders_home_end,
|
||||||
RadarrHandler,
|
RadarrHandler,
|
||||||
@@ -250,7 +270,8 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::System)]
|
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::System)]
|
||||||
#[case(ActiveRadarrBlock::System, 4, ActiveRadarrBlock::RootFolders)]
|
#[case(ActiveRadarrBlock::System, 5, ActiveRadarrBlock::Indexers)]
|
||||||
|
#[case(ActiveRadarrBlock::Indexers, 4, ActiveRadarrBlock::RootFolders)]
|
||||||
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::Collections)]
|
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::Collections)]
|
||||||
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::Downloads)]
|
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::Downloads)]
|
||||||
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Movies)]
|
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Movies)]
|
||||||
@@ -281,8 +302,9 @@ mod tests {
|
|||||||
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::Downloads)]
|
#[case(ActiveRadarrBlock::Movies, 0, ActiveRadarrBlock::Downloads)]
|
||||||
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Collections)]
|
#[case(ActiveRadarrBlock::Downloads, 1, ActiveRadarrBlock::Collections)]
|
||||||
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::RootFolders)]
|
#[case(ActiveRadarrBlock::Collections, 2, ActiveRadarrBlock::RootFolders)]
|
||||||
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::System)]
|
#[case(ActiveRadarrBlock::RootFolders, 3, ActiveRadarrBlock::Indexers)]
|
||||||
#[case(ActiveRadarrBlock::System, 4, ActiveRadarrBlock::Movies)]
|
#[case(ActiveRadarrBlock::Indexers, 4, ActiveRadarrBlock::System)]
|
||||||
|
#[case(ActiveRadarrBlock::System, 5, ActiveRadarrBlock::Movies)]
|
||||||
fn test_radarr_tab_right(
|
fn test_radarr_tab_right(
|
||||||
#[case] active_radarr_block: ActiveRadarrBlock,
|
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||||
#[case] index: usize,
|
#[case] index: usize,
|
||||||
@@ -963,6 +985,7 @@ mod tests {
|
|||||||
ActiveRadarrBlock::Movies,
|
ActiveRadarrBlock::Movies,
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
|
ActiveRadarrBlock::Indexers,
|
||||||
ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
ActiveRadarrBlock::System
|
ActiveRadarrBlock::System
|
||||||
)]
|
)]
|
||||||
|
|||||||
+337
-289
@@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter};
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Number;
|
use serde_json::{Number, Value};
|
||||||
use strum_macros::{Display, EnumIter};
|
use strum_macros::{Display, EnumIter};
|
||||||
|
|
||||||
use crate::models::HorizontallyScrollableText;
|
use crate::models::HorizontallyScrollableText;
|
||||||
@@ -12,86 +12,47 @@ use crate::models::HorizontallyScrollableText;
|
|||||||
#[path = "radarr_models_tests.rs"]
|
#[path = "radarr_models_tests.rs"]
|
||||||
mod radarr_models_tests;
|
mod radarr_models_tests;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
#[derive(Default, Serialize, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DiskSpace {
|
pub struct AddMovieBody {
|
||||||
pub free_space: Number,
|
pub tmdb_id: u64,
|
||||||
pub total_space: Number,
|
pub title: String,
|
||||||
}
|
pub root_folder_path: String,
|
||||||
|
pub quality_profile_id: u64,
|
||||||
#[derive(Deserialize, Debug)]
|
pub minimum_availability: String,
|
||||||
#[serde(rename_all = "camelCase")]
|
pub monitored: bool,
|
||||||
pub struct SystemStatus {
|
pub tags: Vec<u64>,
|
||||||
pub version: String,
|
pub add_options: AddOptions,
|
||||||
pub start_time: DateTime<Utc>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, Eq, PartialEq)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RootFolder {
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub id: Number,
|
|
||||||
pub path: String,
|
|
||||||
pub accessible: bool,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub free_space: Number,
|
|
||||||
pub unmapped_folders: Option<Vec<UnmappedFolder>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct UnmappedFolder {
|
|
||||||
pub name: String,
|
|
||||||
pub path: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
#[derivative(Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Movie {
|
pub struct AddMovieSearchResult {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub id: Number,
|
pub tmdb_id: Number,
|
||||||
pub title: HorizontallyScrollableText,
|
pub title: HorizontallyScrollableText,
|
||||||
pub original_language: Language,
|
pub original_language: Language,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub size_on_disk: Number,
|
|
||||||
pub status: String,
|
pub status: String,
|
||||||
pub overview: String,
|
pub overview: String,
|
||||||
pub path: String,
|
|
||||||
pub studio: String,
|
|
||||||
pub genres: Vec<String>,
|
pub genres: Vec<String>,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub year: Number,
|
pub year: Number,
|
||||||
pub monitored: bool,
|
|
||||||
pub has_file: bool,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub runtime: Number,
|
pub runtime: Number,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub tmdb_id: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub quality_profile_id: Number,
|
|
||||||
pub minimum_availability: MinimumAvailability,
|
|
||||||
pub certification: Option<String>,
|
|
||||||
pub tags: Vec<Number>,
|
|
||||||
pub ratings: RatingsList,
|
pub ratings: RatingsList,
|
||||||
pub movie_file: Option<MovieFile>,
|
|
||||||
pub collection: Option<Collection>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Serialize, Debug, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CollectionMovie {
|
pub struct AddOptions {
|
||||||
pub title: HorizontallyScrollableText,
|
pub monitor: String,
|
||||||
pub overview: String,
|
pub search_for_movie: bool,
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
}
|
||||||
pub year: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
#[derive(Default, Serialize, Debug)]
|
||||||
pub runtime: Number,
|
pub struct AddRootFolderBody {
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
pub path: String,
|
||||||
pub tmdb_id: Number,
|
|
||||||
pub genres: Vec<String>,
|
|
||||||
pub ratings: RatingsList,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)]
|
#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)]
|
||||||
@@ -112,14 +73,148 @@ pub struct Collection {
|
|||||||
pub movies: Option<Vec<CollectionMovie>>,
|
pub movies: Option<Vec<CollectionMovie>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
#[derivative(Default)]
|
#[derivative(Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MovieFile {
|
pub struct CollectionMovie {
|
||||||
pub relative_path: String,
|
pub title: HorizontallyScrollableText,
|
||||||
pub path: String,
|
pub overview: String,
|
||||||
pub date_added: DateTime<Utc>,
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub media_info: Option<MediaInfo>,
|
pub year: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub runtime: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub tmdb_id: Number,
|
||||||
|
pub genres: Vec<String>,
|
||||||
|
pub ratings: RatingsList,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Derivative, Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct CommandBody {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Credit {
|
||||||
|
pub person_name: String,
|
||||||
|
pub character: Option<String>,
|
||||||
|
pub department: Option<String>,
|
||||||
|
pub job: Option<String>,
|
||||||
|
#[serde(rename(deserialize = "type"))]
|
||||||
|
pub credit_type: CreditType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, PartialEq, Eq, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum CreditType {
|
||||||
|
#[default]
|
||||||
|
Cast,
|
||||||
|
Crew,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DiskSpace {
|
||||||
|
pub free_space: Number,
|
||||||
|
pub total_space: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DownloadRecord {
|
||||||
|
pub title: String,
|
||||||
|
pub status: String,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub id: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub movie_id: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub size: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub sizeleft: Number,
|
||||||
|
pub output_path: Option<HorizontallyScrollableText>,
|
||||||
|
pub indexer: String,
|
||||||
|
pub download_client: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Debug)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct DownloadsResponse {
|
||||||
|
pub records: Vec<DownloadRecord>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Indexer {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub id: Number,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub implementation: Option<String>,
|
||||||
|
pub implementation_name: Option<String>,
|
||||||
|
pub config_contract: Option<String>,
|
||||||
|
pub supports_rss: bool,
|
||||||
|
pub supports_search: bool,
|
||||||
|
pub fields: Option<Vec<IndexerField>>,
|
||||||
|
pub enable_rss: bool,
|
||||||
|
pub enable_automatic_search: bool,
|
||||||
|
pub enable_interactive_search: bool,
|
||||||
|
pub protocol: String,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub priority: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub download_client_id: Number,
|
||||||
|
pub tags: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct IndexerField {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub order: Number,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub label: Option<String>,
|
||||||
|
pub value: Option<Value>,
|
||||||
|
pub advanced: bool,
|
||||||
|
pub select_options: Option<Vec<IndexerSelectOption>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct IndexerSelectOption {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub value: Number,
|
||||||
|
pub name: Option<String>,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub order: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
|
pub struct Language {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Log {
|
||||||
|
pub time: DateTime<Utc>,
|
||||||
|
pub exception: Option<String>,
|
||||||
|
pub exception_type: Option<String>,
|
||||||
|
pub level: String,
|
||||||
|
pub logger: Option<String>,
|
||||||
|
pub message: Option<String>,
|
||||||
|
pub method: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Debug, Eq, PartialEq)]
|
||||||
|
pub struct LogResponse {
|
||||||
|
pub records: Vec<Log>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
#[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -146,206 +241,6 @@ pub struct MediaInfo {
|
|||||||
pub scan_type: String,
|
pub scan_type: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct RatingsList {
|
|
||||||
pub imdb: Option<Rating>,
|
|
||||||
pub tmdb: Option<Rating>,
|
|
||||||
pub rotten_tomatoes: Option<Rating>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
pub struct Rating {
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub value: Number,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct DownloadsResponse {
|
|
||||||
pub records: Vec<DownloadRecord>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct DownloadRecord {
|
|
||||||
pub title: String,
|
|
||||||
pub status: String,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub id: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub movie_id: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub size: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub sizeleft: Number,
|
|
||||||
pub output_path: Option<HorizontallyScrollableText>,
|
|
||||||
pub indexer: String,
|
|
||||||
pub download_client: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
pub struct QualityProfile {
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub id: Number,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
pub struct Tag {
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub id: Number,
|
|
||||||
pub label: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct MovieHistoryItem {
|
|
||||||
pub source_title: HorizontallyScrollableText,
|
|
||||||
pub quality: QualityWrapper,
|
|
||||||
pub languages: Vec<Language>,
|
|
||||||
pub date: DateTime<Utc>,
|
|
||||||
pub event_type: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
|
||||||
pub struct Language {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
|
||||||
pub struct Quality {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
|
||||||
pub struct QualityWrapper {
|
|
||||||
pub quality: Quality,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, PartialEq, Eq, Clone, Debug)]
|
|
||||||
#[serde(rename_all = "lowercase")]
|
|
||||||
pub enum CreditType {
|
|
||||||
#[default]
|
|
||||||
Cast,
|
|
||||||
Crew,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Clone, Debug, PartialEq, Eq)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Credit {
|
|
||||||
pub person_name: String,
|
|
||||||
pub character: Option<String>,
|
|
||||||
pub department: Option<String>,
|
|
||||||
pub job: Option<String>,
|
|
||||||
#[serde(rename(deserialize = "type"))]
|
|
||||||
pub credit_type: CreditType,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Release {
|
|
||||||
pub guid: String,
|
|
||||||
pub protocol: String,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub age: Number,
|
|
||||||
pub title: HorizontallyScrollableText,
|
|
||||||
pub indexer: String,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub indexer_id: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub size: Number,
|
|
||||||
pub rejected: bool,
|
|
||||||
pub rejections: Option<Vec<String>>,
|
|
||||||
pub seeders: Option<Number>,
|
|
||||||
pub leechers: Option<Number>,
|
|
||||||
pub languages: Option<Vec<Language>>,
|
|
||||||
pub quality: QualityWrapper,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, Display)]
|
|
||||||
pub enum ReleaseField {
|
|
||||||
#[default]
|
|
||||||
Source,
|
|
||||||
Age,
|
|
||||||
Rejected,
|
|
||||||
Title,
|
|
||||||
Indexer,
|
|
||||||
Size,
|
|
||||||
Peers,
|
|
||||||
Language,
|
|
||||||
Quality,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Debug)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct AddMovieBody {
|
|
||||||
pub tmdb_id: u64,
|
|
||||||
pub title: String,
|
|
||||||
pub root_folder_path: String,
|
|
||||||
pub quality_profile_id: u64,
|
|
||||||
pub minimum_availability: String,
|
|
||||||
pub monitored: bool,
|
|
||||||
pub tags: Vec<u64>,
|
|
||||||
pub add_options: AddOptions,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Debug, PartialEq, Eq)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct AddOptions {
|
|
||||||
pub monitor: String,
|
|
||||||
pub search_for_movie: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Debug)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct ReleaseDownloadBody {
|
|
||||||
pub guid: String,
|
|
||||||
pub indexer_id: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct AddMovieSearchResult {
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub tmdb_id: Number,
|
|
||||||
pub title: HorizontallyScrollableText,
|
|
||||||
pub original_language: Language,
|
|
||||||
pub status: String,
|
|
||||||
pub overview: String,
|
|
||||||
pub genres: Vec<String>,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub year: Number,
|
|
||||||
#[derivative(Default(value = "Number::from(0)"))]
|
|
||||||
pub runtime: Number,
|
|
||||||
pub ratings: RatingsList,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Debug)]
|
|
||||||
pub struct AddRootFolderBody {
|
|
||||||
pub path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Derivative, Serialize, Debug)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct MovieCommandBody {
|
|
||||||
pub name: String,
|
|
||||||
pub movie_ids: Vec<u64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Derivative, Serialize, Debug)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct CommandBody {
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter)]
|
#[derive(Serialize, Deserialize, Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum MinimumAvailability {
|
pub enum MinimumAvailability {
|
||||||
@@ -408,21 +303,181 @@ impl Monitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Clone, Debug, Eq, PartialEq)]
|
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[derivative(Default)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Log {
|
pub struct Movie {
|
||||||
pub time: DateTime<Utc>,
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub exception: Option<String>,
|
pub id: Number,
|
||||||
pub exception_type: Option<String>,
|
pub title: HorizontallyScrollableText,
|
||||||
pub level: String,
|
pub original_language: Language,
|
||||||
pub logger: Option<String>,
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
pub message: Option<String>,
|
pub size_on_disk: Number,
|
||||||
pub method: Option<String>,
|
pub status: String,
|
||||||
|
pub overview: String,
|
||||||
|
pub path: String,
|
||||||
|
pub studio: String,
|
||||||
|
pub genres: Vec<String>,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub year: Number,
|
||||||
|
pub monitored: bool,
|
||||||
|
pub has_file: bool,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub runtime: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub tmdb_id: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub quality_profile_id: Number,
|
||||||
|
pub minimum_availability: MinimumAvailability,
|
||||||
|
pub certification: Option<String>,
|
||||||
|
pub tags: Vec<Number>,
|
||||||
|
pub ratings: RatingsList,
|
||||||
|
pub movie_file: Option<MovieFile>,
|
||||||
|
pub collection: Option<Collection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Debug, Eq, PartialEq)]
|
#[derive(Default, Derivative, Serialize, Debug)]
|
||||||
pub struct LogResponse {
|
#[serde(rename_all = "camelCase")]
|
||||||
pub records: Vec<Log>,
|
pub struct MovieCommandBody {
|
||||||
|
pub name: String,
|
||||||
|
pub movie_ids: Vec<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Derivative, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct MovieFile {
|
||||||
|
pub relative_path: String,
|
||||||
|
pub path: String,
|
||||||
|
pub date_added: DateTime<Utc>,
|
||||||
|
pub media_info: Option<MediaInfo>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct MovieHistoryItem {
|
||||||
|
pub source_title: HorizontallyScrollableText,
|
||||||
|
pub quality: QualityWrapper,
|
||||||
|
pub languages: Vec<Language>,
|
||||||
|
pub date: DateTime<Utc>,
|
||||||
|
pub event_type: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
|
pub struct Quality {
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Debug)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
pub struct QualityProfile {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub id: Number,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
|
pub struct QualityWrapper {
|
||||||
|
pub quality: Quality,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct QueueEvent {
|
||||||
|
pub trigger: String,
|
||||||
|
pub name: String,
|
||||||
|
pub command_name: String,
|
||||||
|
pub status: String,
|
||||||
|
pub queued: DateTime<Utc>,
|
||||||
|
pub started: Option<DateTime<Utc>>,
|
||||||
|
pub ended: Option<DateTime<Utc>>,
|
||||||
|
pub duration: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
pub struct Rating {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub value: Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RatingsList {
|
||||||
|
pub imdb: Option<Rating>,
|
||||||
|
pub tmdb: Option<Rating>,
|
||||||
|
pub rotten_tomatoes: Option<Rating>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Derivative, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Release {
|
||||||
|
pub guid: String,
|
||||||
|
pub protocol: String,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub age: Number,
|
||||||
|
pub title: HorizontallyScrollableText,
|
||||||
|
pub indexer: String,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub indexer_id: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub size: Number,
|
||||||
|
pub rejected: bool,
|
||||||
|
pub rejections: Option<Vec<String>>,
|
||||||
|
pub seeders: Option<Number>,
|
||||||
|
pub leechers: Option<Number>,
|
||||||
|
pub languages: Option<Vec<Language>>,
|
||||||
|
pub quality: QualityWrapper,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Serialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ReleaseDownloadBody {
|
||||||
|
pub guid: String,
|
||||||
|
pub indexer_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, EnumIter, Display)]
|
||||||
|
pub enum ReleaseField {
|
||||||
|
#[default]
|
||||||
|
Source,
|
||||||
|
Age,
|
||||||
|
Rejected,
|
||||||
|
Title,
|
||||||
|
Indexer,
|
||||||
|
Size,
|
||||||
|
Peers,
|
||||||
|
Language,
|
||||||
|
Quality,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RootFolder {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub id: Number,
|
||||||
|
pub path: String,
|
||||||
|
pub accessible: bool,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub free_space: Number,
|
||||||
|
pub unmapped_folders: Option<Vec<UnmappedFolder>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct SystemStatus {
|
||||||
|
pub version: String,
|
||||||
|
pub start_time: DateTime<Utc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Debug)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
pub struct Tag {
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub id: Number,
|
||||||
|
pub label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Derivative, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -438,17 +493,10 @@ pub struct Task {
|
|||||||
pub next_execution: DateTime<Utc>,
|
pub next_execution: DateTime<Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)]
|
||||||
#[serde(rename_all = "camelCase")]
|
pub struct UnmappedFolder {
|
||||||
pub struct QueueEvent {
|
|
||||||
pub trigger: String,
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub command_name: String,
|
pub path: String,
|
||||||
pub status: String,
|
|
||||||
pub queued: DateTime<Utc>,
|
|
||||||
pub started: Option<DateTime<Utc>>,
|
|
||||||
pub ended: Option<DateTime<Utc>>,
|
|
||||||
pub duration: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
|||||||
+724
-703
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@ mod test {
|
|||||||
|
|
||||||
use crate::app::radarr::ActiveRadarrBlock;
|
use crate::app::radarr::ActiveRadarrBlock;
|
||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
CollectionMovie, Language, MediaInfo, MinimumAvailability, Monitor, MovieFile, Quality,
|
CollectionMovie, IndexerField, IndexerSelectOption, Language, MediaInfo, MinimumAvailability,
|
||||||
QualityWrapper, Rating, RatingsList,
|
Monitor, MovieFile, Quality, QualityWrapper, Rating, RatingsList,
|
||||||
};
|
};
|
||||||
use crate::models::HorizontallyScrollableText;
|
use crate::models::HorizontallyScrollableText;
|
||||||
use crate::App;
|
use crate::App;
|
||||||
@@ -854,6 +854,71 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_indexers_event() {
|
||||||
|
let indexers_response_json = json!([{
|
||||||
|
"enableRss": true,
|
||||||
|
"enableAutomaticSearch": true,
|
||||||
|
"enableInteractiveSearch": true,
|
||||||
|
"supportsRss": true,
|
||||||
|
"supportsSearch": true,
|
||||||
|
"protocol": "torrent",
|
||||||
|
"priority": 25,
|
||||||
|
"downloadClientId": 0,
|
||||||
|
"name": "Test Indexer",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"order": 0,
|
||||||
|
"name": "valueIsString",
|
||||||
|
"label": "Value Is String",
|
||||||
|
"value": "hello",
|
||||||
|
"advanced": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 1,
|
||||||
|
"name": "emptyValueWithSelectOptions",
|
||||||
|
"label": "Empty Value With Select Options",
|
||||||
|
"advanced": true,
|
||||||
|
"selectOptions": [
|
||||||
|
{
|
||||||
|
"value": -2,
|
||||||
|
"name": "Original",
|
||||||
|
"order": 0,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"order": 2,
|
||||||
|
"name": "valueIsAnArray",
|
||||||
|
"label": "Value is an array",
|
||||||
|
"value": [1, 2],
|
||||||
|
"advanced": false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"implementationName": "Torznab",
|
||||||
|
"implementation": "Torznab",
|
||||||
|
"configContract": "TorznabSettings",
|
||||||
|
"tags": ["test_tag"],
|
||||||
|
"id": 1
|
||||||
|
}]);
|
||||||
|
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexers_response_json),
|
||||||
|
RadarrEvent::GetIndexers.resource(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let network = Network::new(reqwest::Client::new(), &app_arc);
|
||||||
|
|
||||||
|
network.handle_radarr_event(RadarrEvent::GetIndexers).await;
|
||||||
|
|
||||||
|
async_server.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app_arc.lock().await.data.radarr_data.indexers.items,
|
||||||
|
vec![indexer()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_get_queued_events_event() {
|
async fn test_handle_get_queued_events_event() {
|
||||||
let queued_events_json = json!([{
|
let queued_events_json = json!([{
|
||||||
@@ -2125,4 +2190,53 @@ mod test {
|
|||||||
credit_type: CreditType::Crew,
|
credit_type: CreditType::Crew,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn indexer() -> Indexer {
|
||||||
|
Indexer {
|
||||||
|
enable_rss: true,
|
||||||
|
enable_automatic_search: true,
|
||||||
|
enable_interactive_search: true,
|
||||||
|
supports_rss: true,
|
||||||
|
supports_search: true,
|
||||||
|
protocol: "torrent".to_owned(),
|
||||||
|
priority: Number::from(25),
|
||||||
|
download_client_id: Number::from(0),
|
||||||
|
name: Some("Test Indexer".to_owned()),
|
||||||
|
implementation_name: Some("Torznab".to_owned()),
|
||||||
|
implementation: Some("Torznab".to_owned()),
|
||||||
|
config_contract: Some("TorznabSettings".to_owned()),
|
||||||
|
tags: Some(vec!["test_tag".to_owned()]),
|
||||||
|
id: Number::from(1),
|
||||||
|
fields: Some(vec![
|
||||||
|
IndexerField {
|
||||||
|
order: Number::from(0),
|
||||||
|
name: Some("valueIsString".to_owned()),
|
||||||
|
label: Some("Value Is String".to_owned()),
|
||||||
|
value: Some(json!("hello")),
|
||||||
|
advanced: false,
|
||||||
|
select_options: None,
|
||||||
|
},
|
||||||
|
IndexerField {
|
||||||
|
order: Number::from(1),
|
||||||
|
name: Some("emptyValueWithSelectOptions".to_owned()),
|
||||||
|
label: Some("Empty Value With Select Options".to_owned()),
|
||||||
|
value: None,
|
||||||
|
advanced: true,
|
||||||
|
select_options: Some(vec![IndexerSelectOption {
|
||||||
|
value: Number::from(-2),
|
||||||
|
name: Some("Original".to_owned()),
|
||||||
|
order: Number::from(0),
|
||||||
|
}]),
|
||||||
|
},
|
||||||
|
IndexerField {
|
||||||
|
order: Number::from(2),
|
||||||
|
name: Some("valueIsAnArray".to_owned()),
|
||||||
|
label: Some("Value is an array".to_owned()),
|
||||||
|
value: Some(json!([1, 2])),
|
||||||
|
advanced: false,
|
||||||
|
select_options: None,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
use tui::backend::Backend;
|
||||||
|
use tui::layout::{Constraint, Rect};
|
||||||
|
use tui::text::Text;
|
||||||
|
use tui::widgets::{Cell, Row};
|
||||||
|
use tui::Frame;
|
||||||
|
|
||||||
|
use crate::app::radarr::ActiveRadarrBlock;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::models::radarr_models::Indexer;
|
||||||
|
use crate::models::Route;
|
||||||
|
use crate::ui::utils::{layout_block_top_border, style_failure, style_primary, style_success};
|
||||||
|
use crate::ui::{draw_table, DrawUi, TableProps};
|
||||||
|
|
||||||
|
pub(super) struct IndexersUi {}
|
||||||
|
|
||||||
|
impl DrawUi for IndexersUi {
|
||||||
|
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||||
|
if matches!(
|
||||||
|
*app.get_current_route(),
|
||||||
|
Route::Radarr(ActiveRadarrBlock::Indexers, _)
|
||||||
|
) {
|
||||||
|
draw_indexers(f, app, content_rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_indexers<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect) {
|
||||||
|
draw_table(
|
||||||
|
f,
|
||||||
|
area,
|
||||||
|
layout_block_top_border(),
|
||||||
|
TableProps {
|
||||||
|
content: &mut app.data.radarr_data.indexers,
|
||||||
|
table_headers: vec![
|
||||||
|
"Indexer",
|
||||||
|
"RSS",
|
||||||
|
"Automatic Search",
|
||||||
|
"Interactive Search",
|
||||||
|
"Priority",
|
||||||
|
],
|
||||||
|
constraints: vec![
|
||||||
|
Constraint::Ratio(1, 5),
|
||||||
|
Constraint::Ratio(1, 5),
|
||||||
|
Constraint::Ratio(1, 5),
|
||||||
|
Constraint::Ratio(1, 5),
|
||||||
|
Constraint::Ratio(1, 5),
|
||||||
|
],
|
||||||
|
help: app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.main_tabs
|
||||||
|
.get_active_tab_contextual_help(),
|
||||||
|
},
|
||||||
|
|indexer: &'_ Indexer| {
|
||||||
|
let Indexer {
|
||||||
|
name,
|
||||||
|
enable_rss,
|
||||||
|
enable_automatic_search,
|
||||||
|
enable_interactive_search,
|
||||||
|
priority,
|
||||||
|
..
|
||||||
|
} = indexer;
|
||||||
|
let bool_to_text = |flag: bool| {
|
||||||
|
if flag {
|
||||||
|
return ("Enabled", style_success());
|
||||||
|
}
|
||||||
|
|
||||||
|
("Disabled", style_failure())
|
||||||
|
};
|
||||||
|
|
||||||
|
let (rss_text, rss_style) = bool_to_text(*enable_rss);
|
||||||
|
let mut rss = Text::from(rss_text);
|
||||||
|
rss.patch_style(rss_style);
|
||||||
|
|
||||||
|
let (auto_search_text, auto_search_style) = bool_to_text(*enable_automatic_search);
|
||||||
|
let mut automatic_search = Text::from(auto_search_text);
|
||||||
|
automatic_search.patch_style(auto_search_style);
|
||||||
|
|
||||||
|
let (interactive_search_text, interactive_search_style) =
|
||||||
|
bool_to_text(*enable_interactive_search);
|
||||||
|
let mut interactive_search = Text::from(interactive_search_text);
|
||||||
|
interactive_search.patch_style(interactive_search_style);
|
||||||
|
|
||||||
|
Row::new(vec![
|
||||||
|
Cell::from(name.clone().unwrap_or_default()),
|
||||||
|
Cell::from(rss),
|
||||||
|
Cell::from(automatic_search),
|
||||||
|
Cell::from(interactive_search),
|
||||||
|
Cell::from(priority.as_u64().unwrap().to_string()),
|
||||||
|
])
|
||||||
|
.style(style_primary())
|
||||||
|
},
|
||||||
|
app.is_loading,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ use crate::models::Route;
|
|||||||
use crate::ui::draw_selectable_list;
|
use crate::ui::draw_selectable_list;
|
||||||
use crate::ui::draw_tabs;
|
use crate::ui::draw_tabs;
|
||||||
use crate::ui::loading;
|
use crate::ui::loading;
|
||||||
|
use crate::ui::radarr_ui::indexers_ui::IndexersUi;
|
||||||
use crate::ui::radarr_ui::system_details_ui::SystemDetailsUi;
|
use crate::ui::radarr_ui::system_details_ui::SystemDetailsUi;
|
||||||
use crate::ui::radarr_ui::system_ui::SystemUi;
|
use crate::ui::radarr_ui::system_ui::SystemUi;
|
||||||
use crate::ui::radarr_ui::{
|
use crate::ui::radarr_ui::{
|
||||||
@@ -44,6 +45,7 @@ mod delete_movie_ui;
|
|||||||
mod downloads_ui;
|
mod downloads_ui;
|
||||||
mod edit_collection_ui;
|
mod edit_collection_ui;
|
||||||
mod edit_movie_ui;
|
mod edit_movie_ui;
|
||||||
|
mod indexers_ui;
|
||||||
mod library_ui;
|
mod library_ui;
|
||||||
mod movie_details_ui;
|
mod movie_details_ui;
|
||||||
mod radarr_ui_utils;
|
mod radarr_ui_utils;
|
||||||
@@ -72,6 +74,7 @@ impl DrawUi for RadarrUi {
|
|||||||
ActiveRadarrBlock::Downloads
|
ActiveRadarrBlock::Downloads
|
||||||
| ActiveRadarrBlock::DeleteDownloadPrompt
|
| ActiveRadarrBlock::DeleteDownloadPrompt
|
||||||
| ActiveRadarrBlock::UpdateDownloadsPrompt => DownloadsUi::draw(f, app, content_rect),
|
| ActiveRadarrBlock::UpdateDownloadsPrompt => DownloadsUi::draw(f, app, content_rect),
|
||||||
|
ActiveRadarrBlock::Indexers => IndexersUi::draw(f, app, content_rect),
|
||||||
ActiveRadarrBlock::RootFolders
|
ActiveRadarrBlock::RootFolders
|
||||||
| ActiveRadarrBlock::AddRootFolderPrompt
|
| ActiveRadarrBlock::AddRootFolderPrompt
|
||||||
| ActiveRadarrBlock::DeleteRootFolderPrompt => RootFoldersUi::draw(f, app, content_rect),
|
| ActiveRadarrBlock::DeleteRootFolderPrompt => RootFoldersUi::draw(f, app, content_rect),
|
||||||
|
|||||||
Reference in New Issue
Block a user