aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--tool/Cargo.toml (renamed from import/Cargo.toml)2
-rw-r--r--tool/src/import/infojson.rs (renamed from import/src/infojson.rs)0
-rw-r--r--tool/src/import/mod.rs (renamed from import/src/main.rs)158
-rw-r--r--tool/src/import/tmdb.rs (renamed from import/src/tmdb.rs)0
-rw-r--r--tool/src/main.rs150
7 files changed, 163 insertions, 151 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b19cb99..9de2869 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1492,7 +1492,7 @@ dependencies = [
]
[[package]]
-name = "jellything-import"
+name = "jellytool"
version = "0.1.0"
dependencies = [
"anyhow",
diff --git a/Cargo.toml b/Cargo.toml
index 9ca423a..9e9388e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,7 +3,7 @@ members = [
"server",
"remuxer",
"common",
- "import",
+ "tool",
"matroska",
"ebml_derive",
"client",
diff --git a/import/Cargo.toml b/tool/Cargo.toml
index 9f0912a..c9d46f1 100644
--- a/import/Cargo.toml
+++ b/tool/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "jellything-import"
+name = "jellytool"
version = "0.1.0"
edition = "2021"
diff --git a/import/src/infojson.rs b/tool/src/import/infojson.rs
index dd2151b..dd2151b 100644
--- a/import/src/infojson.rs
+++ b/tool/src/import/infojson.rs
diff --git a/import/src/main.rs b/tool/src/import/mod.rs
index c274e54..e148c98 100644
--- a/import/src/main.rs
+++ b/tool/src/import/mod.rs
@@ -1,141 +1,25 @@
-/*
- 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 infojson;
pub mod tmdb;
+use crate::{make_ident, ok_or_warn, Action};
use anyhow::Context;
-use base64::Engine;
-use clap::{Parser, Subcommand};
use infojson::{parse_upload_date, YVideo};
use jellycommon::{
- config::GlobalConfig, AssetLocation, LocalTrack, MediaInfo, MediaSource, Node, NodeKind,
- NodePrivate, NodePublic, Rating,
+ AssetLocation, LocalTrack, MediaInfo, MediaSource, Node, NodeKind, NodePrivate, NodePublic,
+ Rating,
};
use jellymatroska::read::EbmlReader;
use jellyremuxer::import::import_metadata;
use log::{info, warn};
-use rand::random;
use std::{
collections::BTreeMap,
- fmt::Debug,
fs::{remove_file, File},
io::{stdin, BufReader, Write},
- path::PathBuf,
};
-use tmdb::{tmdb_details, tmdb_image, tmdb_search};
-
-#[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();
+use tmdb::{tmdb_details, tmdb_image};
- 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(())
- }
+pub(crate) fn import(action: Action, dry: bool) -> anyhow::Result<()> {
+ match action {
Action::New {
path,
tmdb_id,
@@ -156,7 +40,7 @@ fn main() -> anyhow::Result<()> {
Some(id.parse().unwrap())
} else if let Some(title) = tmdb_search {
let tmdb_key = std::env::var("TMDB_API_KEY").context("tmdb api key required")?;
- let results = crate::tmdb_search(tmdb_kind, &title, &tmdb_key)?;
+ let results = tmdb::tmdb_search(tmdb_kind, &title, &tmdb_key)?;
info!("results:");
for (i, r) in results.results.iter().enumerate() {
info!(
@@ -237,7 +121,7 @@ fn main() -> anyhow::Result<()> {
let source_path = input.as_ref().map(|_| path.join(format!("source.mkv")));
let (mut poster, mut backdrop) = (None, None);
- if !args.dry {
+ if !dry {
std::fs::create_dir_all(&path)?;
poster = file_meta
@@ -362,7 +246,7 @@ fn main() -> anyhow::Result<()> {
},
};
- if args.dry {
+ if dry {
println!("{}", serde_json::to_string_pretty(&node)?);
} else {
if let Some(source_path) = source_path {
@@ -388,28 +272,6 @@ fn main() -> anyhow::Result<()> {
Ok(())
}
- }
-}
-
-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
- }
+ _ => unreachable!(),
}
}
diff --git a/import/src/tmdb.rs b/tool/src/import/tmdb.rs
index 5f21afd..5f21afd 100644
--- a/import/src/tmdb.rs
+++ b/tool/src/import/tmdb.rs
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
+ }
+ }
+}