diff options
Diffstat (limited to 'tool/src')
-rw-r--r-- | tool/src/add.rs | 224 | ||||
-rw-r--r-- | tool/src/bin/generate_completions.rs | 5 | ||||
-rw-r--r-- | tool/src/cli.rs | 16 |
3 files changed, 84 insertions, 161 deletions
diff --git a/tool/src/add.rs b/tool/src/add.rs index fdaa14e..6e79381 100644 --- a/tool/src/add.rs +++ b/tool/src/add.rs @@ -1,7 +1,12 @@ +/* + 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) 2025 metamuffin <metamuffin.org> +*/ use crate::cli::Action; -use anyhow::{anyhow, bail, Context}; -use dialoguer::{theme::ColorfulTheme, FuzzySelect, Input, MultiSelect}; -use jellybase::{CONF, SECRETS}; +use anyhow::anyhow; +use dialoguer::{theme::ColorfulTheme, Confirm, FuzzySelect, Input}; +use jellybase::SECRETS; use jellycommon::TraktKind; use jellyimport::trakt::Trakt; use log::warn; @@ -9,76 +14,35 @@ use std::{ fmt::Display, path::{Path, PathBuf}, }; +use tokio::fs::rename; pub async fn add(action: Action) -> anyhow::Result<()> { match action { - Action::Add { - id, - media, - library_path, - } => { + Action::Add { media } => { let theme = ColorfulTheme::default(); - let possible_kinds = [ - TraktKind::Movie, - TraktKind::Season, - TraktKind::Show, - TraktKind::Episode, - ]; - let trakt_kind: Vec<usize> = MultiSelect::with_theme(&theme) - .with_prompt("Media Kind") - .items(&possible_kinds) - .defaults(&[true, false, false, false]) - .interact() - .unwrap(); - let search_kinds = trakt_kind - .iter() - .map(|&i| possible_kinds[i]) - .collect::<Vec<_>>(); - - let library_path = if let Some(library_path) = library_path { - library_path - } else { - let mut directories = Vec::new(); - find_folders(&CONF.media_path, &PathBuf::new(), &mut directories) - .context("listing library directories")?; - - let mut default = 0; - for k in possible_kinds { - match k { - TraktKind::Movie => { - if let Some(i) = directories - .iter() - .position(|d| d.0.to_str().unwrap().contains("movies")) - { - default = i - }; - } - TraktKind::Show => { - if let Some(i) = directories - .iter() - .position(|d| d.0.to_str().unwrap().contains("shows")) - { - default = i - }; - } - _ => (), - } - } - - let target_dir_index = FuzzySelect::with_theme(&theme) - .items(&directories) - .default(default) - .with_prompt("Library Path") - .interact() - .unwrap(); - directories[target_dir_index].0.clone() - }; + // let possible_kinds = [ + // TraktKind::Movie, + // TraktKind::Season, + // TraktKind::Show, + // TraktKind::Episode, + // ]; + // let trakt_kind: Vec<usize> = MultiSelect::with_theme(&theme) + // .with_prompt("Media Kind") + // .items(&possible_kinds) + // .defaults(&[true, false, false, false]) + // .interact() + // .unwrap(); + // let search_kinds = trakt_kind + // .iter() + // .map(|&i| possible_kinds[i]) + // .collect::<Vec<_>>(); + let search_kinds = [TraktKind::Show, TraktKind::Season, TraktKind::Movie]; - let (last_search, trakt_object, trakt_kind) = loop { + let (trakt_object, trakt_kind) = loop { let name: String = Input::with_theme(&theme) .with_prompt("Search by title") - .default(media.as_ref().map(|p| path_to_query(p)).unwrap_or_default()) + .default(path_to_query(&media)) .interact_text() .unwrap(); @@ -105,60 +69,32 @@ pub async fn add(action: Action) -> anyhow::Result<()> { .unwrap(); if let Some(o) = correct { - break (name, results[o].inner.inner().to_owned(), results[o].r#type); + break (results[o].inner.inner().to_owned(), results[o].r#type); } }; - let id = id.unwrap_or_else(|| { - trakt_object.ids.slug.unwrap_or_else(|| { - let o: String = Input::with_theme(&theme) - .with_prompt("Node ID") - .validate_with(validate_id) - .default(make_id(&last_search)) - .interact_text() - .unwrap(); - o - }) - }); - - // TODO - let _ = id; - let _ = library_path; - let _ = trakt_kind; - - // let mut sources = Vec::new(); - // sources.push(ImportSource::Trakt { - // id: trakt_object.ids.trakt.unwrap(), - // kind: trakt_kind, - // }); - // if let Some(media) = media { - // sources.push(ImportSource::Media { - // path: media, - // ignore_metadata: true, - // ignore_attachments: false, - // ignore_chapters: false, - // }) - // } - - // let impo = ImportOptions { id, sources }; + assert_eq!(trakt_kind, TraktKind::Movie); - // let ypath = CONF - // .library_path - // .join(library_path) - // .join(&impo.id) - // .with_extension("yaml"); + let stem = media.file_name().unwrap().to_string_lossy().to_string(); + let stem = stem.split_once(".").unwrap_or((stem.as_str(), "")).0; + let mut newpath = media.parent().unwrap().join(format!( + "{stem}.trakt-{}.mkv", + trakt_object.ids.trakt.unwrap() + )); + let mut n = 1; + while newpath.exists() { + newpath = media.parent().unwrap().join(format!("{stem}.alt-{n}.mkv",)); + n += 1; + } - // if Confirm::with_theme(&theme) - // .with_prompt(format!("Write {:?}?", ypath)) - // .default(true) - // .interact() - // .unwrap() - // { - // File::create(ypath) - // .await? - // .write_all(serde_yaml::to_string(&impo)?.as_bytes()) - // .await?; - // } + if Confirm::with_theme(&theme) + .with_prompt(format!("Rename {media:?} -> {newpath:?}?")) + .default(true) + .interact() + .unwrap() + { + rename(media, newpath).await?; + } Ok(()) } @@ -166,46 +102,30 @@ pub async fn add(action: Action) -> anyhow::Result<()> { } } -fn validate_id(s: &String) -> anyhow::Result<()> { - if &make_id(s) == s { - Ok(()) - } else { - bail!("invalid id") - } -} -fn make_id(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 validate_id(s: &String) -> anyhow::Result<()> { +// if &make_id(s) == s { +// Ok(()) +// } else { +// bail!("invalid id") +// } +// } +// fn make_id(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 path_to_query(path: &Path) -> String { - path.file_stem() - .unwrap() - .to_str() - .unwrap() - .to_string() - .replace("-", " ") - .replace(".", " ") -} - -fn find_folders(base: &Path, path: &Path, out: &mut Vec<PathDisplay>) -> anyhow::Result<()> { - out.push(PathDisplay(path.to_owned())); - for entry in base.join(path).read_dir()? { - let entry = entry?; - let child_path = path.join(entry.file_name()); - if entry.path().is_dir() { - find_folders(base, &child_path, out)?; - } - } - Ok(()) + let stem = path.file_name().unwrap().to_string_lossy().to_string(); + let stem = stem.split_once(".").unwrap_or((stem.as_str(), "")).0; + stem.replace("-", " ") } pub struct PathDisplay(PathBuf); diff --git a/tool/src/bin/generate_completions.rs b/tool/src/bin/generate_completions.rs index 9f0917f..1afce29 100644 --- a/tool/src/bin/generate_completions.rs +++ b/tool/src/bin/generate_completions.rs @@ -1,3 +1,8 @@ +/* + 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) 2025 metamuffin <metamuffin.org> +*/ use clap::{CommandFactory, Parser, ValueEnum}; use clap_complete::{generate_to, Shell}; use jellytool::cli; diff --git a/tool/src/cli.rs b/tool/src/cli.rs index 2e12c81..b51b135 100644 --- a/tool/src/cli.rs +++ b/tool/src/cli.rs @@ -1,3 +1,8 @@ +/* + 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) 2025 metamuffin <metamuffin.org> +*/ use clap::{arg, Parser, ValueEnum}; use std::path::PathBuf; @@ -7,17 +12,10 @@ pub type Args = Action; #[clap(version, about)] /// Tool for administering a Jellything instance pub enum Action { - /// Interactive wizard for adding new nodes + /// Interactive wizard for renaming files Add { - /// ID of the new node; inferred if not specified - #[arg(short, long)] - id: Option<String>, /// Path to the media of this node. - #[arg(short, long)] - media: Option<PathBuf>, - /// Path of the new node within the library - #[arg(short, long)] - library_path: Option<PathBuf>, + media: PathBuf, }, /// Migrate the database by export or import to JSON Migrate { |