thumbnail extractor

This commit is contained in:
Brandon Thomas committed 2026-04-12 01:52:28 -04:00
1 parent 422eabb616
commit fa7a0c3200
4 files changed
+168 -1

No files matched your search

@@ -11,6 +11,45 @@ pub (crate) fn extract_model_glb(obj: &Map<String, Value>) -> Option<ModelGlbDat
#[cfg(test)]
mod tests {
use super::*;
use crate::webhook_api::hydrate_webhook_contents::hydrate_webhook_contents;
use crate::webhook_api::hydrated::hydrated_webhook_contents::HydratedWebhookContents;
use crate::webhook_api::raw::raw_webhook_payload::RawWebhookPayload;
fn load_test_webhook(filename: &str) -> RawWebhookPayload {
let path = format!("test_data/webhooks/{}", filename);
let json = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("Failed to read {}: {}", path, e));
serde_json::from_str(&json)
.unwrap_or_else(|e| panic!("Failed to parse {}: {}", path, e))
}
#[test]
fn model_glb_from_test_file() {
let webhook = load_test_webhook("success/model_glb_urls_and_thumbnail_1.json");
let result = hydrate_webhook_contents(&webhook);
let HydratedWebhookContents::Success(data) = result else {
panic!("Expected Success, got {:?}", result);
};
let contents = data.extracted_contents
.expect("extracted_contents should be Some");
let glb = contents.model_glb.expect("model_glb should be Some");
assert_eq!(glb.url.as_deref(), Some("https://v3b.fal.media/files/b/0a95eb37/f7UaAhyfcx0BAnYy0GpFM_model.glb"));
assert_eq!(glb.content_type.as_deref(), Some("model/gltf-binary"));
assert_eq!(glb.file_name.as_deref(), Some("model.glb"));
assert_eq!(glb.file_size, Some(66284788));
// This payload also has a thumbnail.
assert!(contents.thumbnail.is_some());
// No image/images/video/mesh in this payload.
assert!(contents.image.is_none());
assert!(contents.images.is_none());
assert!(contents.video.is_none());
assert!(contents.model_mesh.is_none());
}
#[test]
fn synthetic_model_glb_payload() {
@@ -11,6 +11,43 @@ pub (crate) fn extract_model_mesh(obj: &Map<String, Value>) -> Option<ModelMeshD
#[cfg(test)]
mod tests {
use super::*;
use crate::webhook_api::hydrate_webhook_contents::hydrate_webhook_contents;
use crate::webhook_api::hydrated::hydrated_webhook_contents::HydratedWebhookContents;
use crate::webhook_api::raw::raw_webhook_payload::RawWebhookPayload;
fn load_test_webhook(filename: &str) -> RawWebhookPayload {
let path = format!("test_data/webhooks/{}", filename);
let json = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("Failed to read {}: {}", path, e));
serde_json::from_str(&json)
.unwrap_or_else(|e| panic!("Failed to parse {}: {}", path, e))
}
#[test]
fn model_mesh_from_test_file() {
let webhook = load_test_webhook("success/model_mesh_payload_1.json");
let result = hydrate_webhook_contents(&webhook);
let HydratedWebhookContents::Success(data) = result else {
panic!("Expected Success, got {:?}", result);
};
let contents = data.extracted_contents
.expect("extracted_contents should be Some");
let mesh = contents.model_mesh.expect("model_mesh should be Some");
assert_eq!(mesh.url.as_deref(), Some("https://v3b.fal.media/files/b/0a95eb2d/XCpH7fk-tZVXr1XMUr7DY_mesh-1775972273-765284.glb"));
assert_eq!(mesh.content_type.as_deref(), Some("application/octet-stream"));
assert_eq!(mesh.file_name.as_deref(), Some("mesh-1775972273-765284.glb"));
assert_eq!(mesh.file_size, Some(3886928));
// No other content types in this payload.
assert!(contents.image.is_none());
assert!(contents.images.is_none());
assert!(contents.video.is_none());
assert!(contents.model_glb.is_none());
assert!(contents.thumbnail.is_none());
}
#[test]
fn synthetic_model_mesh_payload() {
@@ -0,0 +1,86 @@
use serde_json::{Map, Value};
use crate::webhook_api::hydrated::hydrated_webhook_contents::ThumbnailData;
/// Extract and deserialize the `thumbnail` key from a webhook success payload.
pub(crate) fn extract_thumbnail(obj: &Map<String, Value>) -> Option<ThumbnailData> {
let value = obj.get("thumbnail")?;
serde_json::from_value(value.clone()).ok()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::webhook_api::hydrate_webhook_contents::hydrate_webhook_contents;
use crate::webhook_api::hydrated::hydrated_webhook_contents::HydratedWebhookContents;
use crate::webhook_api::raw::raw_webhook_payload::RawWebhookPayload;
fn load_test_webhook(filename: &str) -> RawWebhookPayload {
let path = format!("test_data/webhooks/{}", filename);
let json = std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("Failed to read {}: {}", path, e));
serde_json::from_str(&json)
.unwrap_or_else(|e| panic!("Failed to parse {}: {}", path, e))
}
#[test]
fn thumbnail_from_model_glb_test_file() {
let webhook = load_test_webhook("success/model_glb_urls_and_thumbnail_1.json");
let result = hydrate_webhook_contents(&webhook);
let HydratedWebhookContents::Success(data) = result else {
panic!("Expected Success, got {:?}", result);
};
let contents = data.extracted_contents
.expect("extracted_contents should be Some");
let thumbnail = contents.thumbnail.expect("thumbnail should be Some");
assert_eq!(thumbnail.url.as_deref(), Some("https://v3b.fal.media/files/b/0a95eb38/yvwGJWZV9TkWZuZvjxZNj_preview.png"));
assert_eq!(thumbnail.content_type.as_deref(), Some("image/png"));
assert_eq!(thumbnail.file_name.as_deref(), Some("preview.png"));
assert_eq!(thumbnail.file_size, Some(93436));
}
#[test]
fn synthetic_thumbnail_payload() {
let obj: serde_json::Map<String, serde_json::Value> = serde_json::from_str(r#"{
"thumbnail": {
"url": "https://cdn.example.com/thumb.png",
"content_type": "image/png",
"file_name": "thumb.png",
"file_size": 12345
}
}"#).unwrap();
let thumb = extract_thumbnail(&obj).expect("should extract thumbnail");
assert_eq!(thumb.url.as_deref(), Some("https://cdn.example.com/thumb.png"));
assert_eq!(thumb.content_type.as_deref(), Some("image/png"));
assert_eq!(thumb.file_name.as_deref(), Some("thumb.png"));
assert_eq!(thumb.file_size, Some(12345));
}
#[test]
fn missing_thumbnail_key_returns_none() {
let obj: serde_json::Map<String, serde_json::Value> = serde_json::from_str(r#"{
"model_glb": {"url": "https://example.com/model.glb"}
}"#).unwrap();
assert!(extract_thumbnail(&obj).is_none());
}
#[test]
fn model_mesh_payload_has_no_thumbnail() {
let webhook = load_test_webhook("success/model_mesh_payload_1.json");
let result = hydrate_webhook_contents(&webhook);
let HydratedWebhookContents::Success(data) = result else {
panic!("Expected Success, got {:?}", result);
};
let contents = data.extracted_contents
.expect("extracted_contents should be Some");
assert!(contents.thumbnail.is_none());
}
}
@@ -3,6 +3,7 @@ pub mod extract_images_payload;
pub mod extract_video_payload;
pub mod extract_model_glb_payload;
pub mod extract_model_mesh_payload;
pub mod extract_thumbnail_payload;
use serde_json::Value;
@@ -23,8 +24,11 @@ pub fn extract_contents_from_payload(payload: &Value) -> Option<ExtractedContent
let video = extract_video_payload::extract_video(obj);
let model_glb = extract_model_glb_payload::extract_model_glb(obj);
let model_mesh = extract_model_mesh_payload::extract_model_mesh(obj);
let thumbnail = extract_thumbnail_payload::extract_thumbnail(obj);
if image.is_none() && images.is_none() && video.is_none() && model_glb.is_none() && model_mesh.is_none() {
if image.is_none() && images.is_none() && video.is_none()
&& model_glb.is_none() && model_mesh.is_none() && thumbnail.is_none()
{
return None;
}
@@ -34,5 +38,6 @@ pub fn extract_contents_from_payload(payload: &Value) -> Option<ExtractedContent
video,
model_glb,
model_mesh,
thumbnail,
})
}