Fixed agent UI
This commit is contained in:
@@ -82,22 +82,24 @@ pub async fn approve_queue_item(State(state): State<S>, Path(id): Path<Uuid>) ->
|
||||
format!("{}.{}", sanitize_filename(title), ext)
|
||||
};
|
||||
|
||||
match crate::ingest::mover::move_to_storage(
|
||||
&state.config.storage_dir,
|
||||
artist,
|
||||
album,
|
||||
&filename,
|
||||
source,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(storage_path) => {
|
||||
let rel_path = storage_path.to_string_lossy().to_string();
|
||||
match db::approve_and_finalize(&state.pool, id, &rel_path).await {
|
||||
Ok(track_id) => (StatusCode::OK, Json(serde_json::json!({"track_id": track_id}))).into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
let artist_dir = sanitize_filename(artist);
|
||||
let album_dir = sanitize_filename(album);
|
||||
let dest = state.config.storage_dir.join(&artist_dir).join(&album_dir).join(&filename);
|
||||
|
||||
let storage_path = if dest.exists() && !source.exists() {
|
||||
// File already moved (e.g. auto-approved earlier but DB not finalized)
|
||||
dest.to_string_lossy().to_string()
|
||||
} else {
|
||||
match crate::ingest::mover::move_to_storage(
|
||||
&state.config.storage_dir, artist, album, &filename, source,
|
||||
).await {
|
||||
Ok(p) => p.to_string_lossy().to_string(),
|
||||
Err(e) => return error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
};
|
||||
|
||||
match db::approve_and_finalize(&state.pool, id, &storage_path).await {
|
||||
Ok(track_id) => (StatusCode::OK, Json(serde_json::json!({"track_id": track_id}))).into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
@@ -144,6 +146,98 @@ pub async fn update_queue_item(
|
||||
}
|
||||
}
|
||||
|
||||
// --- Retry ---
|
||||
|
||||
pub async fn retry_queue_item(State(state): State<S>, Path(id): Path<Uuid>) -> impl IntoResponse {
|
||||
match db::update_pending_status(&state.pool, id, "pending", None).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
// --- Batch operations ---
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct BatchIds {
|
||||
pub ids: Vec<Uuid>,
|
||||
}
|
||||
|
||||
pub async fn batch_approve(State(state): State<S>, Json(body): Json<BatchIds>) -> impl IntoResponse {
|
||||
let mut ok = 0u32;
|
||||
let mut errors = Vec::new();
|
||||
for id in &body.ids {
|
||||
let pt = match db::get_pending(&state.pool, *id).await {
|
||||
Ok(Some(pt)) => pt,
|
||||
Ok(None) => { errors.push(format!("{}: not found", id)); continue; }
|
||||
Err(e) => { errors.push(format!("{}: {}", id, e)); continue; }
|
||||
};
|
||||
|
||||
let artist = pt.norm_artist.as_deref().unwrap_or("Unknown Artist");
|
||||
let album = pt.norm_album.as_deref().unwrap_or("Unknown Album");
|
||||
let title = pt.norm_title.as_deref().unwrap_or("Unknown Title");
|
||||
let source = std::path::Path::new(&pt.inbox_path);
|
||||
let ext = source.extension().and_then(|e| e.to_str()).unwrap_or("flac");
|
||||
let track_num = pt.norm_track_number.unwrap_or(0);
|
||||
|
||||
let filename = if track_num > 0 {
|
||||
format!("{:02} - {}.{}", track_num, sanitize_filename(title), ext)
|
||||
} else {
|
||||
format!("{}.{}", sanitize_filename(title), ext)
|
||||
};
|
||||
|
||||
let artist_dir = sanitize_filename(artist);
|
||||
let album_dir = sanitize_filename(album);
|
||||
let dest = state.config.storage_dir.join(&artist_dir).join(&album_dir).join(&filename);
|
||||
|
||||
let rel_path = if dest.exists() && !source.exists() {
|
||||
dest.to_string_lossy().to_string()
|
||||
} else {
|
||||
match crate::ingest::mover::move_to_storage(
|
||||
&state.config.storage_dir, artist, album, &filename, source,
|
||||
).await {
|
||||
Ok(p) => p.to_string_lossy().to_string(),
|
||||
Err(e) => { errors.push(format!("{}: {}", id, e)); continue; }
|
||||
}
|
||||
};
|
||||
|
||||
match db::approve_and_finalize(&state.pool, *id, &rel_path).await {
|
||||
Ok(_) => ok += 1,
|
||||
Err(e) => errors.push(format!("{}: {}", id, e)),
|
||||
}
|
||||
}
|
||||
(StatusCode::OK, Json(serde_json::json!({"approved": ok, "errors": errors}))).into_response()
|
||||
}
|
||||
|
||||
pub async fn batch_reject(State(state): State<S>, Json(body): Json<BatchIds>) -> impl IntoResponse {
|
||||
let mut ok = 0u32;
|
||||
for id in &body.ids {
|
||||
if db::update_pending_status(&state.pool, *id, "rejected", None).await.is_ok() {
|
||||
ok += 1;
|
||||
}
|
||||
}
|
||||
(StatusCode::OK, Json(serde_json::json!({"rejected": ok}))).into_response()
|
||||
}
|
||||
|
||||
pub async fn batch_retry(State(state): State<S>, Json(body): Json<BatchIds>) -> impl IntoResponse {
|
||||
let mut ok = 0u32;
|
||||
for id in &body.ids {
|
||||
if db::update_pending_status(&state.pool, *id, "pending", None).await.is_ok() {
|
||||
ok += 1;
|
||||
}
|
||||
}
|
||||
(StatusCode::OK, Json(serde_json::json!({"retried": ok}))).into_response()
|
||||
}
|
||||
|
||||
pub async fn batch_delete(State(state): State<S>, Json(body): Json<BatchIds>) -> impl IntoResponse {
|
||||
let mut ok = 0u32;
|
||||
for id in &body.ids {
|
||||
if db::delete_pending(&state.pool, *id).await.unwrap_or(false) {
|
||||
ok += 1;
|
||||
}
|
||||
}
|
||||
(StatusCode::OK, Json(serde_json::json!({"deleted": ok}))).into_response()
|
||||
}
|
||||
|
||||
// --- Artists ---
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
||||
Reference in New Issue
Block a user