api/src/routes.rs
2025-04-12 22:23:44 -06:00

128 lines
3.4 KiB
Rust
Executable File

use axum::{
Json, debug_handler,
extract::{Query, State},
http::StatusCode,
};
use serde::{Deserialize, Serialize};
use tracing::{error, info};
use crate::{
instance::Instance,
video::{Video, VideoError},
};
#[derive(Debug, Deserialize)]
pub struct ListEntriesQuery {
page: Option<usize>,
}
#[derive(Debug, Serialize)]
pub struct ListEntriesResponse {
videos: Vec<Video>,
page: usize,
per_page: usize,
total: usize,
pages: usize,
}
/// Retrieve video list as JSON (paged)
#[debug_handler]
pub async fn list_entries(
State(state): State<Instance>,
Query(query): Query<ListEntriesQuery>,
) -> Result<Json<ListEntriesResponse>, StatusCode> {
let Ok(videos) = state.fetch_videos().await else {
error!("Could not fetch videos from database!");
return Err(StatusCode::INTERNAL_SERVER_ERROR);
};
let page = query.page.unwrap_or(1).max(1);
let per_page = state.config.videos_per_page;
let total = videos.len();
let pages = (total + per_page - 1).div_ceil(per_page);
let start = per_page * (page - 1);
let end = (start + per_page).min(total);
let videos = if start < total {
videos[start..end].to_vec()
} else {
vec![]
};
Ok(Json(ListEntriesResponse {
videos,
page,
per_page,
total,
pages,
}))
}
#[derive(Debug, Deserialize)]
pub struct UploadVideoQuery {
url: String,
cookie: Option<String>,
}
/// Upload a video to the database
pub async fn upload_video(
State(state): State<Instance>,
Query(query): Query<UploadVideoQuery>,
) -> StatusCode {
let Ok(videos) = state.fetch_videos().await else {
error!("Could not fetch videos from database!");
return StatusCode::INTERNAL_SERVER_ERROR;
};
let new_video = Video::from_url(&query.url, videos.len(), query.cookie.as_deref())
.await
.map_err(|e| match e {
VideoError::InvalidUrl | VideoError::UrlParse(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR,
});
match new_video {
Ok(video) => {
match sqlx::query!(
r#"
INSERT INTO video (
id, url, youtube_id, title, description, author, author_id, author_url,
views, upload_date, likes, dislikes, file_name, file_size, sha256, thumbnail
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
"#,
video.id,
video.url,
video.youtube_id,
video.title,
video.description,
video.author,
video.author_id,
video.author_url,
video.views,
video.upload_date,
video.likes,
video.dislikes,
video.file_name,
video.file_size,
video.sha256,
video.thumbnail,
)
.execute(&state.pool)
.await
{
Ok(result) => {
info!("Inserted video to database successfully! {result:?}");
StatusCode::OK
}
Err(e) => {
error!("Error inserting video to database: {e:?}");
StatusCode::INTERNAL_SERVER_ERROR
}
}
}
Err(status) => status,
}
}