use serde_json::Number; use super::modals::{AddAuthorModal, AddReadarrRootFolderModal, BookDetailsModal, EditAuthorModal}; use crate::app::context_clues::{ BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES, }; use crate::app::readarr::readarr_context_clues::{ AUTHOR_DETAILS_CONTEXT_CLUES, AUTHOR_HISTORY_CONTEXT_CLUES, AUTHORS_CONTEXT_CLUES, MANUAL_AUTHOR_SEARCH_CONTEXT_CLUES, }; use crate::models::readarr_models::{BlocklistItem, ReadarrRelease, ReadarrTask}; use crate::models::servarr_data::modals::EditIndexerModal; use crate::models::servarr_models::{IndexerSettings, QueueEvent}; use crate::models::stateful_list::StatefulList; use crate::models::{ BlockSelectionState, HorizontallyScrollableText, Route, ScrollableText, TabRoute, TabState, readarr_models::{AddAuthorSearchResult, Author, Book, DownloadRecord, ReadarrHistoryItem}, servarr_data::modals::IndexerTestResultModalItem, servarr_models::{DiskSpace, Indexer, RootFolder}, stateful_table::StatefulTable, }; use crate::network::readarr_network::ReadarrEvent; use bimap::BiMap; use chrono::{DateTime, Utc}; use itertools::Itertools; use strum::EnumIter; #[cfg(test)] use { super::modals::EditionDetailsModal, crate::models::readarr_models::{ AuthorStatus, BookFile, DownloadStatus, Edition, MediaInfo, MonitorType, NewItemMonitorType, ReadarrHistoryEventType, ReadarrTaskName, }, crate::models::servarr_models::{IndexerField, Quality, QualityWrapper}, crate::models::stateful_table::SortOption, crate::network::servarr_test_utils::{ diskspace, indexer_settings, indexer_test_result, queued_event, }, crate::network::sonarr_network::sonarr_network_test_utils::test_utils::updates, crate::sort_option, serde_json::json, strum::{Display, EnumString, IntoEnumIterator}, }; #[cfg(test)] #[path = "readarr_data_tests.rs"] mod readarr_data_tests; pub struct ReadarrData<'a> { pub add_author_modal: Option, pub add_author_search: Option, pub add_import_list_exclusion: bool, pub add_root_folder_modal: Option, pub add_searched_authors: Option>, pub author_history: StatefulTable, pub author_info_tabs: TabState, pub author_releases: StatefulTable, pub authors: StatefulTable, pub blocklist: StatefulTable, pub book_details_modal: Option, pub books: StatefulTable, pub delete_files: bool, pub disk_space_vec: Vec, pub downloads: StatefulTable, pub edit_author_modal: Option, pub edit_indexer_modal: Option, pub history: StatefulTable, pub indexer_settings: Option, pub indexer_test_all_results: Option>, pub indexer_test_errors: Option, pub indexers: StatefulTable, pub log_details: StatefulList, pub logs: StatefulList, pub main_tabs: TabState, pub metadata_profile_map: BiMap, pub prompt_confirm: bool, pub prompt_confirm_action: Option, pub quality_profile_map: BiMap, pub queued_events: StatefulTable, pub root_folders: StatefulTable, pub selected_block: BlockSelectionState<'a, ActiveReadarrBlock>, pub start_time: DateTime, pub tags_map: BiMap, pub tasks: StatefulTable, pub updates: ScrollableText, pub version: String, } impl ReadarrData<'_> { pub fn reset_delete_preferences(&mut self) { self.delete_files = false; self.add_import_list_exclusion = false; } pub fn reset_author_info_tabs(&mut self) { self.books = StatefulTable::default(); self.author_releases = StatefulTable::default(); self.author_history = StatefulTable::default(); self.author_info_tabs.index = 0; } pub fn tag_ids_to_display(&self, tag_ids: &[Number]) -> String { tag_ids .iter() .filter_map(|id| { let id = id.as_i64()?; self.tags_map.get_by_left(&id).cloned() }) .collect::>() .join(", ") } pub fn sorted_quality_profile_names(&self) -> Vec { self .quality_profile_map .iter() .sorted_by_key(|(id, _)| *id) .map(|(_, name)| name) .cloned() .collect() } pub fn sorted_metadata_profile_names(&self) -> Vec { self .metadata_profile_map .iter() .sorted_by_key(|(id, _)| *id) .map(|(_, name)| name) .cloned() .collect() } } impl<'a> Default for ReadarrData<'a> { fn default() -> ReadarrData<'a> { ReadarrData { add_author_modal: None, add_author_search: None, add_import_list_exclusion: false, add_root_folder_modal: None, add_searched_authors: None, author_history: StatefulTable::default(), author_releases: StatefulTable::default(), authors: StatefulTable::default(), blocklist: StatefulTable::default(), book_details_modal: None, books: StatefulTable::default(), delete_files: false, disk_space_vec: Vec::new(), downloads: StatefulTable::default(), edit_author_modal: None, edit_indexer_modal: None, history: StatefulTable::default(), indexer_settings: None, indexer_test_all_results: None, indexer_test_errors: None, indexers: StatefulTable::default(), log_details: StatefulList::default(), logs: StatefulList::default(), metadata_profile_map: BiMap::new(), prompt_confirm: false, prompt_confirm_action: None, quality_profile_map: BiMap::new(), queued_events: StatefulTable::default(), root_folders: StatefulTable::default(), selected_block: BlockSelectionState::default(), start_time: DateTime::default(), tags_map: BiMap::new(), tasks: StatefulTable::default(), updates: ScrollableText::default(), version: String::new(), main_tabs: TabState::new(vec![ TabRoute { title: "Library".to_string(), route: ActiveReadarrBlock::Authors.into(), contextual_help: Some(&AUTHORS_CONTEXT_CLUES), config: None, }, TabRoute { title: "Downloads".to_string(), route: ActiveReadarrBlock::Downloads.into(), contextual_help: Some(&DOWNLOADS_CONTEXT_CLUES), config: None, }, TabRoute { title: "Blocklist".to_string(), route: ActiveReadarrBlock::Blocklist.into(), contextual_help: Some(&BLOCKLIST_CONTEXT_CLUES), config: None, }, TabRoute { title: "History".to_string(), route: ActiveReadarrBlock::History.into(), contextual_help: Some(&HISTORY_CONTEXT_CLUES), config: None, }, TabRoute { title: "Root Folders".to_string(), route: ActiveReadarrBlock::RootFolders.into(), contextual_help: Some(&ROOT_FOLDERS_CONTEXT_CLUES), config: None, }, TabRoute { title: "Indexers".to_string(), route: ActiveReadarrBlock::Indexers.into(), contextual_help: Some(&INDEXERS_CONTEXT_CLUES), config: None, }, TabRoute { title: "System".to_string(), route: ActiveReadarrBlock::System.into(), contextual_help: Some(&SYSTEM_CONTEXT_CLUES), config: None, }, ]), author_info_tabs: TabState::new(vec![ TabRoute { title: "Books".to_string(), route: ActiveReadarrBlock::AuthorDetails.into(), contextual_help: Some(&AUTHOR_DETAILS_CONTEXT_CLUES), config: None, }, TabRoute { title: "History".to_string(), route: ActiveReadarrBlock::AuthorHistory.into(), contextual_help: Some(&AUTHOR_HISTORY_CONTEXT_CLUES), config: None, }, TabRoute { title: "Author Search".to_string(), route: ActiveReadarrBlock::ManualAuthorSearch.into(), contextual_help: Some(&MANUAL_AUTHOR_SEARCH_CONTEXT_CLUES), config: None, }, ]), } } } #[cfg(test)] impl ReadarrData<'_> { pub fn test_default_fully_populated() -> Self { let quality_profile_map = BiMap::from_iter([(1i64, "Standard".to_owned())]); let metadata_profile_map = BiMap::from_iter([(1i64, "Standard".to_owned())]); let tags_map = BiMap::from_iter([(1i64, "alex".to_owned())]); let root_folder = RootFolder { id: 1, path: "/nfs".to_owned(), accessible: true, free_space: 219902325555200, unmapped_folders: None, }; let quality = QualityWrapper { quality: Quality { name: "EPUB".to_owned(), }, }; let date = DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap()); let author = Author { id: 1, author_name: "Test Author".into(), foreign_author_id: "test-foreign-id".to_owned(), status: AuthorStatus::Continuing, overview: Some("some interesting description of the author".to_owned()), path: "/nfs/books/Test Author".to_owned(), quality_profile_id: 1, metadata_profile_id: 1, monitored: true, monitor_new_items: NewItemMonitorType::All, genres: vec!["science fiction".to_owned()], tags: vec![Number::from(1)], ..Author::default() }; let book = Book { id: 1, title: "Test Book".into(), author_id: 1, foreign_book_id: "test-foreign-book-id".to_owned(), monitored: true, any_edition_ok: true, page_count: Some(288), release_date: Some(date), ..Book::default() }; let readarr_history_item = ReadarrHistoryItem { id: 1, author_id: 1, book_id: 1, source_title: "Test Source Title".into(), quality: quality.clone(), date, event_type: ReadarrHistoryEventType::Grabbed, ..ReadarrHistoryItem::default() }; let torrent_release = ReadarrRelease { guid: "1234".to_owned(), protocol: "torrent".to_owned(), age: 1, title: "Test Torrent Release".into(), author_name: Some("Test Author".to_owned()), book_title: Some("Test Book".to_owned()), indexer: "kickass torrents".to_owned(), indexer_id: 1, size: 1234, rejected: true, rejections: Some(vec!["Unknown quality profile".to_owned()]), seeders: Some(Number::from(2)), leechers: Some(Number::from(1)), quality: quality.clone(), }; let usenet_release = ReadarrRelease { guid: "5678".to_owned(), protocol: "usenet".to_owned(), title: "Test Usenet Release".into(), indexer: "DrunkenSlug".to_owned(), indexer_id: 2, seeders: None, leechers: None, ..torrent_release.clone() }; let blocklist_item = BlocklistItem { id: 1, author_id: 1, book_ids: Some(vec![Number::from(1)]), source_title: "Test Source Title".to_owned(), quality: quality.clone(), date, protocol: "usenet".to_owned(), indexer: "DrunkenSlug".to_owned(), message: "test message".to_owned(), author: author.clone(), }; let download_record = DownloadRecord { title: "Test Download Title".to_owned(), status: DownloadStatus::Downloading, id: 1, book_id: Some(Number::from(1)), author_id: Some(Number::from(1)), size: 3543348019f64, sizeleft: 1771674009f64, output_path: Some("/nfs/books/Test Author".into()), indexer: "kickass torrents".to_owned(), download_client: Some("transmission".to_owned()), }; let indexer = Indexer { id: 1, name: Some("Test Indexer".to_owned()), implementation: Some("Torznab".to_owned()), implementation_name: Some("Torznab".to_owned()), config_contract: Some("TorznabSettings".to_owned()), supports_rss: true, supports_search: true, enable_rss: true, enable_automatic_search: true, enable_interactive_search: true, protocol: "torrent".to_owned(), priority: 25, download_client_id: 0, tags: vec![Number::from(1)], fields: Some(vec![ IndexerField { name: Some("baseUrl".to_owned()), value: Some(json!("https://test.com")), }, IndexerField { name: Some("apiKey".to_owned()), value: Some(json!("")), }, IndexerField { name: Some("seedCriteria.seedRatio".to_owned()), value: Some(json!("1.2")), }, ]), }; let add_author_search_result = AddAuthorSearchResult { foreign_author_id: "test-foreign-id".to_owned(), author_name: "Test Author".into(), status: AuthorStatus::Continuing, overview: Some("some interesting description of the author".to_owned()), genres: vec!["science fiction".to_owned()], ..AddAuthorSearchResult::default() }; let task = ReadarrTask { name: "Backup".to_owned(), task_name: ReadarrTaskName::Backup, interval: 60, last_execution: date, last_duration: "00:00:00.5111547".to_owned(), next_execution: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T22:29:16Z").unwrap()), }; let log_line = "2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|No list items to process"; let mut add_author_modal = AddAuthorModal { tags: "usenet, testing".into(), ..AddAuthorModal::default() }; add_author_modal .monitor_list .set_items(Vec::from_iter(MonitorType::iter())); add_author_modal .monitor_new_items_list .set_items(Vec::from_iter(NewItemMonitorType::iter())); add_author_modal .metadata_profile_list .set_items(vec!["Standard".to_owned()]); add_author_modal .quality_profile_list .set_items(vec!["Standard".to_owned()]); add_author_modal .root_folder_list .set_items(vec![root_folder.clone()]); let mut edit_author_modal = EditAuthorModal { monitored: Some(true), path: "/nfs/books".into(), tags: "alex".into(), ..EditAuthorModal::default() }; edit_author_modal .monitor_list .set_items(NewItemMonitorType::iter().collect()); edit_author_modal .quality_profile_list .set_items(vec!["Standard".to_owned()]); edit_author_modal .metadata_profile_list .set_items(vec!["Standard".to_owned()]); let mut add_root_folder_modal = AddReadarrRootFolderModal { name: "Test Root Folder".into(), path: "/nfs/books".into(), tags: "test".into(), ..AddReadarrRootFolderModal::default() }; add_root_folder_modal .monitor_list .set_items(Vec::from_iter(MonitorType::iter())); add_root_folder_modal .monitor_new_items_list .set_items(Vec::from_iter(NewItemMonitorType::iter())); add_root_folder_modal .quality_profile_list .set_items(vec!["Standard".to_owned()]); add_root_folder_modal .metadata_profile_list .set_items(vec!["Standard".to_owned()]); let edition_details_modal = EditionDetailsModal { edition_details: ScrollableText::with_string( "Title: Test Edition\n\ Format: Hardcover\n\ Language: English\n\ Publisher: DAW Books\n\ Page Count: 288\n\ Release Date: 2023-05-20 00:00:00 UTC\n\ ISBN13: 9780756404079\n\ ASIN: B0043RSJ9S\n\ Ratings: 4.5 (1000 votes)\n\ Monitored: true\n\ Overview: original cover of ISBN 075640407X\r\n\ \r\n\ My name is Kvothe, pronounced nearly the same as \"quothe.\"\r\n\ \r\n\ The Adem call me Maedre: which means The Flame.\r\n" .to_owned(), ), }; let mut book_details_modal = BookDetailsModal { edition_details_modal: Some(edition_details_modal), ..BookDetailsModal::default() }; book_details_modal.editions.set_items(vec![Edition { id: 1, book_id: 1, foreign_edition_id: "test-foreign-edition-id".to_owned(), monitored: true, is_ebook: true, title: "Test Edition".to_owned(), format: Some("Hardcover".to_owned()), publisher: Some("DAW Books".to_owned()), isbn13: Some("9780756404079".to_owned()), asin: Some("B0043RSJ9S".to_owned()), page_count: Some(288), release_date: Some(date), ..Edition::default() }]); book_details_modal.editions.search = Some("edition search".into()); book_details_modal.book_files.set_items(vec![BookFile { id: 1, author_id: 1, book_id: 1, path: "/nfs/books/Test Author/Test Book.epub".to_owned(), size: 3543348019, date_added: date, quality: quality.clone(), media_info: Some(MediaInfo { audio_bit_rate: Some("128 kbps".to_owned()), audio_channels: 2, audio_codec: Some("MP3".to_owned()), audio_bits: Some("16".to_owned()), audio_sample_rate: Some("44100".to_owned()), }), quality_cutoff_not_met: false, }]); book_details_modal .book_history .set_items(vec![readarr_history_item.clone()]); book_details_modal.book_history.search = Some("book history search".into()); book_details_modal.book_history.filter = Some("book history filter".into()); book_details_modal .book_history .sorting(vec![sort_option!(id)]); book_details_modal .book_releases .set_items(vec![torrent_release.clone(), usenet_release.clone()]); book_details_modal .book_releases .sorting(vec![sort_option!(indexer_id)]); let edit_indexer_modal = EditIndexerModal { name: "DrunkenSlug".into(), enable_rss: Some(true), enable_automatic_search: Some(true), enable_interactive_search: Some(true), url: "http://127.0.0.1:9696/1/".into(), api_key: "someApiKey".into(), seed_ratio: "ratio".into(), tags: "25".into(), priority: 1, }; let mut indexer_test_all_results = StatefulTable::default(); indexer_test_all_results.set_items(vec![indexer_test_result()]); let mut readarr_data = ReadarrData { add_author_modal: Some(add_author_modal), add_root_folder_modal: Some(add_root_folder_modal), book_details_modal: Some(book_details_modal), delete_files: true, disk_space_vec: vec![diskspace()], edit_author_modal: Some(edit_author_modal), edit_indexer_modal: Some(edit_indexer_modal), indexer_settings: Some(indexer_settings()), indexer_test_all_results: Some(indexer_test_all_results), indexer_test_errors: Some("error".to_string()), metadata_profile_map, quality_profile_map, start_time: date, tags_map, updates: updates(), version: "1.2.3.4".to_owned(), ..ReadarrData::default() }; readarr_data .author_history .set_items(vec![readarr_history_item.clone()]); readarr_data.author_history.sorting(vec![sort_option!(id)]); readarr_data.author_history.search = Some("author history search".into()); readarr_data.author_history.filter = Some("author history filter".into()); readarr_data .author_releases .set_items(vec![torrent_release, usenet_release]); readarr_data .author_releases .sorting(vec![sort_option!(indexer_id)]); readarr_data.authors.set_items(vec![author]); readarr_data.authors.sorting(vec![SortOption { name: "Name", cmp_fn: Some(|a: &Author, b: &Author| a.author_name.text.cmp(&b.author_name.text)), }]); readarr_data.authors.search = Some("author search".into()); readarr_data.authors.filter = Some("author filter".into()); readarr_data.blocklist.set_items(vec![blocklist_item]); readarr_data.blocklist.sorting(vec![sort_option!(id)]); readarr_data.books.set_items(vec![book]); readarr_data.books.search = Some("book search".into()); readarr_data.downloads.set_items(vec![download_record]); readarr_data.history.set_items(vec![readarr_history_item]); readarr_data.history.sorting(vec![SortOption { name: "Date", cmp_fn: Some(|a: &ReadarrHistoryItem, b: &ReadarrHistoryItem| a.date.cmp(&b.date)), }]); readarr_data.history.search = Some("test search".into()); readarr_data.history.filter = Some("test filter".into()); readarr_data.indexers.set_items(vec![indexer]); readarr_data.root_folders.set_items(vec![root_folder]); readarr_data.queued_events.set_items(vec![queued_event()]); readarr_data.add_author_search = Some("Test Author".into()); let mut add_searched_authors = StatefulTable::default(); add_searched_authors.set_items(vec![add_author_search_result]); readarr_data.add_searched_authors = Some(add_searched_authors); readarr_data.logs.set_items(vec![log_line.into()]); readarr_data.log_details.set_items(vec![log_line.into()]); readarr_data.tasks.set_items(vec![task]); readarr_data } } #[derive(Clone, Copy, PartialEq, Eq, Debug, Default, EnumIter)] #[cfg_attr(test, derive(Display, EnumString))] pub enum ActiveReadarrBlock { #[default] Authors, AddAuthorAlreadyInLibrary, AddAuthorConfirmPrompt, AddAuthorEmptySearchResults, AddAuthorPrompt, AddAuthorSearchInput, AddAuthorSearchResults, AddAuthorSelectMetadataProfile, AddAuthorSelectMonitor, AddAuthorSelectMonitorNewItems, AddAuthorSelectQualityProfile, AddAuthorSelectRootFolder, AddAuthorTagsInput, AddRootFolderConfirmPrompt, AddRootFolderNameInput, AddRootFolderPathInput, AddRootFolderPrompt, AddRootFolderSelectMetadataProfile, AddRootFolderSelectMonitor, AddRootFolderSelectMonitorNewItems, AddRootFolderSelectQualityProfile, AddRootFolderTagsInput, AllIndexerSettingsPrompt, AuthorDetails, AuthorHistory, AuthorHistoryDetails, AuthorHistorySortPrompt, AuthorsSortPrompt, AutomaticallySearchAuthorPrompt, AutomaticallySearchBookPrompt, Blocklist, BlocklistClearAllItemsPrompt, BlocklistItemDetails, BlocklistSortPrompt, BookDetails, BookEditionDetails, BookFileInfo, BookHistory, BookHistoryDetails, BookHistorySortPrompt, DeleteAuthorConfirmPrompt, DeleteAuthorPrompt, DeleteAuthorToggleAddListExclusion, DeleteAuthorToggleDeleteFile, DeleteBlocklistItemPrompt, DeleteBookConfirmPrompt, DeleteBookFilePrompt, DeleteBookPrompt, DeleteBookToggleAddListExclusion, DeleteBookToggleDeleteFile, DeleteDownloadPrompt, DeleteIndexerPrompt, DeleteRootFolderPrompt, Downloads, EditAuthorConfirmPrompt, EditAuthorPathInput, EditAuthorPrompt, EditAuthorSelectMetadataProfile, EditAuthorSelectMonitorNewItems, EditAuthorSelectQualityProfile, EditAuthorTagsInput, EditAuthorToggleMonitored, EditIndexerApiKeyInput, EditIndexerConfirmPrompt, EditIndexerNameInput, EditIndexerPriorityInput, EditIndexerPrompt, EditIndexerSeedRatioInput, EditIndexerTagsInput, EditIndexerToggleEnableAutomaticSearch, EditIndexerToggleEnableInteractiveSearch, EditIndexerToggleEnableRss, EditIndexerUrlInput, FilterAuthorHistory, FilterAuthorHistoryError, FilterAuthors, FilterAuthorsError, FilterBookHistory, FilterBookHistoryError, FilterHistory, FilterHistoryError, History, HistoryItemDetails, HistorySortPrompt, Indexers, IndexerSettingsConfirmPrompt, IndexerSettingsMaximumSizeInput, IndexerSettingsMinimumAgeInput, IndexerSettingsRetentionInput, IndexerSettingsRssSyncIntervalInput, ManualAuthorSearch, ManualAuthorSearchConfirmPrompt, ManualAuthorSearchSortPrompt, ManualBookSearch, ManualBookSearchConfirmPrompt, ManualBookSearchSortPrompt, RootFolders, SearchAuthorHistory, SearchAuthorHistoryError, SearchAuthors, SearchAuthorsError, SearchBookHistory, SearchBookHistoryError, SearchBooks, SearchBooksError, SearchEditions, SearchEditionsError, SearchHistory, SearchHistoryError, System, SystemLogs, SystemQueuedEvents, SystemTasks, SystemTaskStartConfirmPrompt, SystemUpdates, TestAllIndexers, TestIndexer, UpdateAllAuthorsPrompt, UpdateAndScanAuthorPrompt, UpdateDownloadsPrompt, } pub static LIBRARY_BLOCKS: [ActiveReadarrBlock; 7] = [ ActiveReadarrBlock::Authors, ActiveReadarrBlock::AuthorsSortPrompt, ActiveReadarrBlock::FilterAuthors, ActiveReadarrBlock::FilterAuthorsError, ActiveReadarrBlock::SearchAuthors, ActiveReadarrBlock::SearchAuthorsError, ActiveReadarrBlock::UpdateAllAuthorsPrompt, ]; pub static AUTHOR_DETAILS_BLOCKS: [ActiveReadarrBlock; 15] = [ ActiveReadarrBlock::AuthorDetails, ActiveReadarrBlock::AuthorHistory, ActiveReadarrBlock::AuthorHistoryDetails, ActiveReadarrBlock::AuthorHistorySortPrompt, ActiveReadarrBlock::AutomaticallySearchAuthorPrompt, ActiveReadarrBlock::FilterAuthorHistory, ActiveReadarrBlock::FilterAuthorHistoryError, ActiveReadarrBlock::ManualAuthorSearch, ActiveReadarrBlock::ManualAuthorSearchConfirmPrompt, ActiveReadarrBlock::ManualAuthorSearchSortPrompt, ActiveReadarrBlock::SearchBooks, ActiveReadarrBlock::SearchBooksError, ActiveReadarrBlock::SearchAuthorHistory, ActiveReadarrBlock::SearchAuthorHistoryError, ActiveReadarrBlock::UpdateAndScanAuthorPrompt, ]; pub static BOOK_DETAILS_BLOCKS: [ActiveReadarrBlock; 16] = [ ActiveReadarrBlock::BookDetails, ActiveReadarrBlock::BookHistory, ActiveReadarrBlock::BookHistoryDetails, ActiveReadarrBlock::BookHistorySortPrompt, ActiveReadarrBlock::AutomaticallySearchBookPrompt, ActiveReadarrBlock::DeleteBookFilePrompt, ActiveReadarrBlock::FilterBookHistory, ActiveReadarrBlock::FilterBookHistoryError, ActiveReadarrBlock::BookFileInfo, ActiveReadarrBlock::ManualBookSearch, ActiveReadarrBlock::ManualBookSearchConfirmPrompt, ActiveReadarrBlock::ManualBookSearchSortPrompt, ActiveReadarrBlock::SearchBookHistory, ActiveReadarrBlock::SearchBookHistoryError, ActiveReadarrBlock::SearchEditions, ActiveReadarrBlock::SearchEditionsError, ]; pub static EDITION_DETAILS_BLOCKS: [ActiveReadarrBlock; 1] = [ActiveReadarrBlock::BookEditionDetails]; pub static ADD_AUTHOR_BLOCKS: [ActiveReadarrBlock; 12] = [ ActiveReadarrBlock::AddAuthorAlreadyInLibrary, ActiveReadarrBlock::AddAuthorConfirmPrompt, ActiveReadarrBlock::AddAuthorEmptySearchResults, ActiveReadarrBlock::AddAuthorPrompt, ActiveReadarrBlock::AddAuthorSearchInput, ActiveReadarrBlock::AddAuthorSearchResults, ActiveReadarrBlock::AddAuthorSelectMetadataProfile, ActiveReadarrBlock::AddAuthorSelectMonitor, ActiveReadarrBlock::AddAuthorSelectMonitorNewItems, ActiveReadarrBlock::AddAuthorSelectQualityProfile, ActiveReadarrBlock::AddAuthorSelectRootFolder, ActiveReadarrBlock::AddAuthorTagsInput, ]; pub const ADD_AUTHOR_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ActiveReadarrBlock::AddAuthorSelectRootFolder], &[ActiveReadarrBlock::AddAuthorSelectMonitor], &[ActiveReadarrBlock::AddAuthorSelectMonitorNewItems], &[ActiveReadarrBlock::AddAuthorSelectQualityProfile], &[ActiveReadarrBlock::AddAuthorSelectMetadataProfile], &[ActiveReadarrBlock::AddAuthorTagsInput], &[ActiveReadarrBlock::AddAuthorConfirmPrompt], ]; pub static DELETE_AUTHOR_BLOCKS: [ActiveReadarrBlock; 4] = [ ActiveReadarrBlock::DeleteAuthorPrompt, ActiveReadarrBlock::DeleteAuthorConfirmPrompt, ActiveReadarrBlock::DeleteAuthorToggleDeleteFile, ActiveReadarrBlock::DeleteAuthorToggleAddListExclusion, ]; pub const DELETE_AUTHOR_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ActiveReadarrBlock::DeleteAuthorToggleDeleteFile], &[ActiveReadarrBlock::DeleteAuthorToggleAddListExclusion], &[ActiveReadarrBlock::DeleteAuthorConfirmPrompt], ]; pub static DELETE_BOOK_BLOCKS: [ActiveReadarrBlock; 4] = [ ActiveReadarrBlock::DeleteBookPrompt, ActiveReadarrBlock::DeleteBookConfirmPrompt, ActiveReadarrBlock::DeleteBookToggleDeleteFile, ActiveReadarrBlock::DeleteBookToggleAddListExclusion, ]; pub const DELETE_BOOK_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ActiveReadarrBlock::DeleteBookToggleDeleteFile], &[ActiveReadarrBlock::DeleteBookToggleAddListExclusion], &[ActiveReadarrBlock::DeleteBookConfirmPrompt], ]; pub static EDIT_AUTHOR_BLOCKS: [ActiveReadarrBlock; 8] = [ ActiveReadarrBlock::EditAuthorPrompt, ActiveReadarrBlock::EditAuthorConfirmPrompt, ActiveReadarrBlock::EditAuthorPathInput, ActiveReadarrBlock::EditAuthorSelectMetadataProfile, ActiveReadarrBlock::EditAuthorSelectMonitorNewItems, ActiveReadarrBlock::EditAuthorSelectQualityProfile, ActiveReadarrBlock::EditAuthorTagsInput, ActiveReadarrBlock::EditAuthorToggleMonitored, ]; pub const EDIT_AUTHOR_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ActiveReadarrBlock::EditAuthorToggleMonitored], &[ActiveReadarrBlock::EditAuthorSelectMonitorNewItems], &[ActiveReadarrBlock::EditAuthorSelectQualityProfile], &[ActiveReadarrBlock::EditAuthorSelectMetadataProfile], &[ActiveReadarrBlock::EditAuthorPathInput], &[ActiveReadarrBlock::EditAuthorTagsInput], &[ActiveReadarrBlock::EditAuthorConfirmPrompt], ]; pub static ADD_ROOT_FOLDER_BLOCKS: [ActiveReadarrBlock; 9] = [ ActiveReadarrBlock::AddRootFolderPrompt, ActiveReadarrBlock::AddRootFolderConfirmPrompt, ActiveReadarrBlock::AddRootFolderNameInput, ActiveReadarrBlock::AddRootFolderPathInput, ActiveReadarrBlock::AddRootFolderSelectMonitor, ActiveReadarrBlock::AddRootFolderSelectMonitorNewItems, ActiveReadarrBlock::AddRootFolderSelectQualityProfile, ActiveReadarrBlock::AddRootFolderSelectMetadataProfile, ActiveReadarrBlock::AddRootFolderTagsInput, ]; pub const ADD_ROOT_FOLDER_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ActiveReadarrBlock::AddRootFolderNameInput], &[ActiveReadarrBlock::AddRootFolderPathInput], &[ActiveReadarrBlock::AddRootFolderSelectMonitor], &[ActiveReadarrBlock::AddRootFolderSelectMonitorNewItems], &[ActiveReadarrBlock::AddRootFolderSelectQualityProfile], &[ActiveReadarrBlock::AddRootFolderSelectMetadataProfile], &[ActiveReadarrBlock::AddRootFolderTagsInput], &[ActiveReadarrBlock::AddRootFolderConfirmPrompt], ]; pub static ROOT_FOLDERS_BLOCKS: [ActiveReadarrBlock; 2] = [ ActiveReadarrBlock::RootFolders, ActiveReadarrBlock::DeleteRootFolderPrompt, ]; pub static BLOCKLIST_BLOCKS: [ActiveReadarrBlock; 5] = [ ActiveReadarrBlock::Blocklist, ActiveReadarrBlock::BlocklistItemDetails, ActiveReadarrBlock::DeleteBlocklistItemPrompt, ActiveReadarrBlock::BlocklistClearAllItemsPrompt, ActiveReadarrBlock::BlocklistSortPrompt, ]; pub static DOWNLOADS_BLOCKS: [ActiveReadarrBlock; 3] = [ ActiveReadarrBlock::Downloads, ActiveReadarrBlock::DeleteDownloadPrompt, ActiveReadarrBlock::UpdateDownloadsPrompt, ]; pub static HISTORY_BLOCKS: [ActiveReadarrBlock; 7] = [ ActiveReadarrBlock::History, ActiveReadarrBlock::HistoryItemDetails, ActiveReadarrBlock::HistorySortPrompt, ActiveReadarrBlock::SearchHistory, ActiveReadarrBlock::SearchHistoryError, ActiveReadarrBlock::FilterHistory, ActiveReadarrBlock::FilterHistoryError, ]; pub static EDIT_INDEXER_BLOCKS: [ActiveReadarrBlock; 11] = [ ActiveReadarrBlock::EditIndexerPrompt, ActiveReadarrBlock::EditIndexerConfirmPrompt, ActiveReadarrBlock::EditIndexerApiKeyInput, ActiveReadarrBlock::EditIndexerNameInput, ActiveReadarrBlock::EditIndexerSeedRatioInput, ActiveReadarrBlock::EditIndexerToggleEnableRss, ActiveReadarrBlock::EditIndexerToggleEnableAutomaticSearch, ActiveReadarrBlock::EditIndexerToggleEnableInteractiveSearch, ActiveReadarrBlock::EditIndexerPriorityInput, ActiveReadarrBlock::EditIndexerUrlInput, ActiveReadarrBlock::EditIndexerTagsInput, ]; pub const EDIT_INDEXER_TORRENT_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ ActiveReadarrBlock::EditIndexerNameInput, ActiveReadarrBlock::EditIndexerUrlInput, ], &[ ActiveReadarrBlock::EditIndexerToggleEnableRss, ActiveReadarrBlock::EditIndexerApiKeyInput, ], &[ ActiveReadarrBlock::EditIndexerToggleEnableAutomaticSearch, ActiveReadarrBlock::EditIndexerSeedRatioInput, ], &[ ActiveReadarrBlock::EditIndexerToggleEnableInteractiveSearch, ActiveReadarrBlock::EditIndexerTagsInput, ], &[ ActiveReadarrBlock::EditIndexerPriorityInput, ActiveReadarrBlock::EditIndexerConfirmPrompt, ], &[ ActiveReadarrBlock::EditIndexerConfirmPrompt, ActiveReadarrBlock::EditIndexerConfirmPrompt, ], ]; pub const EDIT_INDEXER_NZB_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ ActiveReadarrBlock::EditIndexerNameInput, ActiveReadarrBlock::EditIndexerUrlInput, ], &[ ActiveReadarrBlock::EditIndexerToggleEnableRss, ActiveReadarrBlock::EditIndexerApiKeyInput, ], &[ ActiveReadarrBlock::EditIndexerToggleEnableAutomaticSearch, ActiveReadarrBlock::EditIndexerTagsInput, ], &[ ActiveReadarrBlock::EditIndexerToggleEnableInteractiveSearch, ActiveReadarrBlock::EditIndexerPriorityInput, ], &[ ActiveReadarrBlock::EditIndexerConfirmPrompt, ActiveReadarrBlock::EditIndexerConfirmPrompt, ], ]; pub static INDEXER_SETTINGS_BLOCKS: [ActiveReadarrBlock; 6] = [ ActiveReadarrBlock::AllIndexerSettingsPrompt, ActiveReadarrBlock::IndexerSettingsConfirmPrompt, ActiveReadarrBlock::IndexerSettingsMaximumSizeInput, ActiveReadarrBlock::IndexerSettingsMinimumAgeInput, ActiveReadarrBlock::IndexerSettingsRetentionInput, ActiveReadarrBlock::IndexerSettingsRssSyncIntervalInput, ]; pub const INDEXER_SETTINGS_SELECTION_BLOCKS: &[&[ActiveReadarrBlock]] = &[ &[ActiveReadarrBlock::IndexerSettingsMinimumAgeInput], &[ActiveReadarrBlock::IndexerSettingsRetentionInput], &[ActiveReadarrBlock::IndexerSettingsMaximumSizeInput], &[ActiveReadarrBlock::IndexerSettingsRssSyncIntervalInput], &[ActiveReadarrBlock::IndexerSettingsConfirmPrompt], ]; pub static INDEXERS_BLOCKS: [ActiveReadarrBlock; 3] = [ ActiveReadarrBlock::Indexers, ActiveReadarrBlock::DeleteIndexerPrompt, ActiveReadarrBlock::TestIndexer, ]; pub static SYSTEM_DETAILS_BLOCKS: [ActiveReadarrBlock; 5] = [ ActiveReadarrBlock::SystemLogs, ActiveReadarrBlock::SystemQueuedEvents, ActiveReadarrBlock::SystemTasks, ActiveReadarrBlock::SystemTaskStartConfirmPrompt, ActiveReadarrBlock::SystemUpdates, ]; impl From for Route { fn from(active_readarr_block: ActiveReadarrBlock) -> Route { Route::Readarr(active_readarr_block, None) } } impl From<(ActiveReadarrBlock, Option)> for Route { fn from(value: (ActiveReadarrBlock, Option)) -> Route { Route::Readarr(value.0, value.1) } }