Compare commits

...
Author SHA1 Message Date
Brandon Thomas e7ad25e9d8 start replacing old cdn paths 2026-03-11 09:54:40 -04:00
Brandon Thomas bfe19076d6 fix test failures 2026-03-11 09:45:15 -04:00
Brandon Thomas d21fda4b9d cleanup 2026-03-11 01:19:29 -04:00
Brandon Thomas 8bde78d8c1 wip 2026-03-11 01:17:30 -04:00
Brandon Thomas 08127a4f4a logging 2026-03-11 01:07:38 -04:00
6 changed files with 76 additions and 69 deletions
@@ -124,7 +124,7 @@ mod tests {
let links = MediaLinksBuilder::from_rooted_path_and_env(MediaDomain::FakeYou, ServerEnvironment::Production, "/foo/bar.wav");
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/foo/bar.wav");
use crate::http_server::common_responses::media::media_links_builder::MediaLinksBuilder;let links = MediaLinksBuilder::from_rooted_path_and_env(MediaDomain::Storyteller, ServerEnvironment::Development, "/foo/bar.wav");
let links = MediaLinksBuilder::from_rooted_path_and_env(MediaDomain::Storyteller, ServerEnvironment::Development, "/foo/bar.wav");
assert_eq!(links.cdn_url.as_str(), "https://pub-c8a4a5bdbdb048f286b77bdf9f786ff2.r2.dev/foo/bar.wav");
}
@@ -219,7 +219,7 @@ use crate::http_server::common_responses::media::media_links_builder::MediaLinks
#[test]
fn wav_file() {
let links = MediaLinksBuilder::from_rooted_path_and_env(DOMAIN, ServerEnvironment::Production, "/foo/bar.wav");
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/foo/bar.wav");
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/foo/bar.wav");
assert_eq!(links.maybe_thumbnail_template, None);
assert_eq!(links.maybe_video_previews, None);
}
@@ -227,7 +227,7 @@ use crate::http_server::common_responses::media::media_links_builder::MediaLinks
#[test]
fn glb_file() {
let links = MediaLinksBuilder::from_rooted_path_and_env(DOMAIN, ServerEnvironment::Production, "/foo/bar.glb");
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/foo/bar.glb");
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/foo/bar.glb");
assert_eq!(links.maybe_thumbnail_template, None);
assert_eq!(links.maybe_video_previews, None);
}
@@ -235,21 +235,21 @@ use crate::http_server::common_responses::media::media_links_builder::MediaLinks
#[test]
fn jpg_image() {
let links = MediaLinksBuilder::from_rooted_path_and_env(DOMAIN, ServerEnvironment::Production, "/foo/bar.jpg");
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/foo/bar.jpg");
assert_eq!(links.maybe_thumbnail_template, Some("https://cdn.storyteller.ai/cdn-cgi/image/width={WIDTH},quality=95/foo/bar.jpg".to_string()));
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/foo/bar.jpg");
assert_eq!(links.maybe_thumbnail_template, Some("https://cdn-2.fakeyou.com/cdn-cgi/image/width={WIDTH},quality=95/foo/bar.jpg".to_string()));
assert_eq!(links.maybe_video_previews, None);
}
#[test]
fn mp4_video() {
let links = MediaLinksBuilder::from_rooted_path_and_env(DOMAIN, ServerEnvironment::Production, "/foo/bar.mp4");
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/foo/bar.mp4");
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/foo/bar.mp4");
assert_eq!(links.maybe_thumbnail_template, None);
let video_previews = links.maybe_video_previews.expect("should have previews");
assert_eq!(video_previews.animated.as_str(), "https://cdn.storyteller.ai/foo/bar.mp4-thumb.gif");
assert_eq!(video_previews.still.as_str(), "https://cdn.storyteller.ai/foo/bar.mp4-thumb.jpg");
assert_eq!(video_previews.animated_thumbnail_template, "https://cdn.storyteller.ai/cdn-cgi/image/width={WIDTH},quality=95/foo/bar.mp4-thumb.gif");
assert_eq!(video_previews.still_thumbnail_template, "https://cdn.storyteller.ai/cdn-cgi/image/width={WIDTH},quality=95/foo/bar.mp4-thumb.jpg");
assert_eq!(video_previews.animated.as_str(), "https://cdn-2.fakeyou.com/foo/bar.mp4-thumb.gif");
assert_eq!(video_previews.still.as_str(), "https://cdn-2.fakeyou.com/foo/bar.mp4-thumb.jpg");
assert_eq!(video_previews.animated_thumbnail_template, "https://cdn-2.fakeyou.com/cdn-cgi/image/width={WIDTH},quality=95/foo/bar.mp4-thumb.gif");
assert_eq!(video_previews.still_thumbnail_template, "https://cdn-2.fakeyou.com/cdn-cgi/image/width={WIDTH},quality=95/foo/bar.mp4-thumb.jpg");
}
}
@@ -262,7 +262,7 @@ use crate::http_server::common_responses::media::media_links_builder::MediaLinks
// https://storage.googleapis.com/vocodes-public/media/9/4/a/2/7/94a27nmbd0bqmd10tg0pp3hz45zytf67/fakeyou_94a27nmbd0bqmd10tg0pp3hz45zytf67.wav
let media_path = MediaFileBucketPath::from_object_hash("94a27nmbd0bqmd10tg0pp3hz45zytf67", Some("fakeyou_"), Some(".wav"));
let links = MediaLinksBuilder::from_media_path_and_env(DOMAIN, ServerEnvironment::Production, &media_path);
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/media/9/4/a/2/7/94a27nmbd0bqmd10tg0pp3hz45zytf67/fakeyou_94a27nmbd0bqmd10tg0pp3hz45zytf67.wav");
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/media/9/4/a/2/7/94a27nmbd0bqmd10tg0pp3hz45zytf67/fakeyou_94a27nmbd0bqmd10tg0pp3hz45zytf67.wav");
assert_eq!(links.maybe_thumbnail_template, None);
assert_eq!(links.maybe_video_previews, None);
}
@@ -272,8 +272,8 @@ use crate::http_server::common_responses::media::media_links_builder::MediaLinks
/// https://storage.googleapis.com/vocodes-public/media/3/7/m/b/3/37mb3gh8fmj85y21thvbv08bzv24atjt/upload_37mb3gh8fmj85y21thvbv08bzv24atjt.png
let media_path = MediaFileBucketPath::from_object_hash("37mb3gh8fmj85y21thvbv08bzv24atjt", Some("upload_"), Some(".png"));
let links = MediaLinksBuilder::from_media_path_and_env(DOMAIN, ServerEnvironment::Production, &media_path);
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/media/3/7/m/b/3/37mb3gh8fmj85y21thvbv08bzv24atjt/upload_37mb3gh8fmj85y21thvbv08bzv24atjt.png");
assert_eq!(links.maybe_thumbnail_template, Some("https://cdn.storyteller.ai/cdn-cgi/image/width={WIDTH},quality=95/media/3/7/m/b/3/37mb3gh8fmj85y21thvbv08bzv24atjt/upload_37mb3gh8fmj85y21thvbv08bzv24atjt.png".to_string()));
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/media/3/7/m/b/3/37mb3gh8fmj85y21thvbv08bzv24atjt/upload_37mb3gh8fmj85y21thvbv08bzv24atjt.png");
assert_eq!(links.maybe_thumbnail_template, Some("https://cdn-2.fakeyou.com/cdn-cgi/image/width={WIDTH},quality=95/media/3/7/m/b/3/37mb3gh8fmj85y21thvbv08bzv24atjt/upload_37mb3gh8fmj85y21thvbv08bzv24atjt.png".to_string()));
assert_eq!(links.maybe_video_previews, None);
}
@@ -282,13 +282,13 @@ use crate::http_server::common_responses::media::media_links_builder::MediaLinks
// https://storage.googleapis.com/vocodes-public/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4
let media_path = MediaFileBucketPath::from_object_hash("t6cnyw4g3e8k7carkk2bvrt6nd3fycjv", Some("storyteller_"), Some(".mp4"));
let links = MediaLinksBuilder::from_media_path_and_env(DOMAIN, ServerEnvironment::Production, &media_path);
assert_eq!(links.cdn_url.as_str(), "https://cdn.storyteller.ai/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4");
assert_eq!(links.cdn_url.as_str(), "https://cdn-2.fakeyou.com/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4");
assert_eq!(links.maybe_thumbnail_template, None);
let video_previews = links.maybe_video_previews.expect("should have previews");
assert_eq!(video_previews.animated.as_str(), "https://cdn.storyteller.ai/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.gif");
assert_eq!(video_previews.still.as_str(), "https://cdn.storyteller.ai/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.jpg");
assert_eq!(video_previews.animated_thumbnail_template, "https://cdn.storyteller.ai/cdn-cgi/image/width={WIDTH},quality=95/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.gif");
assert_eq!(video_previews.still_thumbnail_template, "https://cdn.storyteller.ai/cdn-cgi/image/width={WIDTH},quality=95/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.jpg");
assert_eq!(video_previews.animated.as_str(), "https://cdn-2.fakeyou.com/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.gif");
assert_eq!(video_previews.still.as_str(), "https://cdn-2.fakeyou.com/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.jpg");
assert_eq!(video_previews.animated_thumbnail_template, "https://cdn-2.fakeyou.com/cdn-cgi/image/width={WIDTH},quality=95/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.gif");
assert_eq!(video_previews.still_thumbnail_template, "https://cdn-2.fakeyou.com/cdn-cgi/image/width={WIDTH},quality=95/media/t/6/c/n/y/t6cnyw4g3e8k7carkk2bvrt6nd3fycjv/storyteller_t6cnyw4g3e8k7carkk2bvrt6nd3fycjv.mp4-thumb.jpg");
}
}
}
@@ -8,7 +8,7 @@ use crate::http_server::common_responses::simple_entity_stats::SimpleEntityStats
use crate::http_server::common_responses::user_details_lite::UserDetailsLight;
use crate::http_server::endpoints::media_files::common_responses::live_portrait::MediaFileLivePortraitDetails;
use crate::http_server::endpoints::media_files::helpers::get_media_domain::get_media_domain;
use crate::http_server::web_utils::bucket_urls::bucket_url_from_media_path::bucket_url_from_media_path;
use crate::http_server::web_utils::bucket_urls::bucket_url_from_media_path_updated::bucket_url_from_media_path_updated;
use crate::http_server::web_utils::bucket_urls::bucket_url_from_str_path::bucket_url_from_str_path;
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
use crate::state::server_state::ServerState;
@@ -366,11 +366,7 @@ async fn modern_media_file_lookup(
maybe_batch_token: result.maybe_batch_token,
maybe_scene_source_media_file_token: result.maybe_scene_source_media_file_token,
media_links: MediaLinksBuilder::from_media_path_and_env(media_domain, server_state.server_environment, &public_bucket_path),
public_bucket_url: bucket_url_from_media_path(&public_bucket_path)
.map_err(|err| {
warn!("error creating URL: {:?}", err);
GetMediaFileError::ServerError
})?,
public_bucket_url: bucket_url_from_media_path_updated(media_domain, server_state.server_environment, &public_bucket_path),
public_bucket_path: public_bucket_path
.get_full_object_path_str()
.to_string(),
@@ -115,6 +115,8 @@ pub async fn fal_webhook_handler(
) -> Result<Json<SimpleGenericJsonSuccess>, FalWebhookError> {
info!("Received FAL webhook body: {:?}", request);
println!("--------------------\nFal Result: {:?}\n--------------------", request);
let request_id = request.request_id
.as_deref()
@@ -13,7 +13,6 @@ use mimetypes::mimetype_info::mimetype_info::MimetypeInfo;
use mysql_queries::queries::generic_inference::fal::get_inference_job_by_fal_id::FalJobDetails;
use mysql_queries::queries::media_files::create::insert_builder::media_file_insert_builder::MediaFileInsertBuilder;
use serde_json::{Map, Value};
use mysql_queries::queries::media_files::edit::set_media_file_cover_image::{set_media_file_cover_image, UpdateArgs};
use tokens::tokens::media_files::MediaFileToken;
const PREFIX : Option<&str> = Some("artcraft_");
@@ -68,31 +67,37 @@ pub async fn handle_model_glb_payload(
job: &FalJobDetails,
server_state: &ServerState,
) -> AnyhowResult<MediaFileToken> {
// Step 1: Try to upload thumbnail first (fail open)
let maybe_cover_token = match try_to_upload_thumbnail(payload, job, server_state).await {
Ok(maybe_token) => maybe_token,
Err(err) => {
warn!("Could not upload thumbnail as cover image: {:?}. Continuing without cover.", err);
None
}
};
// Step 2: Upload the GLB mesh, attaching the cover image if available
let model_glb_value = payload.get("model_glb")
.ok_or_else(|| anyhow!("no `model_mesh` key in payload"))?;
.ok_or_else(|| anyhow!("no `model_glb` key in payload"))?;
info!("Fal Model Glb Payload: {:?}", model_glb_value);
let mesh: FalMediaPayload = serde_json::from_value(model_glb_value.clone())?;
let mesh_url = mesh.url
.as_deref()
.ok_or_else(|| anyhow!("no `url` in image payload"))?;
//let mime_type = mesh.content_type
// .as_deref()
// .ok_or_else(|| anyhow!("no `content_type` in mesh payload"))?;
.ok_or_else(|| anyhow!("no `url` in model_glb payload"))?;
let file_bytes = http_download_url_to_bytes(mesh_url)
.await
.map_err(|e| anyhow!("Failed to download mesh: {:?}", e))?;
let mimetype_info = MimetypeInfo::get_for_bytes(&file_bytes)
.ok_or_else(|| anyhow!("Failed to get mimetype info"))?;
let mime_type = mimetype_info.mime_type();
info!("Mime type of mesh: {}", mime_type);
let media_file_type = MediaFileType::try_from_mime_type(mime_type)
@@ -124,59 +129,51 @@ pub async fn handle_model_glb_payload(
.media_file_type(media_file_type)
.media_file_origin_category(MediaFileOriginCategory::Inference)
.maybe_engine_category(Some(MediaFileEngineCategory::Object))
//.media_file_origin_product_category(MediaFileOriginProductCategory::Unknown)
.mime_type(mime_type)
.file_size_bytes(file_size_bytes as u64)
.maybe_prompt_token(job.maybe_prompt_token.as_ref())
.maybe_cover_image_media_file_token(maybe_cover_token.as_ref())
.checksum_sha2(&file_hash)
.insert_pool(&server_state.mysql_pool)
.await?;
info!("Glb media file uploaded with token: {}", media_token);
let result = try_to_attach_thumbnail(
payload,
job,
server_state,
&media_token,
).await;
// NB: Fail open
if let Err(err) = result {
warn!("Could not attach thumbnail as cover image to media file: {:?}", err);
}
Ok(media_token)
}
async fn try_to_attach_thumbnail(
async fn try_to_upload_thumbnail(
payload: &Map<String, Value>,
job: &FalJobDetails,
server_state: &ServerState,
glb_media_token: &MediaFileToken,
) -> AnyhowResult<()> {
) -> AnyhowResult<Option<MediaFileToken>> {
let thumbnail_value = payload.get("thumbnail")
.ok_or_else(|| anyhow!("no `thumbnail` key in payload"))?;
let thumbnail_value = match payload.get("thumbnail") {
Some(value) => value,
None => {
info!("No thumbnail in payload, skipping cover image.");
return Ok(None);
}
};
info!("Fal Thumbnail Payload: {:?}", thumbnail_value);
let thumbnail : FalMediaPayload = serde_json::from_value(thumbnail_value.clone())?;
let thumbnail: FalMediaPayload = serde_json::from_value(thumbnail_value.clone())?;
let mesh_url = thumbnail.url
let thumbnail_url = thumbnail.url
.as_deref()
.ok_or_else(|| anyhow!("no `url` in image payload"))?;
.ok_or_else(|| anyhow!("no `url` in thumbnail payload"))?;
let file_bytes = http_download_url_to_bytes(mesh_url)
let file_bytes = http_download_url_to_bytes(thumbnail_url)
.await
.map_err(|e| anyhow!("Failed to download image: {:?}", e))?;
.map_err(|e| anyhow!("Failed to download thumbnail: {:?}", e))?;
let mimetype_info = MimetypeInfo::get_for_bytes(&file_bytes)
.ok_or_else(|| anyhow!("Failed to get mimetype info"))?;
let mime_type = mimetype_info.mime_type();
info!("Mime type of image: {}", mime_type);
info!("Mime type of thumbnail: {}", mime_type);
let media_file_type = MediaFileType::try_from_mime_type(mime_type)
.ok_or_else(|| anyhow!("Unsupported media file type: {}", mime_type))?;
@@ -206,8 +203,6 @@ async fn try_to_attach_thumbnail(
.media_file_class(MediaFileClass::Image)
.media_file_type(media_file_type)
.media_file_origin_category(MediaFileOriginCategory::Processed)
//.maybe_engine_category(Some(MediaFileEngineCategory::Object))
//.media_file_origin_product_category(MediaFileOriginProductCategory::Unknown)
.mime_type(mime_type)
.file_size_bytes(file_size_bytes as u64)
.maybe_prompt_token(job.maybe_prompt_token.as_ref())
@@ -216,11 +211,7 @@ async fn try_to_attach_thumbnail(
.insert_pool(&server_state.mysql_pool)
.await?;
let query_result = set_media_file_cover_image(UpdateArgs {
media_file_token: glb_media_token,
maybe_cover_image_media_file_token: Some(&thumbnail_media_token),
mysql_pool: &server_state.mysql_pool,
}).await;
info!("Thumbnail uploaded with token: {}", thumbnail_media_token);
Ok(())
Ok(Some(thumbnail_media_token))
}
@@ -0,0 +1,17 @@
use url::Url;
use bucket_paths::legacy::typified_paths::public::media_files::bucket_file_path::MediaFileBucketPath;
use server_environment::ServerEnvironment;
use crate::http_server::common_responses::media::media_domain::MediaDomain;
use crate::http_server::common_responses::media::media_links_builder::MediaLinksBuilder;
#[deprecated(note="this is better than bucket_url_from_media_path, but still refrain from using it")]
pub fn bucket_url_from_media_path_updated(
media_domain: MediaDomain,
server_environment: ServerEnvironment,
bucket_path: &MediaFileBucketPath,
) -> Url {
let media_links = MediaLinksBuilder::from_media_path_and_env(media_domain, server_environment, bucket_path);
media_links.cdn_url
}
@@ -1,3 +1,4 @@
pub mod bucket_url_from_media_path;
pub mod bucket_url_from_media_path_updated;
pub mod bucket_url_from_str_path;
pub mod bucket_url_string_from_media_path;