Updated the dashboard page
This commit is contained in:
@@ -87,6 +87,17 @@ async fn trigger_process(
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Count total pending for progress reporting
|
||||
let total = shanty_db::queries::downloads::list(
|
||||
state.db.conn(),
|
||||
Some(shanty_db::entities::download_queue::DownloadStatus::Pending),
|
||||
)
|
||||
.await
|
||||
.map(|v| v.len() as u64)
|
||||
.unwrap_or(0);
|
||||
|
||||
state.tasks.update_progress(&tid, 0, total, "Starting downloads...");
|
||||
|
||||
let cookies = state.config.download.cookies_path.clone();
|
||||
let format: shanty_dl::AudioFormat = state.config.download.format.parse().unwrap_or(shanty_dl::AudioFormat::Opus);
|
||||
let source: shanty_dl::SearchSource = state.config.download.search_source.parse().unwrap_or(shanty_dl::SearchSource::YouTubeMusic);
|
||||
|
||||
@@ -21,19 +21,31 @@ async fn get_status(
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let summary = shanty_watch::library_summary(state.db.conn()).await?;
|
||||
let pending = queries::downloads::list(state.db.conn(), Some(DownloadStatus::Pending))
|
||||
.await?
|
||||
.len();
|
||||
let downloading = queries::downloads::list(state.db.conn(), Some(DownloadStatus::Downloading))
|
||||
.await?
|
||||
.len();
|
||||
let pending_items = queries::downloads::list(state.db.conn(), Some(DownloadStatus::Pending)).await?;
|
||||
let downloading_items = queries::downloads::list(state.db.conn(), Some(DownloadStatus::Downloading)).await?;
|
||||
let failed_items = queries::downloads::list(state.db.conn(), Some(DownloadStatus::Failed)).await?;
|
||||
let tasks = state.tasks.list();
|
||||
|
||||
// Combine active/recent download items for the dashboard
|
||||
let mut queue_items = Vec::new();
|
||||
queue_items.extend(downloading_items.iter().cloned());
|
||||
queue_items.extend(pending_items.iter().cloned());
|
||||
queue_items.extend(failed_items.iter().take(5).cloned());
|
||||
|
||||
// Tracks needing metadata (tagging queue)
|
||||
let needs_tagging = queries::tracks::get_needing_metadata(state.db.conn()).await?;
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"library": summary,
|
||||
"queue": {
|
||||
"pending": pending,
|
||||
"downloading": downloading,
|
||||
"pending": pending_items.len(),
|
||||
"downloading": downloading_items.len(),
|
||||
"failed": failed_items.len(),
|
||||
"items": queue_items,
|
||||
},
|
||||
"tagging": {
|
||||
"needs_tagging": needs_tagging.len(),
|
||||
"items": needs_tagging.iter().take(20).collect::<Vec<_>>(),
|
||||
},
|
||||
"tasks": tasks,
|
||||
})))
|
||||
@@ -47,6 +59,7 @@ async fn trigger_index(
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
state.tasks.update_progress(&tid, 0, 0, "Scanning library...");
|
||||
let scan_config = shanty_index::ScanConfig {
|
||||
root: state.config.library_path.clone(),
|
||||
dry_run: false,
|
||||
@@ -69,6 +82,7 @@ async fn trigger_tag(
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
state.tasks.update_progress(&tid, 0, 0, "Preparing tagger...");
|
||||
let mb = match shanty_tag::MusicBrainzClient::new() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
@@ -81,6 +95,7 @@ async fn trigger_tag(
|
||||
write_tags: state.config.tagging.write_tags,
|
||||
confidence: state.config.tagging.confidence,
|
||||
};
|
||||
state.tasks.update_progress(&tid, 0, 0, "Tagging tracks...");
|
||||
match shanty_tag::run_tagging(state.db.conn(), &mb, &tag_config, None).await {
|
||||
Ok(stats) => state.tasks.complete(&tid, format!("{stats}")),
|
||||
Err(e) => state.tasks.fail(&tid, e.to_string()),
|
||||
@@ -98,6 +113,7 @@ async fn trigger_organize(
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
state.tasks.update_progress(&tid, 0, 0, "Organizing files...");
|
||||
let org_config = shanty_org::OrgConfig {
|
||||
target_dir: state.config.library_path.clone(),
|
||||
format: state.config.organization_format.clone(),
|
||||
@@ -105,7 +121,18 @@ async fn trigger_organize(
|
||||
copy: false,
|
||||
};
|
||||
match shanty_org::organize_from_db(state.db.conn(), &org_config).await {
|
||||
Ok(stats) => state.tasks.complete(&tid, format!("{stats}")),
|
||||
Ok(stats) => {
|
||||
// Promote all Downloaded wanted items to Owned
|
||||
let promoted = queries::wanted::promote_downloaded_to_owned(state.db.conn())
|
||||
.await
|
||||
.unwrap_or(0);
|
||||
let msg = if promoted > 0 {
|
||||
format!("{stats} — {promoted} items marked as owned")
|
||||
} else {
|
||||
format!("{stats}")
|
||||
};
|
||||
state.tasks.complete(&tid, msg);
|
||||
}
|
||||
Err(e) => state.tasks.fail(&tid, e.to_string()),
|
||||
}
|
||||
});
|
||||
|
||||
22
src/tasks.rs
22
src/tasks.rs
@@ -4,11 +4,19 @@ use std::sync::Mutex;
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct TaskProgress {
|
||||
pub current: u64,
|
||||
pub total: u64,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct TaskInfo {
|
||||
pub id: String,
|
||||
pub task_type: String,
|
||||
pub status: TaskStatus,
|
||||
pub progress: Option<TaskProgress>,
|
||||
pub started_at: NaiveDateTime,
|
||||
pub completed_at: Option<NaiveDateTime>,
|
||||
pub result: Option<String>,
|
||||
@@ -39,6 +47,7 @@ impl TaskManager {
|
||||
id: id.clone(),
|
||||
task_type: task_type.to_string(),
|
||||
status: TaskStatus::Running,
|
||||
progress: None,
|
||||
started_at: Utc::now().naive_utc(),
|
||||
completed_at: None,
|
||||
result: None,
|
||||
@@ -47,10 +56,22 @@ impl TaskManager {
|
||||
id
|
||||
}
|
||||
|
||||
/// Update progress on a running task.
|
||||
pub fn update_progress(&self, id: &str, current: u64, total: u64, message: &str) {
|
||||
if let Some(task) = self.tasks.lock().unwrap().get_mut(id) {
|
||||
task.progress = Some(TaskProgress {
|
||||
current,
|
||||
total,
|
||||
message: message.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Mark a task as completed with a result string.
|
||||
pub fn complete(&self, id: &str, result: String) {
|
||||
if let Some(task) = self.tasks.lock().unwrap().get_mut(id) {
|
||||
task.status = TaskStatus::Completed;
|
||||
task.progress = None;
|
||||
task.completed_at = Some(Utc::now().naive_utc());
|
||||
task.result = Some(result);
|
||||
}
|
||||
@@ -60,6 +81,7 @@ impl TaskManager {
|
||||
pub fn fail(&self, id: &str, error: String) {
|
||||
if let Some(task) = self.tasks.lock().unwrap().get_mut(id) {
|
||||
task.status = TaskStatus::Failed;
|
||||
task.progress = None;
|
||||
task.completed_at = Some(Utc::now().naive_utc());
|
||||
task.result = Some(error);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user