Added merge
All checks were successful
Publish Metadata Agent Image / build-and-push-image (push) Successful in 1m9s
Publish Web Player Image / build-and-push-image (push) Successful in 1m12s
Publish Server Image / build-and-push-image (push) Successful in 2m18s

This commit is contained in:
2026-03-19 02:36:27 +00:00
parent e1210e6e20
commit a7af27d064
4 changed files with 565 additions and 29 deletions

View File

@@ -480,6 +480,100 @@ pub async fn library_artists(State(state): State<S>, Query(q): Query<LibraryQuer
}
}
// --- Track / Album detail & edit ---
pub async fn get_track(State(state): State<S>, Path(id): Path<i64>) -> impl IntoResponse {
match db::get_track_full(&state.pool, id).await {
Ok(Some(t)) => (StatusCode::OK, Json(serde_json::to_value(t).unwrap())).into_response(),
Ok(None) => error_response(StatusCode::NOT_FOUND, "not found"),
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
}
}
pub async fn update_track(
State(state): State<S>,
Path(id): Path<i64>,
Json(body): Json<db::TrackUpdateFields>,
) -> impl IntoResponse {
match db::update_track_metadata(&state.pool, id, &body).await {
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
}
}
pub async fn get_album_full(State(state): State<S>, Path(id): Path<i64>) -> impl IntoResponse {
match db::get_album_details(&state.pool, id).await {
Ok(Some(a)) => (StatusCode::OK, Json(serde_json::to_value(a).unwrap())).into_response(),
Ok(None) => error_response(StatusCode::NOT_FOUND, "not found"),
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
}
}
#[derive(Deserialize)]
pub struct AlbumUpdateBody {
pub name: String,
pub year: Option<i32>,
pub artist_id: i64,
}
pub async fn update_album_full(
State(state): State<S>,
Path(id): Path<i64>,
Json(body): Json<AlbumUpdateBody>,
) -> impl IntoResponse {
match db::update_album_full(&state.pool, id, &body.name, body.year, body.artist_id).await {
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
}
}
#[derive(Deserialize)]
pub struct ReorderBody {
pub orders: Vec<(i64, i32)>,
}
pub async fn reorder_album_tracks(
State(state): State<S>,
Path(_id): Path<i64>,
Json(body): Json<ReorderBody>,
) -> impl IntoResponse {
match db::reorder_tracks(&state.pool, &body.orders).await {
Ok(()) => StatusCode::NO_CONTENT.into_response(),
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
}
}
pub async fn album_cover(State(state): State<S>, Path(id): Path<i64>) -> impl IntoResponse {
let cover = match db::get_album_cover(&state.pool, id).await {
Ok(Some(c)) => c,
Ok(None) => return StatusCode::NOT_FOUND.into_response(),
Err(e) => return error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
};
match tokio::fs::read(&cover.0).await {
Ok(bytes) => (
[(axum::http::header::CONTENT_TYPE, cover.1)],
bytes,
).into_response(),
Err(_) => StatusCode::NOT_FOUND.into_response(),
}
}
#[derive(Deserialize)]
pub struct AlbumSearchQuery {
#[serde(default)]
pub q: String,
pub artist_id: Option<i64>,
}
pub async fn search_albums_for_artist(State(state): State<S>, Query(q): Query<AlbumSearchQuery>) -> impl IntoResponse {
match db::search_albums_for_artist(&state.pool, &q.q, q.artist_id).await {
Ok(items) => (StatusCode::OK, Json(serde_json::to_value(
items.iter().map(|(id, name)| serde_json::json!({"id": id, "name": name})).collect::<Vec<_>>()
).unwrap())).into_response(),
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
}
}
// --- Helpers ---
fn error_response(status: StatusCode, message: &str) -> axum::response::Response {