feat(network): Support for adding a new series to Sonarr

This commit is contained in:
2024-11-24 13:18:02 -07:00
parent c98828aec7
commit 5ba3f2b1ba
9 changed files with 668 additions and 26 deletions
+144 -8
View File
@@ -9,7 +9,7 @@ use crate::{
servarr_data::{
modals::IndexerTestResultModalItem,
sonarr::{
modals::{EpisodeDetailsModal, SeasonDetailsModal},
modals::{AddSeriesModal, EpisodeDetailsModal, SeasonDetailsModal},
sonarr_data::ActiveSonarrBlock,
},
},
@@ -18,10 +18,10 @@ use crate::{
QualityProfile, QueueEvent, RootFolder, SecurityConfig, Tag, Update,
},
sonarr_models::{
BlocklistResponse, DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode,
IndexerSettings, Series, SonarrCommandBody, SonarrHistoryItem, SonarrHistoryWrapper,
SonarrRelease, SonarrReleaseDownloadBody, SonarrSerdeable, SonarrTask, SonarrTaskName,
SystemStatus,
AddSeriesBody, AddSeriesOptions, AddSeriesSearchResult, BlocklistResponse,
DeleteSeriesParams, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series,
SonarrCommandBody, SonarrHistoryItem, SonarrHistoryWrapper, SonarrRelease,
SonarrReleaseDownloadBody, SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus,
},
stateful_table::StatefulTable,
HorizontallyScrollableText, Route, Scrollable, ScrollableText,
@@ -38,6 +38,7 @@ mod sonarr_network_tests;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum SonarrEvent {
AddRootFolder(Option<String>),
AddSeries(Option<AddSeriesBody>),
AddTag(String),
ClearBlocklist,
DeleteBlocklistItem(Option<i64>),
@@ -120,9 +121,10 @@ impl NetworkResource for SonarrEvent {
SonarrEvent::GetTasks => "/system/task",
SonarrEvent::GetUpdates => "/update",
SonarrEvent::HealthCheck => "/health",
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) | SonarrEvent::DeleteSeries(_) => {
"/series"
}
SonarrEvent::AddSeries(_)
| SonarrEvent::ListSeries
| SonarrEvent::GetSeriesDetails(_)
| SonarrEvent::DeleteSeries(_) => "/series",
SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
SonarrEvent::TestIndexer(_) => "/indexer/test",
SonarrEvent::TestAllIndexers => "/indexer/testall",
@@ -146,6 +148,10 @@ impl<'a, 'b> Network<'a, 'b> {
.add_sonarr_root_folder(path)
.await
.map(SonarrSerdeable::from),
SonarrEvent::AddSeries(body) => self
.add_sonarr_series(body)
.await
.map(SonarrSerdeable::from),
SonarrEvent::AddTag(tag) => self.add_sonarr_tag(tag).await.map(SonarrSerdeable::from),
SonarrEvent::ClearBlocklist => self
.clear_sonarr_blocklist()
@@ -327,6 +333,106 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn add_sonarr_series(
&mut self,
add_series_body_option: Option<AddSeriesBody>,
) -> Result<Value> {
info!("Adding new series to Sonarr");
let event = SonarrEvent::AddSeries(None);
let body = if let Some(add_series_body) = add_series_body_option {
add_series_body
} else {
let tags = self
.app
.lock()
.await
.data
.sonarr_data
.add_series_modal
.as_ref()
.unwrap()
.tags
.text
.clone();
let tag_ids_vec = self.extract_and_add_sonarr_tag_ids_vec(tags).await;
let mut app = self.app.lock().await;
let AddSeriesModal {
root_folder_list,
monitor_list,
quality_profile_list,
language_profile_list,
series_type_list,
use_season_folder,
..
} = app.data.sonarr_data.add_series_modal.as_ref().unwrap();
let season_folder = *use_season_folder;
let (tvdb_id, title) = {
let AddSeriesSearchResult { tvdb_id, title, .. } = app
.data
.sonarr_data
.add_searched_series
.as_ref()
.unwrap()
.current_selection()
.clone();
(tvdb_id, title.text)
};
let quality_profile = quality_profile_list.current_selection();
let quality_profile_id = *app
.data
.sonarr_data
.quality_profile_map
.iter()
.filter(|(_, value)| *value == quality_profile)
.map(|(key, _)| key)
.next()
.unwrap();
let language_profile = language_profile_list.current_selection();
let language_profile_id = *app
.data
.sonarr_data
.language_profiles_map
.iter()
.filter(|(_, value)| *value == language_profile)
.map(|(key, _)| key)
.next()
.unwrap();
let path = root_folder_list.current_selection().path.clone();
let monitor = monitor_list.current_selection().to_string();
let series_type = series_type_list.current_selection().to_string();
app.data.sonarr_data.add_series_modal = None;
AddSeriesBody {
tvdb_id,
title,
monitored: true,
root_folder_path: path,
quality_profile_id,
language_profile_id,
series_type,
season_folder,
tags: tag_ids_vec,
add_options: AddSeriesOptions {
monitor,
search_for_cutoff_unmet_episodes: true,
search_for_missing_episodes: true,
},
}
};
debug!("Add series body: {body:?}");
let request_props = self
.request_props_from(event, RequestMethod::Post, Some(body), None, None)
.await;
self
.handle_request::<AddSeriesBody, Value>(request_props, |_, _| ())
.await
}
async fn add_sonarr_tag(&mut self, tag: String) -> Result<Tag> {
info!("Adding a new Sonarr tag");
let event = SonarrEvent::AddTag(String::new());
@@ -1703,6 +1809,36 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn extract_and_add_sonarr_tag_ids_vec(&mut self, edit_tags: String) -> Vec<i64> {
let tags_map = self.app.lock().await.data.sonarr_data.tags_map.clone();
let tags = edit_tags.clone();
let missing_tags_vec = edit_tags
.split(',')
.filter(|&tag| !tag.is_empty() && tags_map.get_by_right(tag.trim()).is_none())
.collect::<Vec<&str>>();
for tag in missing_tags_vec {
self
.add_sonarr_tag(tag.trim().to_owned())
.await
.expect("Unable to add tag");
}
let app = self.app.lock().await;
tags
.split(',')
.filter(|tag| !tag.is_empty())
.map(|tag| {
*app
.data
.sonarr_data
.tags_map
.get_by_right(tag.trim())
.unwrap()
})
.collect()
}
async fn extract_series_id(&mut self, series_id: Option<i64>) -> (i64, String) {
let series_id = if let Some(id) = series_id {
id