feat: download top-5 cast photos during TMDb enrichment
Some checks failed
CI / Check / Test (push) Failing after 41s

This commit is contained in:
2026-06-03 00:42:25 +02:00
parent a5cf62e281
commit c842ad6a55
3 changed files with 64 additions and 12 deletions

View File

@@ -8,8 +8,8 @@ use domain::{
events::DomainEvent,
models::{CastMember, CrewMember, Genre, Keyword, MovieProfile},
ports::{
EventHandler, MovieEnrichmentClient, MovieProfileRepository, MovieRepository,
PersonCommand, SearchCommand,
EventHandler, ImageStorage, MovieEnrichmentClient, MovieProfileRepository,
MovieRepository, PersonCommand, SearchCommand,
},
value_objects::MovieId,
};
@@ -229,6 +229,52 @@ pub struct EnrichmentHandler {
pub profile_repo: Arc<dyn MovieProfileRepository>,
pub person_command: Arc<dyn PersonCommand>,
pub search_command: Arc<dyn SearchCommand>,
pub image_storage: Arc<dyn ImageStorage>,
http: reqwest::Client,
}
impl EnrichmentHandler {
pub fn new(
enrichment_client: Arc<dyn MovieEnrichmentClient>,
movie_repository: Arc<dyn MovieRepository>,
profile_repo: Arc<dyn MovieProfileRepository>,
person_command: Arc<dyn PersonCommand>,
search_command: Arc<dyn SearchCommand>,
image_storage: Arc<dyn ImageStorage>,
) -> Self {
Self {
enrichment_client,
movie_repository,
profile_repo,
person_command,
search_command,
image_storage,
http: reqwest::Client::new(),
}
}
async fn download_cast_photos(&self, profile: &MovieProfile) {
for member in profile.cast.iter().take(5) {
let Some(ref path) = member.profile_path else {
continue;
};
let key = format!("cast{path}");
if self.image_storage.get(&key).await.is_ok() {
continue;
}
let url = format!("https://image.tmdb.org/t/p/w185{path}");
match self.http.get(&url).send().await {
Ok(resp) if resp.status().is_success() => {
if let Ok(bytes) = resp.bytes().await {
if let Err(e) = self.image_storage.store(&key, &bytes).await {
tracing::debug!("cast photo store failed for {path}: {e}");
}
}
}
_ => tracing::debug!("cast photo download failed for {path}"),
}
}
}
}
#[async_trait]
@@ -263,6 +309,7 @@ impl EventHandler for EnrichmentHandler {
.await
{
Ok(profile) => {
self.download_cast_photos(&profile).await;
enrich_movie::execute(
&self.movie_repository,
&self.profile_repo,

View File

@@ -2,7 +2,7 @@ use crate::context::AppContext;
use crate::wrapup::{compute, queries::ComputeWrapUpQuery};
use domain::errors::DomainError;
use domain::events::DomainEvent;
use domain::models::wrapup::{DateRange, WrapUpReport, WrapUpScope, WrapUpStatus};
use domain::models::wrapup::{DateRange, WrapUpScope, WrapUpStatus};
use domain::ports::{VideoRenderAssets, VideoRenderConfig};
use domain::value_objects::WrapUpId;
@@ -41,8 +41,12 @@ pub async fn execute(
if let Some(ref renderer) = ctx.services.video_renderer {
let poster_images = resolve_images(ctx, &report.poster_paths, "poster").await;
let cast_images =
resolve_images(ctx, &report.top_cast_profile_paths, "cast").await;
let cast_keys: Vec<String> = report
.top_cast_profile_paths
.iter()
.map(|p| format!("cast{p}"))
.collect();
let cast_images = resolve_images(ctx, &cast_keys, "cast").await;
let wc = &ctx.config.wrapup;
let config = VideoRenderConfig {
slide_duration_secs: 4,

View File

@@ -127,13 +127,14 @@ async fn main() -> anyhow::Result<()> {
match tmdb_enrichment::TmdbEnrichmentClient::from_env() {
Ok(client) => {
tracing::info!("TMDb enrichment enabled");
let handler = Arc::new(tmdb_enrichment::EnrichmentHandler {
enrichment_client: Arc::new(client),
movie_repository: Arc::clone(&ctx.repos.movie),
profile_repo: Arc::clone(&ctx.repos.movie_profile),
person_command: Arc::clone(&ctx.repos.person_command),
search_command: Arc::clone(&ctx.repos.search_command),
}) as Arc<dyn EventHandler>;
let handler = Arc::new(tmdb_enrichment::EnrichmentHandler::new(
Arc::new(client),
Arc::clone(&ctx.repos.movie),
Arc::clone(&ctx.repos.movie_profile),
Arc::clone(&ctx.repos.person_command),
Arc::clone(&ctx.repos.search_command),
Arc::clone(&ctx.services.image_storage),
)) as Arc<dyn EventHandler>;
let job = Arc::new(application::jobs::EnrichmentStalenessJob::new(ctx.clone()))
as Arc<dyn PeriodicJob>;
(Some(handler), Some(job))