diff options
author | metamuffin <metamuffin@disroot.org> | 2023-10-24 19:32:26 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2023-10-24 19:32:26 +0200 |
commit | 42568332b5433c97813e8c291db0fc0d15867b76 (patch) | |
tree | 299ef0d2306b2c986bdbe0df39545a5a2b04f062 /tool/src/main.rs | |
parent | 2fc5931a6ce9bbb75757c4a20022b19778bd91c5 (diff) | |
download | jellything-42568332b5433c97813e8c291db0fc0d15867b76.tar jellything-42568332b5433c97813e8c291db0fc0d15867b76.tar.bz2 jellything-42568332b5433c97813e8c291db0fc0d15867b76.tar.zst |
import -> jellytool
Diffstat (limited to 'tool/src/main.rs')
-rw-r--r-- | tool/src/main.rs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/tool/src/main.rs b/tool/src/main.rs new file mode 100644 index 0000000..1e84bda --- /dev/null +++ b/tool/src/main.rs @@ -0,0 +1,150 @@ +/* + 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> +*/ +#![feature(file_create_new)] + +pub mod import; + +use base64::Engine; +use clap::{Parser, Subcommand}; +use import::import; +use jellycommon::{config::GlobalConfig, Node, NodeKind, NodePrivate, NodePublic}; +use log::{info, warn}; +use rand::random; +use std::{fmt::Debug, fs::File, io::Write, path::PathBuf}; + +#[derive(Parser)] +struct Args { + #[arg(short = 'N', long)] + dry: bool, + #[clap(subcommand)] + action: Action, +} + +#[derive(Subcommand)] +enum Action { + /// Initialize a new jellything instance + Init { + /// Base path of the instance, must either be absolute or relative to the servers pwd + base_path: PathBuf, + #[arg(short, long)] + brand: String, + }, + /// Imports a movie, video or series given media and metadata sources + New { + /// Relative path to the node's parent(!). + path: PathBuf, + /// Search the node by title on TMDB + #[arg(short = 't', long)] + tmdb_search: Option<String>, + /// Search the node by id on TMDB + #[arg(short = 'T', long)] + tmdb_id: Option<String>, + #[arg(long)] + /// Prefix the inferred id with something to avoid collisions + ident_prefix: Option<String>, + /// Copies media into the library + #[arg(long)] + copy: bool, + /// Moves media into the library (potentially destructive operation) + #[arg(long)] + r#move: bool, + /// Marks node as a video + #[arg(long)] + video: bool, + /// Path to the media of the node, required for non-series + #[arg(short, long)] + input: Option<PathBuf>, + /// Marks node as a series + #[arg(short, long)] + series: bool, + }, +} + +fn main() -> anyhow::Result<()> { + env_logger::builder() + .filter_level(log::LevelFilter::Info) + .parse_env("LOG") + .init(); + let args = Args::parse(); + + match args.action { + Action::Init { + base_path: path, + brand, + } => { + info!("creating new instance..."); + std::fs::create_dir_all(path.join("library"))?; + std::fs::create_dir_all(path.join("cache"))?; + std::fs::create_dir_all(path.join("assets"))?; + File::create_new(path.join("assets/front.htm"))? + .write_fmt(format_args!("<h1>My very own jellything instance</h1>"))?; + serde_yaml::to_writer( + File::create_new(path.join("config.yaml"))?, + &GlobalConfig { + brand: brand.clone(), + slogan: "Creative slogan here".to_string(), + asset_path: path.join("assets"), + cache_path: path.join("cache"), + library_path: path.join("library"), + database_path: path.join("database"), + temp_path: "/tmp".into(), + cookie_key: Some( + base64::engine::general_purpose::STANDARD + .encode([(); 32].map(|_| random())), + ), + session_key: Some( + base64::engine::general_purpose::STANDARD + .encode([(); 32].map(|_| random())), + ), + admin_username: "admin".to_string(), + admin_password: "hackme".to_string(), + login_expire: 10, + ..Default::default() + }, + )?; + serde_json::to_writer( + File::create_new(path.join("library/directory.json"))?, + &Node { + public: NodePublic { + kind: NodeKind::Collection, + title: "My Library".to_string(), + ..Default::default() + }, + private: NodePrivate { + ..Default::default() + }, + }, + )?; + info!("{brand:?} is ready!"); + warn!("please change the admin password."); + Ok(()) + } + a @ Action::New { .. } => import(a, args.dry), + } +} + +fn make_ident(s: &str) -> String { + let mut out = String::new(); + for s in s.chars() { + match s { + 'a'..='z' | '0'..='9' => out.push(s), + 'A'..='Z' => out.push(s.to_ascii_lowercase()), + '-' | ' ' | '_' | ':' => out.push('-'), + _ => (), + } + } + out +} + +fn ok_or_warn<T, E: Debug>(r: Result<T, E>) -> Option<T> { + match r { + Ok(t) => Some(t), + Err(e) => { + warn!("{e:?}"); + None + } + } +} |