diff --git a/src/main.rs b/src/main.rs index f005bdb..eeb0235 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use clap::Parser; use std::error::Error; use std::fs::File; use std::path::{Path, PathBuf}; +use std::process::Command; use walkdir::WalkDir; #[derive(Parser, Debug)] @@ -24,6 +25,10 @@ struct Args { /// Rename flag (whether to rename root directory of torrent, if exists) #[arg(short = 'r', long = "rename", default_value_t = false)] rename: bool, + + /// Do no harm, only print actions + #[arg(short = 'n', long = "dry-run", default_value_t = false)] + dry_run: bool, } fn find_torrent_files(start_path: &Path) -> Vec { @@ -50,19 +55,71 @@ enum TorrentType { fn get_torrent_type(torrent: &Path) -> Result> { let f = File::open(torrent)?; let value: Value = bt_bencode::from_reader(f)?; - let torrenttype = match value.get("info").unwrap().get("files") { + let torrenttype = match value + .get("info") + .ok_or("torrent sould have 'info' section")? + .get("files") + { Some(_) => TorrentType::Directory( value .get("info") .and_then(|v| v.get("name")) .and_then(|v| v.as_str()) - .unwrap() + .ok_or("torrent with multiple files should have recommended directory name")? .to_owned(), ), _ => TorrentType::SingleFile, }; Ok(torrenttype) } +fn make_destination(torrent: &Path, source: &Path, dest: &Path) -> PathBuf { + let filename = Path::new( + torrent + .file_stem() + .expect("torrent file should have '.torrent' extension"), + ); + let rel_path = torrent + .parent() + .expect("torrent file should have a parent directory") + .strip_prefix(source) + .expect("torrent file should have prefix equal to source"); + [dest, rel_path, filename].iter().collect() +} + +fn exec_transmission_remote( + source: &Path, + dest: &Path, + torrent_type: &TorrentType, + rename: bool, + dry_run: bool, +) -> Result<(), Box> { + let mut command = Command::new("transmission-remote"); + command + .arg("--json") + .arg("--add") + .arg(source) + .arg("--download-dir") + .arg(dest); + if rename { + if let TorrentType::Directory(old_name) = torrent_type { + command + .arg("--rename") + .arg(dest) + .arg("--path") + .arg(old_name); + } + } + println!( + "Running {:?} with {:?}", + command.get_program(), + command.get_args() + ); + if !dry_run { + let output = command.output()?; + println!("Result: {:?}", output); + } + Ok(()) +} fn main() { let args = Args::parse(); @@ -72,8 +129,20 @@ fn main() { println!("Destination path: {}", args.destination); println!("Rename: {}", args.rename); let source = Path::new(&args.source); + let dest = Path::new(&args.destination); let torrent_files = find_torrent_files(source); for file in torrent_files { - println!("{:?}", get_torrent_type(&file)); + // println!("{:?}", get_torrent_type(&file)); + // println!("{:?}", make_destination(&file, source, dest)); + let torrent_type = get_torrent_type(&file).unwrap(); + let destination = make_destination(&file, source, dest); + exec_transmission_remote( + &file, + &destination, + &torrent_type, + args.rename, + args.dry_run, + ) + .unwrap(); } }