/* This file is part of jellything (https://codeberg.org/metamuffin/jellything) which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2026 metamuffin */ use super::error::MyResult; use crate::{request_info::RequestInfo, responders::cache::CacheControlImage}; use anyhow::Context; use jellycache::HashKey; use jellycommon::routes::u_image; use jellyimport::generate_person_fallback; use rocket::{get, http::ContentType, response::Redirect}; use std::path::PathBuf; use tokio::task::spawn_blocking; pub const AVIF_QUALITY: u32 = 70; pub const AVIF_SPEED: u8 = 5; #[get("/image/?")] pub async fn r_image( ri: RequestInfo<'_>, path: PathBuf, size: Option, ) -> MyResult<(ContentType, CacheControlImage)> { let size = size.unwrap_or(2048); let path = path.to_string_lossy().to_string(); // fit the resolution into a finite set so the maximum cache is finite too. let width = 2usize.pow(size.clamp(128, 2048).ilog2()); let encoded = spawn_blocking(move || { jellytranscoder::image::transcode(&ri.state.cache, &path, AVIF_QUALITY, AVIF_SPEED, width) .context("transcoding asset") }) .await .unwrap()?; Ok((ContentType::AVIF, CacheControlImage(encoded))) } #[get("/image_fallback/person/?")] pub async fn r_image_fallback_person( ri: RequestInfo<'_>, name: &str, size: Option, ) -> MyResult { let path = ri .state .cache .store(format!("fallback/person/{}.image", HashKey(name)), || { generate_person_fallback(name) })?; Ok(Redirect::found(u_image(&path, size.unwrap_or(2048)))) }