Reworked agent UI. Artist management form.
All checks were successful
Publish Metadata Agent Image (dev) / build-and-push-image (push) Successful in 1m8s
Publish Web Player Image (dev) / build-and-push-image (push) Successful in 1m9s
Publish Metadata Agent Image / build-and-push-image (push) Successful in 1m7s
Publish Web Player Image / build-and-push-image (push) Successful in 1m10s
Publish Server Image / build-and-push-image (push) Successful in 2m23s
All checks were successful
Publish Metadata Agent Image (dev) / build-and-push-image (push) Successful in 1m8s
Publish Web Player Image (dev) / build-and-push-image (push) Successful in 1m9s
Publish Metadata Agent Image / build-and-push-image (push) Successful in 1m7s
Publish Web Player Image / build-and-push-image (push) Successful in 1m10s
Publish Server Image / build-and-push-image (push) Successful in 2m23s
This commit is contained in:
@@ -143,6 +143,7 @@ pub async fn update_queue_item(
|
||||
track_number: body.norm_track_number,
|
||||
genre: body.norm_genre,
|
||||
featured_artists: body.featured_artists,
|
||||
release_type: None,
|
||||
confidence: Some(1.0), // manual edit = full confidence
|
||||
notes: Some("Manually edited".to_owned()),
|
||||
};
|
||||
@@ -574,6 +575,116 @@ pub async fn search_albums_for_artist(State(state): State<S>, Query(q): Query<Al
|
||||
}
|
||||
}
|
||||
|
||||
// --- Artist full admin form ---
|
||||
|
||||
pub async fn get_artist_full(State(state): State<S>, Path(id): Path<i64>) -> impl IntoResponse {
|
||||
let artist = match db::get_artist_by_id(&state.pool, id).await {
|
||||
Ok(Some(a)) => a,
|
||||
Ok(None) => return error_response(StatusCode::NOT_FOUND, "not found"),
|
||||
Err(e) => return error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
};
|
||||
let (albums, appearances) = tokio::join!(
|
||||
db::get_artist_albums(&state.pool, id),
|
||||
db::get_artist_appearances(&state.pool, id),
|
||||
);
|
||||
// For each album, load tracks
|
||||
let albums = match albums {
|
||||
Ok(a) => a,
|
||||
Err(e) => return error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
};
|
||||
let mut albums_with_tracks = Vec::new();
|
||||
for album in albums {
|
||||
let tracks = db::get_album_tracks_admin(&state.pool, album.id).await.unwrap_or_default();
|
||||
albums_with_tracks.push(serde_json::json!({
|
||||
"id": album.id, "name": album.name, "year": album.year,
|
||||
"release_type": album.release_type, "hidden": album.hidden,
|
||||
"track_count": album.track_count, "tracks": tracks,
|
||||
}));
|
||||
}
|
||||
(StatusCode::OK, Json(serde_json::json!({
|
||||
"artist": artist,
|
||||
"albums": albums_with_tracks,
|
||||
"appearances": appearances.unwrap_or_default(),
|
||||
}))).into_response()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetHiddenBody { pub hidden: bool }
|
||||
|
||||
pub async fn set_track_hidden(State(state): State<S>, Path(id): Path<i64>, Json(b): Json<SetHiddenBody>) -> impl IntoResponse {
|
||||
match db::set_track_hidden(&state.pool, id, b.hidden).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_album_hidden(State(state): State<S>, Path(id): Path<i64>, Json(b): Json<SetHiddenBody>) -> impl IntoResponse {
|
||||
match db::set_album_hidden(&state.pool, id, b.hidden).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_artist_hidden(State(state): State<S>, Path(id): Path<i64>, Json(b): Json<SetHiddenBody>) -> impl IntoResponse {
|
||||
match db::set_artist_hidden(&state.pool, id, b.hidden).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SetReleaseTypeBody { pub release_type: String }
|
||||
|
||||
pub async fn set_album_release_type(State(state): State<S>, Path(id): Path<i64>, Json(b): Json<SetReleaseTypeBody>) -> impl IntoResponse {
|
||||
let valid = ["album","single","ep","compilation","live"];
|
||||
if !valid.contains(&b.release_type.as_str()) {
|
||||
return error_response(StatusCode::BAD_REQUEST, "invalid release_type");
|
||||
}
|
||||
match db::set_album_release_type(&state.pool, id, &b.release_type).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct RenameArtistBody { pub name: String }
|
||||
|
||||
pub async fn rename_artist_api(State(state): State<S>, Path(id): Path<i64>, Json(b): Json<RenameArtistBody>) -> impl IntoResponse {
|
||||
match db::rename_artist_name(&state.pool, id, &b.name).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct AddAppearanceBody { pub track_id: i64 }
|
||||
|
||||
pub async fn add_appearance(State(state): State<S>, Path(artist_id): Path<i64>, Json(b): Json<AddAppearanceBody>) -> impl IntoResponse {
|
||||
match db::add_track_appearance(&state.pool, b.track_id, artist_id).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove_appearance(State(state): State<S>, Path((artist_id, track_id)): Path<(i64, i64)>) -> impl IntoResponse {
|
||||
match db::remove_track_appearance(&state.pool, track_id, artist_id).await {
|
||||
Ok(()) => StatusCode::NO_CONTENT.into_response(),
|
||||
Err(e) => error_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct SearchTracksQuery { #[serde(default)] pub q: String }
|
||||
|
||||
pub async fn search_tracks_feat(State(state): State<S>, Query(q): Query<SearchTracksQuery>) -> impl IntoResponse {
|
||||
match db::search_tracks_for_feat(&state.pool, &q.q).await {
|
||||
Ok(rows) => (StatusCode::OK, Json(serde_json::to_value(
|
||||
rows.iter().map(|(id, title, artist)| serde_json::json!({"id": id, "title": title, "artist_name": artist})).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 {
|
||||
|
||||
Reference in New Issue
Block a user