use axum::{ Json, extract::{Path, Query, State}, }; use pinakes_core::model::MediaId; use uuid::Uuid; use crate::{ dto::{CreateTranscodeRequest, PaginationParams, TranscodeSessionResponse}, error::ApiError, state::AppState, }; #[utoipa::path( post, path = "/api/v1/media/{id}/transcode", tag = "transcode", params(("id" = Uuid, Path, description = "Media item ID")), request_body = CreateTranscodeRequest, responses( (status = 200, description = "Transcode job submitted"), (status = 400, description = "Bad request"), (status = 401, description = "Unauthorized"), (status = 500, description = "Internal server error"), ), security(("bearer_auth" = [])) )] pub async fn start_transcode( State(state): State, Path(id): Path, Json(req): Json, ) -> Result, ApiError> { if req.profile.is_empty() || req.profile.len() > 255 { return Err(ApiError::bad_request("profile must be 1-255 bytes")); } let job_id = state .job_queue .submit(pinakes_core::jobs::JobKind::Transcode { media_id: MediaId(id), profile: req.profile, }) .await; Ok(Json(serde_json::json!({"job_id": job_id.to_string()}))) } #[utoipa::path( get, path = "/api/v1/transcode/{id}", tag = "transcode", params(("id" = Uuid, Path, description = "Transcode session ID")), responses( (status = 200, description = "Transcode session details", body = TranscodeSessionResponse), (status = 401, description = "Unauthorized"), (status = 404, description = "Not found"), ), security(("bearer_auth" = [])) )] pub async fn get_session( State(state): State, Path(id): Path, ) -> Result, ApiError> { let session = state.storage.get_transcode_session(id).await?; Ok(Json(TranscodeSessionResponse::from(session))) } #[utoipa::path( get, path = "/api/v1/transcode", tag = "transcode", responses( (status = 200, description = "List of transcode sessions", body = Vec), (status = 401, description = "Unauthorized"), ), security(("bearer_auth" = [])) )] pub async fn list_sessions( State(state): State, Query(params): Query, ) -> Result>, ApiError> { let _ = params; // reserved for future filtering let sessions = state.storage.list_transcode_sessions(None).await?; Ok(Json( sessions .into_iter() .map(TranscodeSessionResponse::from) .collect(), )) } #[utoipa::path( delete, path = "/api/v1/transcode/{id}", tag = "transcode", params(("id" = Uuid, Path, description = "Transcode session ID")), responses( (status = 200, description = "Transcode session cancelled"), (status = 401, description = "Unauthorized"), (status = 404, description = "Not found"), ), security(("bearer_auth" = [])) )] pub async fn cancel_session( State(state): State, Path(id): Path, ) -> Result, ApiError> { if let Some(transcode_service) = &state.transcode_service { transcode_service .cancel_transcode(id, &state.storage) .await?; } else { state .storage .update_transcode_status( id, pinakes_core::transcode::TranscodeStatus::Cancelled, 0.0, ) .await?; } Ok(Json(serde_json::json!({"cancelled": true}))) }