/* 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) 2025 metamuffin */ use super::error::MyResult; use crate::{ helper::{cache::CacheControlFile, A}, CONF, }; use anyhow::{anyhow, bail, Context}; use jellycommon::{NodeID, PeopleGroup}; use jellyimport::asset_token::AssetInner; use jellylogic::{ assets::{get_node_backdrop, get_node_person_asset, get_node_poster, get_node_thumbnail}, session::Session, }; use log::info; use rocket::{get, http::ContentType, response::Redirect}; use std::path::PathBuf; pub const AVIF_QUALITY: f32 = 50.; pub const AVIF_SPEED: u8 = 5; #[get("/asset/?")] pub async fn r_asset( _session: A, token: &str, width: Option, ) -> MyResult<(ContentType, CacheControlFile)> { let width = width.unwrap_or(2048); let asset = AssetInner::deser(token)?; // if let AssetInner::Federated { host, asset } = asset { // let session = fed.get_session(&host).await?; // let asset = base64::engine::general_purpose::URL_SAFE.encode(asset); // async_cache_file("fed-asset", &asset, |out| async { // session.asset(out, &asset, width).await // }) // .await? // } else let path = { let source = resolve_asset(asset).await.context("resolving asset")?; // fit the resolution into a finite set so the maximum cache is finite too. let width = 2usize.pow(width.clamp(128, 2048).ilog2()); jellytranscoder::image::transcode(&source, AVIF_QUALITY, AVIF_SPEED, width) .await .context("transcoding asset")? }; info!("loading asset from {path:?}"); Ok(( ContentType::AVIF, CacheControlFile::new_cachekey(&path.abs()).await?, )) } pub async fn resolve_asset(asset: AssetInner) -> anyhow::Result { match asset { AssetInner::Cache(c) => Ok(c.abs()), AssetInner::Assets(c) => Ok(CONF.asset_path.join(c)), AssetInner::Media(c) => Ok(c), _ => bail!("wrong asset type"), } } #[get("/n//poster?")] pub async fn r_item_poster( session: A, id: A, width: Option, ) -> MyResult { let asset = get_node_poster(&session.0, id.0)?; Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width)))) } #[get("/n//backdrop?")] pub async fn r_item_backdrop( session: A, id: A, width: Option, ) -> MyResult { let asset = get_node_backdrop(&session.0, id.0)?; Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width)))) } #[get("/n//person//asset?&")] pub async fn r_person_asset( session: A, id: A, index: usize, group: String, width: Option, ) -> MyResult { let group = PeopleGroup::from_str_opt(&group).ok_or(anyhow!("unknown people group"))?; let asset = get_node_person_asset(&session.0, id.0, group, index)?; Ok(Redirect::permanent(rocket::uri!(r_asset(asset.0, width)))) } #[get("/n//thumbnail?&")] pub async fn r_node_thumbnail( session: A, id: A, t: f64, width: Option, ) -> MyResult { let asset = get_node_thumbnail(&session.0, id.0, t).await?; Ok(Redirect::temporary(rocket::uri!(r_asset(asset.0, width)))) }