Initial commit
This commit is contained in:
147
src/routes/system.rs
Normal file
147
src/routes/system.rs
Normal file
@@ -0,0 +1,147 @@
|
||||
use actix_web::{web, HttpResponse};
|
||||
|
||||
use shanty_db::entities::download_queue::DownloadStatus;
|
||||
use shanty_db::queries;
|
||||
|
||||
use crate::error::ApiError;
|
||||
use crate::state::AppState;
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(web::resource("/status").route(web::get().to(get_status)))
|
||||
.service(web::resource("/index").route(web::post().to(trigger_index)))
|
||||
.service(web::resource("/tag").route(web::post().to(trigger_tag)))
|
||||
.service(web::resource("/organize").route(web::post().to(trigger_organize)))
|
||||
.service(web::resource("/tasks/{id}").route(web::get().to(get_task)))
|
||||
.service(web::resource("/watchlist").route(web::get().to(list_watchlist)))
|
||||
.service(web::resource("/watchlist/{id}").route(web::delete().to(remove_watchlist)))
|
||||
.service(web::resource("/config").route(web::get().to(get_config)));
|
||||
}
|
||||
|
||||
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 tasks = state.tasks.list();
|
||||
|
||||
Ok(HttpResponse::Ok().json(serde_json::json!({
|
||||
"library": summary,
|
||||
"queue": {
|
||||
"pending": pending,
|
||||
"downloading": downloading,
|
||||
},
|
||||
"tasks": tasks,
|
||||
})))
|
||||
}
|
||||
|
||||
async fn trigger_index(
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let task_id = state.tasks.register("index");
|
||||
let state = state.clone();
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let scan_config = shanty_index::ScanConfig {
|
||||
root: state.config.library_path.clone(),
|
||||
dry_run: false,
|
||||
concurrency: 4,
|
||||
};
|
||||
match shanty_index::run_scan(state.db.conn(), &scan_config).await {
|
||||
Ok(stats) => state.tasks.complete(&tid, format!("{stats}")),
|
||||
Err(e) => state.tasks.fail(&tid, e.to_string()),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
||||
}
|
||||
|
||||
async fn trigger_tag(
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let task_id = state.tasks.register("tag");
|
||||
let state = state.clone();
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let mb = match shanty_tag::MusicBrainzClient::new() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
state.tasks.fail(&tid, e.to_string());
|
||||
return;
|
||||
}
|
||||
};
|
||||
let tag_config = shanty_tag::TagConfig {
|
||||
dry_run: false,
|
||||
write_tags: state.config.tagging.write_tags,
|
||||
confidence: state.config.tagging.confidence,
|
||||
};
|
||||
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()),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
||||
}
|
||||
|
||||
async fn trigger_organize(
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let task_id = state.tasks.register("organize");
|
||||
let state = state.clone();
|
||||
let tid = task_id.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let org_config = shanty_org::OrgConfig {
|
||||
target_dir: state.config.library_path.clone(),
|
||||
format: state.config.organization_format.clone(),
|
||||
dry_run: false,
|
||||
copy: false,
|
||||
};
|
||||
match shanty_org::organize_from_db(state.db.conn(), &org_config).await {
|
||||
Ok(stats) => state.tasks.complete(&tid, format!("{stats}")),
|
||||
Err(e) => state.tasks.fail(&tid, e.to_string()),
|
||||
}
|
||||
});
|
||||
|
||||
Ok(HttpResponse::Accepted().json(serde_json::json!({ "task_id": task_id })))
|
||||
}
|
||||
|
||||
async fn get_task(
|
||||
state: web::Data<AppState>,
|
||||
path: web::Path<String>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let id = path.into_inner();
|
||||
match state.tasks.get(&id) {
|
||||
Some(task) => Ok(HttpResponse::Ok().json(task)),
|
||||
None => Err(ApiError::NotFound(format!("task {id}"))),
|
||||
}
|
||||
}
|
||||
|
||||
async fn list_watchlist(
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let items = shanty_watch::list_items(state.db.conn(), None, None).await?;
|
||||
Ok(HttpResponse::Ok().json(items))
|
||||
}
|
||||
|
||||
async fn remove_watchlist(
|
||||
state: web::Data<AppState>,
|
||||
path: web::Path<i32>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let id = path.into_inner();
|
||||
shanty_watch::remove_item(state.db.conn(), id).await?;
|
||||
Ok(HttpResponse::NoContent().finish())
|
||||
}
|
||||
|
||||
async fn get_config(
|
||||
state: web::Data<AppState>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
Ok(HttpResponse::Ok().json(&state.config))
|
||||
}
|
||||
Reference in New Issue
Block a user