diff --git a/crates/api-types/src/search.rs b/crates/api-types/src/search.rs index 91cc84b..37da6ad 100644 --- a/crates/api-types/src/search.rs +++ b/crates/api-types/src/search.rs @@ -70,6 +70,21 @@ pub struct PersonDto { pub name: String, pub known_for_department: Option, pub profile_path: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub biography: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub birthday: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub deathday: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub place_of_birth: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub also_known_as: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub homepage: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub imdb_url: Option, + pub enriched: bool, } #[derive(Debug, Serialize, ToSchema)] diff --git a/crates/presentation/src/handlers/search.rs b/crates/presentation/src/handlers/search.rs index 1a70d7f..f2887a6 100644 --- a/crates/presentation/src/handlers/search.rs +++ b/crates/presentation/src/handlers/search.rs @@ -108,6 +108,14 @@ pub async fn get_person_handler( name: person.name().to_string(), known_for_department: person.known_for_department().map(str::to_string), profile_path: person.profile_path().map(str::to_string), + biography: person.biography().map(str::to_string), + birthday: person.birthday().map(|d| d.to_string()), + deathday: person.deathday().map(|d| d.to_string()), + place_of_birth: person.place_of_birth().map(str::to_string), + also_known_as: person.also_known_as().to_vec(), + homepage: person.homepage().map(str::to_string), + imdb_url: person.imdb_id().map(|id| format!("https://www.imdb.com/name/{id}")), + enriched: person.enriched_at().is_some(), }) .into_response(), Ok(None) => StatusCode::NOT_FOUND.into_response(), @@ -136,6 +144,14 @@ pub async fn get_person_credits_handler( name: credits.person.name().to_string(), known_for_department: credits.person.known_for_department().map(str::to_string), profile_path: credits.person.profile_path().map(str::to_string), + biography: credits.person.biography().map(str::to_string), + birthday: credits.person.birthday().map(|d| d.to_string()), + deathday: credits.person.deathday().map(|d| d.to_string()), + place_of_birth: credits.person.place_of_birth().map(str::to_string), + also_known_as: credits.person.also_known_as().to_vec(), + homepage: credits.person.homepage().map(str::to_string), + imdb_url: credits.person.imdb_id().map(|id| format!("https://www.imdb.com/name/{id}")), + enriched: credits.person.enriched_at().is_some(), }, cast: credits .cast diff --git a/crates/worker/src/main.rs b/crates/worker/src/main.rs index 4972ab0..808c344 100644 --- a/crates/worker/src/main.rs +++ b/crates/worker/src/main.rs @@ -15,7 +15,10 @@ use export::ExportAdapter; use importer::ImporterDocumentParser; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; -use domain::ports::{DiaryExporter, DocumentParser, EventHandler, PeriodicJob}; +use domain::ports::{ + DiaryExporter, DocumentParser, EventHandler, MovieEnrichmentClient, PeriodicJob, + PersonEnrichmentClient, +}; #[cfg(not(any(feature = "sqlite", feature = "postgres")))] compile_error!( @@ -74,7 +77,7 @@ async fn main() -> anyhow::Result<()> { Arc::clone(&event_publisher_arc), )); - let ctx = AppContext { + let mut ctx = AppContext { repos: Repositories { movie: db.movie, review: db.review, @@ -125,26 +128,38 @@ async fn main() -> anyhow::Result<()> { // Both the event handler and the staleness job are gated on TMDB_API_KEY. // Without a key, no MovieEnrichmentRequested events are produced or handled. - type OptionalPair = (Option>, Option>); - let (enrichment_handler, enrichment_job): OptionalPair = + type EnrichmentParts = ( + Option>, + Option>, + Option>, + ); + let (enrichment_handler, person_enrichment_handler, enrichment_job): EnrichmentParts = match tmdb_enrichment::TmdbEnrichmentClient::from_env() { Ok(client) => { tracing::info!("TMDb enrichment enabled"); + let client = Arc::new(client); let handler = Arc::new(tmdb_enrichment::EnrichmentHandler::new( - Arc::new(client), + Arc::clone(&client) as Arc, 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.object_storage), )) as Arc; + let person_handler = Arc::new(tmdb_enrichment::PersonEnrichmentHandler::new( + Arc::clone(&client) as Arc, + Arc::clone(&ctx.repos.person_query), + Arc::clone(&ctx.repos.person_command), + )) as Arc; + ctx.services.person_enrichment = + Some(Arc::clone(&client) as Arc); let job = Arc::new(application::jobs::EnrichmentStalenessJob::new(ctx.clone())) as Arc; - (Some(handler), Some(job)) + (Some(handler), Some(person_handler), Some(job)) } Err(e) => { tracing::warn!("TMDb enrichment disabled: {e}"); - (None, None) + (None, None, None) } }; @@ -226,6 +241,9 @@ async fn main() -> anyhow::Result<()> { if let Some(e) = enrichment_handler { h.push(e); } + if let Some(e) = person_enrichment_handler { + h.push(e); + } if let Some((ref conv_handler, _)) = conversion { h.push(Arc::clone(conv_handler)); } @@ -282,6 +300,9 @@ async fn main() -> anyhow::Result<()> { if let Some(e) = enrichment_handler { h.push(e); } + if let Some(e) = person_enrichment_handler { + h.push(e); + } if let Some((ref conv_handler, _)) = conversion { h.push(Arc::clone(conv_handler)); }