feat: Full Lidarr system support for both the CLI and TUI
This commit is contained in:
1 parent
c74d5936d2
commit
8b9467bd39
63 files changed
+4824
-74
No files matched your search
@@ -1,10 +1,14 @@
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
|
||||
use crate::models::lidarr_models::SystemStatus;
|
||||
use crate::models::servarr_models::{DiskSpace, HostConfig, SecurityConfig};
|
||||
use crate::models::lidarr_models::{LidarrTask, LidarrTaskName, SystemStatus};
|
||||
use crate::models::servarr_models::{
|
||||
CommandBody, DiskSpace, HostConfig, LogResponse, QueueEvent, SecurityConfig, Update,
|
||||
};
|
||||
use crate::models::{HorizontallyScrollableText, Scrollable, ScrollableText};
|
||||
use crate::network::lidarr_network::LidarrEvent;
|
||||
use crate::network::{Network, RequestMethod};
|
||||
use anyhow::Result;
|
||||
use indoc::formatdoc;
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "lidarr_system_network_tests.rs"]
|
||||
@@ -26,18 +30,62 @@ impl Network<'_, '_> {
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn get_lidarr_security_config(
|
||||
pub(in crate::network::lidarr_network) async fn get_lidarr_logs(
|
||||
&mut self,
|
||||
) -> Result<SecurityConfig> {
|
||||
info!("Fetching Lidarr security config");
|
||||
let event = LidarrEvent::GetSecurityConfig;
|
||||
events: u64,
|
||||
) -> Result<LogResponse> {
|
||||
info!("Fetching Lidarr logs");
|
||||
let event = LidarrEvent::GetLogs(events);
|
||||
|
||||
let params = format!("pageSize={events}&sortDirection=descending&sortKey=time");
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, Some(params))
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), SecurityConfig>(request_props, |_, _| ())
|
||||
.handle_request::<(), LogResponse>(request_props, |log_response, mut app| {
|
||||
let mut logs = log_response.records;
|
||||
logs.reverse();
|
||||
|
||||
let log_lines = logs
|
||||
.into_iter()
|
||||
.map(|log| {
|
||||
if log.exception.is_some() {
|
||||
HorizontallyScrollableText::from(format!(
|
||||
"{}|{}|{}|{}|{}",
|
||||
log.time,
|
||||
log.level.to_uppercase(),
|
||||
log
|
||||
.logger
|
||||
.as_ref()
|
||||
.expect("logger must exist when exception is present"),
|
||||
log
|
||||
.exception_type
|
||||
.as_ref()
|
||||
.expect("exception_type must exist when exception is present"),
|
||||
log
|
||||
.exception
|
||||
.as_ref()
|
||||
.expect("exception must exist in this branch")
|
||||
))
|
||||
} else {
|
||||
HorizontallyScrollableText::from(format!(
|
||||
"{}|{}|{}|{}",
|
||||
log.time,
|
||||
log.level.to_uppercase(),
|
||||
log.logger.as_ref().expect("logger must exist in log entry"),
|
||||
log
|
||||
.message
|
||||
.as_ref()
|
||||
.expect("message must exist when exception is not present")
|
||||
))
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
app.data.lidarr_data.logs.set_items(log_lines);
|
||||
app.data.lidarr_data.logs.scroll_to_bottom();
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -58,6 +106,42 @@ impl Network<'_, '_> {
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn get_queued_lidarr_events(
|
||||
&mut self,
|
||||
) -> Result<Vec<QueueEvent>> {
|
||||
info!("Fetching Lidarr queued events");
|
||||
let event = LidarrEvent::GetQueuedEvents;
|
||||
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), Vec<QueueEvent>>(request_props, |queued_events_vec, mut app| {
|
||||
app
|
||||
.data
|
||||
.lidarr_data
|
||||
.queued_events
|
||||
.set_items(queued_events_vec);
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn get_lidarr_security_config(
|
||||
&mut self,
|
||||
) -> Result<SecurityConfig> {
|
||||
info!("Fetching Lidarr security config");
|
||||
let event = LidarrEvent::GetSecurityConfig;
|
||||
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), SecurityConfig>(request_props, |_, _| ())
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn get_lidarr_status(
|
||||
&mut self,
|
||||
) -> Result<SystemStatus> {
|
||||
@@ -75,4 +159,120 @@ impl Network<'_, '_> {
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn get_lidarr_tasks(
|
||||
&mut self,
|
||||
) -> Result<Vec<LidarrTask>> {
|
||||
info!("Fetching Lidarr tasks");
|
||||
let event = LidarrEvent::GetTasks;
|
||||
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), Vec<LidarrTask>>(request_props, |tasks_vec, mut app| {
|
||||
app.data.lidarr_data.tasks.set_items(tasks_vec);
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn get_lidarr_updates(
|
||||
&mut self,
|
||||
) -> Result<Vec<Update>> {
|
||||
info!("Fetching Lidarr updates");
|
||||
let event = LidarrEvent::GetUpdates;
|
||||
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), Vec<Update>>(request_props, |updates_vec, mut app| {
|
||||
let latest_installed = if updates_vec
|
||||
.iter()
|
||||
.any(|update| update.latest && update.installed_on.is_some())
|
||||
{
|
||||
"already".to_owned()
|
||||
} else {
|
||||
"not".to_owned()
|
||||
};
|
||||
let updates = updates_vec
|
||||
.into_iter()
|
||||
.map(|update| {
|
||||
let install_status = if update.installed_on.is_some() {
|
||||
if update.installed {
|
||||
" (Currently Installed)".to_owned()
|
||||
} else {
|
||||
" (Previously Installed)".to_owned()
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let vec_to_bullet_points = |vec: Vec<String>| {
|
||||
vec
|
||||
.iter()
|
||||
.map(|change| format!(" * {change}"))
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n")
|
||||
};
|
||||
|
||||
let mut update_info = formatdoc!(
|
||||
"{} - {}{install_status}
|
||||
{}",
|
||||
update.version,
|
||||
update.release_date,
|
||||
"-".repeat(200)
|
||||
);
|
||||
|
||||
if let Some(new_changes) = update.changes.new {
|
||||
let changes = vec_to_bullet_points(new_changes);
|
||||
update_info = formatdoc!(
|
||||
"{update_info}
|
||||
New:
|
||||
{changes}"
|
||||
)
|
||||
}
|
||||
|
||||
if let Some(fixes) = update.changes.fixed {
|
||||
let fixes = vec_to_bullet_points(fixes);
|
||||
update_info = formatdoc!(
|
||||
"{update_info}
|
||||
Fixed:
|
||||
{fixes}"
|
||||
);
|
||||
}
|
||||
|
||||
update_info
|
||||
})
|
||||
.reduce(|version_1, version_2| format!("{version_1}\n\n\n{version_2}"))
|
||||
.unwrap();
|
||||
|
||||
app.data.lidarr_data.updates = ScrollableText::with_string(formatdoc!(
|
||||
"The latest version of Lidarr is {latest_installed} installed
|
||||
|
||||
{updates}"
|
||||
));
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::lidarr_network) async fn start_lidarr_task(
|
||||
&mut self,
|
||||
task: LidarrTaskName,
|
||||
) -> Result<Value> {
|
||||
let event = LidarrEvent::StartTask(task);
|
||||
let task_name = task.to_string();
|
||||
info!("Starting Lidarr task: {task_name}");
|
||||
|
||||
let body = CommandBody { name: task_name };
|
||||
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Post, Some(body), None, None)
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<CommandBody, Value>(request_props, |_, _| ())
|
||||
.await
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user