aboutsummaryrefslogtreecommitdiff
path: root/import
diff options
context:
space:
mode:
Diffstat (limited to 'import')
-rw-r--r--import/Cargo.toml2
-rw-r--r--import/src/lib.rs141
-rw-r--r--import/src/tmdb.rs47
3 files changed, 71 insertions, 119 deletions
diff --git a/import/Cargo.toml b/import/Cargo.toml
index a54967c..91a7662 100644
--- a/import/Cargo.toml
+++ b/import/Cargo.toml
@@ -12,7 +12,7 @@ jellyremuxer = { path = "../remuxer" }
log = { workspace = true }
anyhow = "1.0.75"
-reqwest = { version = "0.11.22", features = ["blocking", "json"] }
+reqwest = { version = "0.11.22", features = ["json"] }
serde = { version = "1.0.193", features = ["derive"] }
serde_json = "1.0.108"
diff --git a/import/src/lib.rs b/import/src/lib.rs
index e69e203..3f14960 100644
--- a/import/src/lib.rs
+++ b/import/src/lib.rs
@@ -28,13 +28,16 @@ use std::{
cmp::Ordering,
ffi::OsStr,
fs::File,
- io::{BufReader, Write},
+ io::BufReader,
os::unix::prelude::OsStrExt,
path::{Path, PathBuf},
sync::{Arc, LazyLock},
};
+use tmdb::tmdb_image;
use tokio::{io::AsyncWriteExt, sync::Semaphore, task::spawn_blocking};
+use crate::tmdb::TmdbKind;
+
static IMPORT_SEM: LazyLock<Semaphore> = LazyLock::new(|| Semaphore::new(1));
pub async fn import(db: &Database, fed: &Federation) -> anyhow::Result<()> {
@@ -183,8 +186,39 @@ async fn process_source(
};
match s {
ImportSource::Override(n) => insert_node(&id, n)?,
- ImportSource::Tmdb { id } => {
- todo!()
+ ImportSource::Tmdb { id: tid } => {
+ let key = CONF
+ .tmdb_api_key
+ .as_ref()
+ .ok_or(anyhow!("no tmdb api key"))?;
+ let details = tmdb::tmdb_details(TmdbKind::Movie, tid, key).await?;
+
+ let mut node = Node::default();
+
+ if let Some(poster) = details.poster_path {
+ node.private.poster = Some(
+ async_cache_file(
+ &["tmdb-asset", "poster", &format!("{tid}")],
+ |mut f| async move { Ok(f.write_all(&tmdb_image(&poster).await?).await?) },
+ )
+ .await?,
+ );
+ }
+ if let Some(backdrop) = details.backdrop_path {
+ node.private.backdrop = Some(
+ async_cache_file(
+ &["tmdb-asset", "backdrop", &format!("{tid}")],
+ |mut f| async move { Ok(f.write_all(&tmdb_image(&backdrop).await?).await?) },
+ )
+ .await?,
+ );
+ }
+
+ node.public.tagline = details.tagline;
+ node.public.title = details.title;
+ node.public.description = Some(details.overview);
+
+ insert_node(&id, node)?;
}
ImportSource::Media { location, .. } => {
// TODO use ignore options
@@ -314,107 +348,6 @@ fn merge_node(x: Node, y: Node) -> Node {
}
}
-// #[async_recursion]
-// pub async fn import_path(
-// path: PathBuf,
-// db: &Database,
-// fed: &Federation,
-// mut node_path: Vec<String>,
-// ) -> anyhow::Result<(Vec<String>, usize)> {
-// if path.is_dir() {
-// let mpath = path.join("directory.json");
-// let children_paths = path.read_dir()?.map(Result::unwrap).filter_map(|e| {
-// if e.path().extension() == Some(&OsStr::from_bytes(b"jelly"))
-// || e.metadata().unwrap().is_dir()
-// {
-// Some(e.path())
-// } else {
-// None
-// }
-// });
-// let identifier = if mpath.exists() {
-// path.file_name().unwrap().to_str().unwrap().to_string()
-// } else {
-// node_path
-// .last()
-// .cloned()
-// .ok_or(anyhow!("non-root node requires parent"))?
-// };
-
-// node_path.push(identifier.clone());
-// let mut all: FuturesUnordered<_> = children_paths
-// .into_iter()
-// .map(|p| import_path(p.clone(), db, fed, node_path.clone()).map_err(|e| (p, e)))
-// .collect();
-// node_path.pop(); // we will set the dirs path later and need it to not be included
-
-// let mut children_ids = Vec::new();
-// let mut errs = 0;
-// while let Some(k) = all.next().await {
-// match k {
-// core::result::Result::Ok((els, errs2)) => {
-// errs += errs2;
-// children_ids.extend(els)
-// }
-// Err((p, e)) => {
-// errs += 1;
-// error!("import of {p:?} failed: {e:?}")
-// }
-// }
-// }
-// if mpath.exists() {
-// let mut node: Node =
-// serde_json::from_reader(File::open(mpath).context("metadata missing")?)?;
-
-// node.public.children = children_ids;
-// node.public.path = node_path;
-// node.public.id = Some(identifier.to_owned());
-// info!("adding {identifier}");
-// db.node.insert(&identifier, &node)?;
-// Ok((vec![identifier], errs))
-// } else {
-// Ok((children_ids, errs))
-// }
-// } else if path.is_file() {
-// info!("loading {path:?}");
-// let datafile = File::open(path.clone()).context("cant load metadata")?;
-// let mut node: Node = serde_json::from_reader(datafile).context("invalid metadata")?;
-// let identifier = node.private.id.clone().unwrap_or_else(|| {
-// path.file_name()
-// .unwrap()
-// .to_str()
-// .unwrap()
-// .strip_suffix(".json")
-// .unwrap()
-// .to_string()
-// });
-
-// let idents = if let Some(io) = node.private.import.take() {
-// let session = fed
-// .get_session(&io.host)
-// .await
-// .context("creating session")?;
-
-// import_remote(io, db, &session, identifier.clone(), node_path)
-// .await
-// .context("federated import")?
-// } else {
-// debug!("adding {identifier}");
-// node.public.path = node_path;
-// node.public.id = Some(identifier.to_owned());
-// let did_insert = db.node.insert(&identifier, &node)?.is_none();
-// if did_insert {
-// vec![identifier]
-// } else {
-// vec![]
-// }
-// };
-// Ok((idents, 0))
-// } else {
-// bail!("did somebody really put a fifo or socket in the library?!")
-// }
-// }
-
static SEM_REMOTE_IMPORT: LazyLock<Semaphore> = LazyLock::new(|| Semaphore::new(16));
#[async_recursion]
diff --git a/import/src/tmdb.rs b/import/src/tmdb.rs
index c38d50e..3780524 100644
--- a/import/src/tmdb.rs
+++ b/import/src/tmdb.rs
@@ -72,28 +72,47 @@ pub struct TmdbProductionCompany {
pub logo_path: Option<String>,
}
-pub fn tmdb_search(kind: &str, query: &str, key: &str) -> anyhow::Result<TmdbQuery> {
+#[derive(Debug, Clone, Copy)]
+pub enum TmdbKind {
+ Tv,
+ Movie,
+}
+impl TmdbKind {
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ TmdbKind::Tv => "tv",
+ TmdbKind::Movie => "movie",
+ }
+ }
+}
+
+pub async fn tmdb_search(kind: TmdbKind, query: &str, key: &str) -> anyhow::Result<TmdbQuery> {
info!("searching tmdb: {query:?}");
- Ok(reqwest::blocking::get(&format!(
- "https://api.themoviedb.org/3/search/{kind}?query={}&api_key={key}",
+ Ok(reqwest::get(&format!(
+ "https://api.themoviedb.org/3/search/{}?query={}&api_key={key}",
+ kind.as_str(),
query.replace(" ", "+")
- ))?
- .json::<TmdbQuery>()?)
+ ))
+ .await?
+ .json::<TmdbQuery>()
+ .await?)
}
-pub fn tmdb_details(kind: &str, id: u64, key: &str) -> anyhow::Result<TmdbDetails> {
+pub async fn tmdb_details(kind: TmdbKind, id: u64, key: &str) -> anyhow::Result<TmdbDetails> {
info!("fetching details: {id:?}");
- Ok(reqwest::blocking::get(&format!(
- "https://api.themoviedb.org/3/{kind}/{id}?api_key={key}"
- ))?
- .json()?)
+ Ok(reqwest::get(&format!(
+ "https://api.themoviedb.org/3/{}/{id}?api_key={key}",
+ kind.as_str()
+ ))
+ .await?
+ .json()
+ .await?)
}
-pub fn tmdb_image(path: &str, out: &mut impl Write) -> anyhow::Result<()> {
+pub async fn tmdb_image(path: &str) -> anyhow::Result<Vec<u8>> {
info!("downloading image {path:?}");
- let mut res = reqwest::blocking::get(&format!("https://image.tmdb.org/t/p/original{path}"))?;
- res.copy_to(out)?;
- Ok(())
+ let res = reqwest::get(&format!("https://image.tmdb.org/t/p/original{path}")).await?;
+ Ok(res.bytes().await?.to_vec())
}
pub fn parse_release_date(d: &str) -> anyhow::Result<DateTime<Utc>> {