diff options
Diffstat (limited to 'tools/src')
-rw-r--r-- | tools/src/bin/import.rs | 322 | ||||
-rw-r--r-- | tools/src/lib.rs | 6 | ||||
-rw-r--r-- | tools/src/tmdb.rs | 95 |
3 files changed, 0 insertions, 423 deletions
diff --git a/tools/src/bin/import.rs b/tools/src/bin/import.rs deleted file mode 100644 index eada6ad..0000000 --- a/tools/src/bin/import.rs +++ /dev/null @@ -1,322 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2023 metamuffin <metamuffin.org> -*/ -use anyhow::Context; -use clap::{Parser, Subcommand}; -use jellycommon::{AssetLocation, MediaInfo, MediaSource, Node, NodeKind, NodePrivate, NodePublic}; -use jellymatroska::read::EbmlReader; -use jellyremuxer::import::{import_metadata, seek_index::import_seek_index}; -use jellytools::tmdb::{tmdb_details, tmdb_image, tmdb_search}; -use log::info; -use std::{ - collections::BTreeMap, - fs::{remove_file, File}, - io::stdin, - path::PathBuf, - process::exit, -}; - -#[derive(Parser)] -struct Args { - #[arg(short = 'N', long)] - dry: bool, - #[clap(subcommand)] - action: Action, -} - -#[derive(Subcommand)] -enum Action { - Create { - path: PathBuf, - #[arg(short = 't', long)] - tmdb_search: Option<String>, - #[arg(short = 'T', long)] - tmdb_id: Option<String>, - #[arg(long)] - copy: bool, - #[arg(long)] - r#move: bool, - #[arg(short, long)] - input: Option<PathBuf>, - #[arg(short, long)] - series: bool, - }, - Set { - #[arg(short = 'I', long)] - item: PathBuf, - #[arg(short, long)] - poster: Option<PathBuf>, - #[arg(short, long)] - title: Option<String>, - #[arg(short = 'D', long)] - tagline: Option<String>, - #[arg(short = 'd', long)] - description: Option<String>, - #[arg(short = 'c', long)] - clear_inputs: bool, - #[arg(short = 'i', long, num_args(0..))] - input: Vec<PathBuf>, - }, -} - -fn main() -> anyhow::Result<()> { - env_logger::builder() - .filter_level(log::LevelFilter::Info) - .parse_env("LOG") - .init(); - let args = Args::parse(); - - match args.action { - Action::Create { - path, - tmdb_id, - tmdb_search, - input, - series, - copy, - r#move, - } => { - let tmdb_kind = if series { "tv" } else { "movie" }; - let tmdb_key = std::env::var("TMDB_API_KEY").context("tmdb api key required")?; - let tmdb_id = if let Some(id) = tmdb_id { - Some(id.parse().unwrap()) - } else { - let title = tmdb_search.as_ref().unwrap(); - let results = crate::tmdb_search(tmdb_kind, title, &tmdb_key)?; - info!("results:"); - for (i, r) in results.results.iter().enumerate() { - info!( - "\t[{i}] {}: {} ({})", - r.id, - r.title.as_ref().or(r.name.as_ref()).unwrap(), - r.overview.chars().take(100).collect::<String>() - ); - } - let res_index = if results.results.len() > 1 { - stdin() - .lines() - .next() - .unwrap() - .unwrap() - .parse::<usize>() - .unwrap() - } else { - 0 - }; - Some(results.results[res_index].id) - }; - - let tmdb_details = tmdb_id.map(|id| { - let td = tmdb_details(tmdb_kind, id, &tmdb_key) - .context("fetching details") - .unwrap(); - if td.title.is_some() { - info!("is this correct? [y/n]"); - if stdin().lines().next().unwrap().unwrap() != "y" { - exit(0) - } - } - td - }); - - let title = tmdb_details - .as_ref() - .map(|d| d.title.clone().or(d.name.clone())) - .flatten() - .unwrap(); - let ident = make_ident(&title); - let path = path.join(&ident); - - let poster = tmdb_details - .as_ref() - .map(|d| { - d.poster_path - .as_ref() - .map(|p| { - let pu = path.join("poster.jpeg"); - let mut f = File::create(&pu)?; - tmdb_image(&p, &mut f)?; - Ok::<_, anyhow::Error>(pu) - }) - .transpose() - }) - .transpose()? - .flatten(); - - let backdrop = tmdb_details - .as_ref() - .map(|d| { - d.backdrop_path - .as_ref() - .map(|p| { - let pu = path.join("backdrop.jpeg"); - let mut f = File::create(&pu)?; - tmdb_image(&p, &mut f)?; - Ok::<_, anyhow::Error>(pu) - }) - .transpose() - }) - .transpose()? - .flatten(); - - let kind; - let media; - let source; - let mut seek_index = BTreeMap::new(); - let mut source_path_e = None; - - if let Some(input) = input { - let source_path = path.join(format!("source.mkv")); - if r#move { - std::fs::rename(&input, &source_path)?; - } else if copy { - std::fs::copy(&input, &source_path)?; - } else { - if source_path.is_symlink() { - remove_file(&source_path)?; - } - std::os::unix::fs::symlink(&input, &source_path)?; - } - - let (tracks, local_tracks, duration) = { - let input = File::open(&source_path).unwrap(); - let mut input = EbmlReader::new(input); - import_metadata(&source_path.to_path_buf(), &mut input)? - }; - seek_index = { - let input = File::open(&source_path).unwrap(); - let mut input = EbmlReader::new(input); - import_seek_index(&mut input)? - }; - - kind = NodeKind::Movie; - media = Some(MediaInfo { duration, tracks }); - source = Some(MediaSource::Local { - tracks: local_tracks, - }); - source_path_e = Some(source_path) - } else { - kind = NodeKind::Series; - media = None; - source = None; - }; - - let node = Node { - private: NodePrivate { - import: None, - backdrop: backdrop.clone().map(AssetLocation::Library), - poster: poster.clone().map(AssetLocation::Library), - source, - }, - public: NodePublic { - parent: None, - federated: None, - description: tmdb_details.as_ref().map(|d| d.overview.to_owned()), - tagline: tmdb_details - .as_ref() - .map(|d| d.tagline.to_owned()) - .flatten(), - title, - index: None, - kind, - children: Vec::new(), - media, - }, - }; - - if args.dry { - println!("{node:?}") - } else { - std::fs::create_dir_all(&path)?; - for (tn, index) in seek_index { - info!("writing index {tn} with {} blocks", index.blocks.len()); - bincode::encode_into_std_write( - index, - &mut File::create( - source_path_e - .as_ref() - .unwrap() - .with_extension(&format!("si.{tn}")), - )?, - bincode::config::standard(), - )?; - } - let f = File::create(path.join(if series { - "directory.json".to_string() - } else { - format!("{ident}.jelly") - }))?; - serde_json::to_writer_pretty(f, &node)?; - } - - Ok(()) - } - Action::Set { .. } => { - // let mut iteminfo: ItemInfo = match File::open(item.clone()) { - // Ok(f) => serde_json::from_reader(f)?, - // Err(e) => { - // warn!("could not load item info: {e}"); - // warn!("using the default instead"); - // ItemInfo { - // common: CommmonInfo { - // poster: None, - // backdrop: None, - // tagline: None, - // description: None, - // title: item.to_str().unwrap().to_string(), - // index: None, - // }, - // duration: 0.0, - // tracks: Default::default(), - // } - // } - // }; - - // if let Some(title) = title { - // iteminfo.title = title; - // } - // if let Some(poster) = poster { - // iteminfo.poster = Some(poster); - // } - // if let Some(d) = description { - // iteminfo.description = Some(d); - // } - // if let Some(d) = tagline { - // iteminfo.tagline = Some(d); - // } - // if clear_inputs { - // iteminfo.tracks = Default::default() - // } - - // // for input_path in input { - // // let input = File::open(input_path.clone()).unwrap(); - // // let mut input = EbmlReader::new(input); - // // import_read(&input_path, &mut input, &mut iteminfo)?; - // // } - - // let k = serde_json::to_string_pretty(&iteminfo)?; - // if args.dry { - // println!("{k}") - // } else { - // let mut f = File::create(item)?; - // f.write_all(k.as_bytes())?; - // } - Ok(()) - } - } -} - -fn make_ident(s: &str) -> String { - let mut out = String::new(); - for s in s.chars() { - match s { - 'a'..='z' => out.push(s), - 'A'..='Z' => out.push(s.to_ascii_lowercase()), - '-' | ' ' | '_' => out.push('-'), - _ => (), - } - } - out -} diff --git a/tools/src/lib.rs b/tools/src/lib.rs deleted file mode 100644 index c5dca31..0000000 --- a/tools/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2023 metamuffin <metamuffin.org> -*/ -pub mod tmdb; diff --git a/tools/src/tmdb.rs b/tools/src/tmdb.rs deleted file mode 100644 index 5f21afd..0000000 --- a/tools/src/tmdb.rs +++ /dev/null @@ -1,95 +0,0 @@ -/* - This file is part of jellything (https://codeberg.org/metamuffin/jellything) - which is licensed under the GNU Affero General Public License (version 3); see /COPYING. - Copyright (C) 2023 metamuffin <metamuffin.org> -*/ -use log::info; -use serde::Deserialize; -use std::io::Write; - -#[derive(Debug, Clone, Deserialize)] -pub struct TmdbQuery { - pub page: usize, - pub results: Vec<TmdbQueryResult>, - pub total_pages: usize, - pub total_results: usize, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct TmdbQueryResult { - pub adult: bool, - pub backdrop_path: Option<String>, - pub genre_ids: Vec<u64>, - pub id: u64, - pub original_language: Option<String>, - pub original_title: Option<String>, - pub overview: String, - pub popularity: f64, - pub poster_path: Option<String>, - pub release_date: Option<String>, - pub title: Option<String>, - pub name: Option<String>, - pub vote_average: f64, - pub vote_count: usize, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct TmdbDetails { - pub adult: bool, - pub backdrop_path: Option<String>, - pub genres: Vec<TmdbGenre>, - pub id: u64, - pub original_language: Option<String>, - pub original_title: Option<String>, - pub overview: String, - pub popularity: f64, - pub poster_path: Option<String>, - pub release_date: Option<String>, - pub title: Option<String>, - pub name: Option<String>, - pub vote_average: f64, - pub vote_count: usize, - pub budget: Option<usize>, - pub homepage: Option<String>, - pub imdb_id: Option<String>, - pub production_companies: Vec<TmdbProductionCompany>, - pub revenue: Option<usize>, - pub tagline: Option<String>, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct TmdbGenre { - pub id: u64, - pub name: String, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct TmdbProductionCompany { - pub id: u64, - pub name: String, - pub logo_path: Option<String>, -} - -pub fn tmdb_search(kind: &str, 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}", - query.replace(" ", "+") - ))? - .json::<TmdbQuery>()?) -} - -pub fn tmdb_details(kind: &str, 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()?) -} - -pub fn tmdb_image(path: &str, out: &mut impl Write) -> anyhow::Result<()> { - info!("downloading image {path:?}"); - let mut res = reqwest::blocking::get(&format!("https://image.tmdb.org/t/p/original{path}"))?; - res.copy_to(out)?; - Ok(()) -} |