feat(image): add brat + animated brat image generation
Deploy Scraper / build-and-deploy (push) Canceled after 0s

Ported from Shirokami-API scraper/image/brat.js (v2 path):
- /image/brat - static brat PNG via brat.siputzx.my.id API
- /image/brat/animated - animated brat GIF
Both return raw image bytes with proper Content-Type (image/png, image/gif)
This commit is contained in:
asepharyana
2026-09-01 20:17:32 +07:00
parent 278d4fe32a
commit 4efcf1f0ea
7 changed files with 113 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
//! Axum handlers for image generation endpoints.
//!
//! Returns raw image bytes with the proper Content-Type.
use axum::body::Body;
use axum::extract::Query;
use axum::http::{header, StatusCode};
use axum::response::Response;
use serde::Deserialize;
use crate::application::image as use_cases;
use crate::presentation::error::AppError;
#[derive(Deserialize)]
pub struct BratParams {
pub text: Option<String>,
}
pub async fn brat_handler(Query(params): Query<BratParams>) -> Result<Response, AppError> {
let text = params
.text
.ok_or_else(|| AppError::BadRequest("text parameter is required".into()))?;
let bytes = use_cases::brat(&text).await?;
Ok(Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, "image/png")
.body(Body::from(bytes))
.expect("valid response"))
}
pub async fn brat_animated_handler(Query(params): Query<BratParams>) -> Result<Response, AppError> {
let text = params
.text
.ok_or_else(|| AppError::BadRequest("text parameter is required".into()))?;
let bytes = use_cases::brat_animated(&text).await?;
Ok(Response::builder()
.status(StatusCode::OK)
.header(header::CONTENT_TYPE, "image/gif")
.body(Body::from(bytes))
.expect("valid response"))
}
+1
View File
@@ -2,6 +2,7 @@ pub mod anime;
pub mod anime2;
pub mod downloader;
pub mod health;
pub mod image;
pub mod komik;
pub mod misc;
pub mod proxy;
+9
View File
@@ -349,6 +349,15 @@ pub fn build_router(app_state: Arc<AppState>) -> anyhow::Result<Router> {
"/tool/cek-resi",
axum::routing::get(crate::presentation::handler::tools::cek_resi_handler),
)
// Image routes
.route(
"/image/brat",
axum::routing::get(crate::presentation::handler::image::brat_handler),
)
.route(
"/image/brat/animated",
axum::routing::get(crate::presentation::handler::image::brat_animated_handler),
)
// Health
.route(
"/health",