use julid::Julid; use sqlx::{Sqlite, SqlitePool}; use crate::{ import_utils::{insert_credit, insert_star, insert_watch}, Credit, ShowKind, Star, Watch, }; pub type IdMap = std::collections::BTreeMap; const OMEGA_ID: Julid = Julid::omega(); #[derive(Debug, sqlx::FromRow, Clone)] pub struct ImportImdbMovie { pub title: String, pub year: Option, pub length: Option, pub id: String, pub kind: Option, } impl From for Watch { fn from(value: ImportImdbMovie) -> Self { Watch { id: OMEGA_ID, // this is ignored by the inserter title: value.title, release_date: value.year, length: value.length.and_then(|v| v.parse::().ok()), kind: ShowKind::Movie, metadata_url: Some(format!("https://imdb.com/title/{}/", &value.id)), added_by: OMEGA_ID, } } } impl From<&ImportImdbMovie> for Watch { fn from(value: &ImportImdbMovie) -> Self { Watch { id: OMEGA_ID, title: value.title.to_string(), release_date: value.year.clone(), length: value.length.as_ref().and_then(|v| v.parse::().ok()), kind: ShowKind::Movie, metadata_url: Some(format!("https://imdb.com/title/{}/", value.id)), added_by: OMEGA_ID, } } } #[derive(Debug, sqlx::FromRow, Clone)] pub struct ImdbStar { pub nconst: String, #[sqlx(rename = "primaryName")] pub name: String, #[sqlx(rename = "birthYear")] pub born: Option, #[sqlx(rename = "deathYear")] pub died: Option, } impl From<&ImdbStar> for Star { fn from(value: &ImdbStar) -> Self { let id = &value.nconst; let metadata_url = Some(format!("https://imdb.com/name/{id}/")); Self { name: value.name.clone(), metadata_url, born: value.born.clone(), died: value.died.clone(), ..Default::default() } } } pub async fn import_imdb_data(w2w_db: &SqlitePool, imdb: &SqlitePool, ids: &mut IdMap, num: u32) { const IMDB_QUERY: &str = "select * from watches order by year, title asc limit ?"; let iwatches: Vec = sqlx::query_as(IMDB_QUERY) .bind(num) .fetch_all(imdb) .await .unwrap(); for batch in iwatches.chunks(5_000) { let mut tx = w2w_db.begin().await.unwrap(); for iwatch in batch { let aid = iwatch.id.clone(); let kind = show_kind(iwatch.kind.as_ref().unwrap()); let mut watch: Watch = iwatch.into(); watch.kind = kind; let watch_id: Julid = insert_watch(watch, &mut tx).await; add_imdb_stars(&mut tx, imdb, &aid, watch_id, ids).await; ids.insert(aid, watch_id); } tx.commit().await.unwrap(); } } async fn add_imdb_stars( w2w_db: &mut sqlx::Transaction<'_, Sqlite>, imdb: &SqlitePool, iwatch: &str, watch: Julid, ids: &mut IdMap, ) { let principals_query = "select nconst, category from principals where tconst = ?"; let principals = sqlx::query_as::(principals_query) .bind(iwatch) .fetch_all(imdb) .await .unwrap(); for row in principals { let (name_id, cat) = row; let star = if let Some(id) = ids.get(&name_id) { *id } else { let name_query = "select nconst, primaryName, birthYear, deathYear from names where nconst = ?"; let istar: Option = sqlx::query_as(name_query) .bind(&name_id) .fetch_optional(imdb) .await .unwrap(); if let Some(star) = istar { let star = (&star).into(); let star_id = insert_star(&star, w2w_db).await; ids.insert(name_id, star_id); star_id } else { continue; } }; let credit = Credit { star, watch, credit: Some(cat.to_string()), }; insert_credit(&credit, w2w_db).await; } } fn show_kind(kind: &str) -> ShowKind { /* tvSeries tvMiniSeries tvMovie tvShort tvSpecial */ match &kind[0..4] { "tvSe" => ShowKind::Series, "tvSh" => ShowKind::Short, "tvMi" => ShowKind::LimitedSeries, "tvSp" => ShowKind::Other, "tvMo" | "movi" => ShowKind::Movie, _ => ShowKind::Unknown, } }