Better video ID handling + Instance::new improvements

This commit is contained in:
roaming97 2025-04-13 13:21:07 -06:00
parent 3fc3eb8d68
commit 461ccaa4b9
6 changed files with 32 additions and 34 deletions

2
Cargo.lock generated
View File

@ -33,7 +33,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "almond"
name = "almond-api"
version = "0.2.0"
dependencies = [
"axum",

View File

@ -1,5 +1,5 @@
[package]
name = "almond"
name = "almond-api"
version = "0.2.0"
edition = "2024"

View File

@ -4,13 +4,11 @@ use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
use thiserror::Error;
use crate::video::Video;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub host: String,
pub port: u16,
pub password: Option<String>,
pub password: String,
pub videos_per_page: usize,
}
@ -19,7 +17,7 @@ impl Default for Config {
Self {
host: "0.0.0.0".into(),
port: 3000,
password: None,
password: "123456".into(),
videos_per_page: 10,
}
}
@ -36,10 +34,10 @@ pub struct Instance {
pub enum NewInstanceError {
#[error("Failed to open TOML configuration file")]
ConfigLoad(#[from] io::Error),
#[error("Could not parse TOML configuration: {0}")]
#[error("Could not parse TOML configuration")]
ConfigParse(#[from] toml::de::Error),
#[error("Failed to fetch entries from database: {0}")]
Populate(#[from] sqlx::Error),
#[error("Failed to create connection pool")]
PoolConnect(#[from] sqlx::Error),
}
impl Instance {
@ -52,10 +50,4 @@ impl Instance {
Ok(Self { config, pool })
}
pub async fn fetch_videos(&self) -> Result<Vec<Video>, sqlx::Error> {
sqlx::query_as!(Video, "SELECT * FROM video")
.fetch_all(&self.pool)
.await
}
}

View File

@ -3,7 +3,7 @@ use axum::{
routing::{get, post},
};
use instance::Instance;
use routes::{list_entries, upload_video};
use routes::{list_videos, upload_video};
use tokio::signal;
use tracing::info;
@ -30,7 +30,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let address = format!("{}:{}", instance.config.host, instance.config.port);
let almond = Router::new()
.route("/", get(list_entries))
.route("/", get(list_videos))
.route("/upload", post(upload_video))
.with_state(instance);

View File

@ -1,5 +1,5 @@
use axum::{
Json, debug_handler,
Json,
extract::{Query, State},
http::StatusCode,
};
@ -12,12 +12,12 @@ use crate::{
};
#[derive(Debug, Deserialize)]
pub struct ListEntriesQuery {
pub struct ListVideosQuery {
page: Option<usize>,
}
#[derive(Debug, Serialize)]
pub struct ListEntriesResponse {
pub struct ListVideosResponse {
videos: Vec<Video>,
page: usize,
per_page: usize,
@ -26,12 +26,14 @@ pub struct ListEntriesResponse {
}
/// Retrieve video list as JSON (paged)
#[debug_handler]
pub async fn list_entries(
pub async fn list_videos(
State(state): State<Instance>,
Query(query): Query<ListEntriesQuery>,
) -> Result<Json<ListEntriesResponse>, StatusCode> {
let Ok(videos) = state.fetch_videos().await else {
Query(query): Query<ListVideosQuery>,
) -> Result<Json<ListVideosResponse>, StatusCode> {
let Ok(videos) = sqlx::query_as!(Video, "SELECT * FROM video")
.fetch_all(&state.pool)
.await
else {
error!("Could not fetch videos from database!");
return Err(StatusCode::INTERNAL_SERVER_ERROR);
};
@ -50,7 +52,7 @@ pub async fn list_entries(
vec![]
};
Ok(Json(ListEntriesResponse {
Ok(Json(ListVideosResponse {
videos,
page,
per_page,
@ -70,12 +72,18 @@ 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 id = match sqlx::query_scalar!("SELECT MAX(id) FROM video")
.fetch_one(&state.pool)
.await
{
Ok(Some(max_id)) => max_id + 1,
Ok(None) => 0,
Err(_) => {
return StatusCode::INTERNAL_SERVER_ERROR;
}
};
let new_video = Video::from_url(&query.url, videos.len(), query.cookie.as_deref())
let new_video = Video::from_url(&query.url, id, query.cookie.as_deref())
.await
.map_err(|e| match e {
VideoError::InvalidUrl | VideoError::UrlParse(_) => StatusCode::BAD_REQUEST,

View File

@ -95,8 +95,7 @@ impl Video {
Some(query_v.1.to_string())
}
#[allow(clippy::cast_possible_wrap)]
pub async fn from_url(url: &str, id: usize, cookie: Option<&str>) -> Result<Self, VideoError> {
pub async fn from_url(url: &str, id: i64, cookie: Option<&str>) -> Result<Self, VideoError> {
let url = Url::parse(url)?;
info!("Parsed argument as URL");
@ -141,8 +140,6 @@ impl Video {
.unwrap()
};
let id = id as i64;
let url = url.to_string();
let description = format!("{file_stem}.description");
let title = get_info_value("title").to_string();
@ -175,6 +172,7 @@ impl Video {
};
let sha256 = format!("{:x}", Sha3_256::digest(&buffer));
#[allow(clippy::cast_possible_wrap)]
let file_size = buffer.len() as i64;
let author_id = get_info_value("channel_id").to_string();
let author_url = get_info_value("channel_url").to_string();