aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-21 12:09:59 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-21 12:09:59 +0100
commit276da3a082333b2287eca2e0fb2127fc6d1619e5 (patch)
treed0240b797455d571ceb39c1d57dd27d98ea955aa
parent356bc5fe6913e85b18a2cb355f30019cdfd6b146 (diff)
downloadjellything-276da3a082333b2287eca2e0fb2127fc6d1619e5.tar
jellything-276da3a082333b2287eca2e0fb2127fc6d1619e5.tar.bz2
jellything-276da3a082333b2287eca2e0fb2127fc6d1619e5.tar.zst
person fallback images
-rw-r--r--common/src/routes.rs3
-rw-r--r--import/fallback_generator/src/lib.rs4
-rw-r--r--import/src/lib.rs2
-rw-r--r--server/src/routes.rs3
-rw-r--r--server/src/ui/assets.rs20
-rw-r--r--ui/src/components/node_card.rs18
6 files changed, 43 insertions, 7 deletions
diff --git a/common/src/routes.rs b/common/src/routes.rs
index 82a6f45..3ee1e4c 100644
--- a/common/src/routes.rs
+++ b/common/src/routes.rs
@@ -21,6 +21,9 @@ pub fn u_node_slug_player_time(node: &str, time: f64) -> String {
pub fn u_image(path: &str, size: usize) -> String {
format!("/image/{path}?size={size}")
}
+pub fn u_image_fallback_person(name: &str, size: usize) -> String {
+ format!("/image_fallback/person/{name}?size={size}")
+}
pub fn u_node_slug_watched(node: &str, state: &str) -> String {
format!("/n/{node}/watched?state={state}")
}
diff --git a/import/fallback_generator/src/lib.rs b/import/fallback_generator/src/lib.rs
index 60b8cc5..d24356d 100644
--- a/import/fallback_generator/src/lib.rs
+++ b/import/fallback_generator/src/lib.rs
@@ -5,7 +5,7 @@ use image::{DynamicImage, ImageBuffer, ImageEncoder, Rgba, codecs::qoi::QoiEncod
use imageproc::drawing::{draw_text_mut, text_size};
use std::hash::{Hash, Hasher};
-pub fn generate_fallback(name: &str) -> Result<Vec<u8>> {
+pub fn generate_person_fallback(name: &str) -> Result<Vec<u8>> {
let width = 1024;
let height = (width * 1000) / 707;
@@ -102,5 +102,5 @@ fn random_accent(text: &str, y: f32) -> Rgba<f32> {
#[test]
fn generate_fallback_test() {
- generate_fallback("Hello world!").unwrap();
+ generate_person_fallback("Hello world!").unwrap();
}
diff --git a/import/src/lib.rs b/import/src/lib.rs
index 7e402be..ceda42f 100644
--- a/import/src/lib.rs
+++ b/import/src/lib.rs
@@ -42,6 +42,8 @@ use std::{
};
use tokio::{runtime::Handle, sync::Semaphore, task::spawn_blocking};
+pub use jellyimport_fallback_generator::generate_person_fallback;
+
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
pub struct Config {
media_path: PathBuf,
diff --git a/server/src/routes.rs b/server/src/routes.rs
index 4a875f4..334fb39 100644
--- a/server/src/routes.rs
+++ b/server/src/routes.rs
@@ -18,7 +18,7 @@ use crate::{
log::{r_admin_log, r_admin_log_stream},
r_admin_dashboard,
},
- assets::r_image,
+ assets::{r_image, r_image_fallback_person},
error::{r_api_catch, r_catch},
home::r_home,
node::r_node,
@@ -95,6 +95,7 @@ pub(super) fn build_rocket(state: Arc<State>) -> Rocket<Build> {
// r_admin_users,
// r_items,
r_image,
+ r_image_fallback_person,
r_assets_font,
r_assets_js_map,
r_assets_js,
diff --git a/server/src/ui/assets.rs b/server/src/ui/assets.rs
index 91bb5e2..5903b83 100644
--- a/server/src/ui/assets.rs
+++ b/server/src/ui/assets.rs
@@ -6,7 +6,10 @@
use super::error::MyResult;
use crate::{request_info::RequestInfo, responders::cache::CacheControlImage};
use anyhow::Context;
-use rocket::{get, http::ContentType};
+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;
@@ -34,6 +37,21 @@ pub async fn r_image(
Ok((ContentType::AVIF, CacheControlImage(encoded)))
}
+#[get("/image_fallback/person/<name>?<size>")]
+pub async fn r_image_fallback_person(
+ ri: RequestInfo<'_>,
+ name: &str,
+ size: Option<usize>,
+) -> MyResult<Redirect> {
+ 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))))
+}
+
// #[get("/n/<id>/image/<slot>?<size>")]
// pub async fn r_item_poster(
// session: A<Session>,
diff --git a/ui/src/components/node_card.rs b/ui/src/components/node_card.rs
index 1b8fd67..eb00ccc 100644
--- a/ui/src/components/node_card.rs
+++ b/ui/src/components/node_card.rs
@@ -10,7 +10,7 @@ use crate::{
};
use jellycommon::{
jellyobject::Object,
- routes::{u_image, u_node_slug, u_node_slug_player},
+ routes::{u_image, u_image_fallback_person, u_node_slug, u_node_slug_player},
*,
};
@@ -22,7 +22,7 @@ markup::define! {
div[class=cls] {
.poster {
a[href=u_node_slug(&slug)] {
- img[src=u_image(node.get(NO_PICTURES).unwrap_or_default().get(PICT_COVER).unwrap_or_default(), 512), loading="lazy"];
+ img[src=cover_image(&node, 512), loading="lazy"];
}
.cardhover.item {
@if node.has(NO_TRACK.0) {
@@ -49,7 +49,7 @@ markup::define! {
div[class="node card widecard poster"] {
div[class=&format!("poster {}", aspect_class(node))] {
a[href=u_node_slug(&slug)] {
- img[src=u_image(node.get(NO_PICTURES).unwrap_or_default().get(PICT_COVER).unwrap_or_default(), 512), loading="lazy"];
+ img[src=cover_image(&node, 512), loading="lazy"];
}
.cardhover.item {
@if node.has(NO_TRACK.0) {
@@ -65,3 +65,15 @@ markup::define! {
}
}
}
+
+fn cover_image(node: &Object, size: usize) -> String {
+ if let Some(cover) = node.get(NO_PICTURES).unwrap_or_default().get(PICT_COVER) {
+ return u_image(cover, size);
+ }
+ if let Some(title) = node.get(NO_TITLE)
+ && node.get(NO_KIND) == Some(KIND_PERSON)
+ {
+ return u_image_fallback_person(title, 512);
+ }
+ return String::new();
+}