Load settings from -c/--config flag and print errors
Ignore hidden files Add add subcommand
This commit is contained in:
parent
9097a18926
commit
cbe7bc51a6
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/target
|
||||
.*
|
||||
|
|
BIN
src/.error.rs.swp
Normal file
BIN
src/.error.rs.swp
Normal file
Binary file not shown.
BIN
src/action/.add.rs.swp
Normal file
BIN
src/action/.add.rs.swp
Normal file
Binary file not shown.
|
@ -1,22 +1,32 @@
|
|||
use argh::FromArgs;
|
||||
use tokio::task;
|
||||
use qbittorrent_web_api::Api;
|
||||
|
||||
use crate::api::ApiClient;
|
||||
use crate::Error;
|
||||
use crate::action::ActionExec;
|
||||
use crate::config::Config;
|
||||
use crate::utils::torrent_to_magnet;
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
#[argh(subcommand, name = "add")]
|
||||
/// add a torrent to qBittorrent (only magnet for the moment)
|
||||
/// add a torrent to qBittorrent (magnet or torrent file)
|
||||
pub struct AddAction {
|
||||
#[argh(switch, short = 'p')]
|
||||
/// pause the torrent instead of starting immediately
|
||||
paused: bool,
|
||||
|
||||
#[argh(positional)]
|
||||
/// the magnet link to add
|
||||
magnet: String,
|
||||
/// the torrent to add
|
||||
torrent: String,
|
||||
}
|
||||
|
||||
impl ActionExec for AddAction {
|
||||
fn exec(&self, _config: &Config) -> Result<(), Error> {
|
||||
unimplemented!();
|
||||
fn exec(&self, config: &Config) -> Result<(), Error> {
|
||||
let magnet = if self.torrent.starts_with("magnet:") {
|
||||
self.torrent.clone()
|
||||
} else {
|
||||
torrent_to_magnet(&self.torrent)
|
||||
};
|
||||
let api = ApiClient::from_config(&config)?;
|
||||
api.add(&magnet, self.paused)
|
||||
}
|
||||
}
|
||||
|
|
15
src/api.rs
15
src/api.rs
|
@ -27,6 +27,21 @@ impl ApiClient {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> {
|
||||
let base_call = self.api.torrent_management();
|
||||
let call = if paused {
|
||||
base_call.add(magnet).paused("true")
|
||||
} else {
|
||||
base_call.add(magnet)
|
||||
};
|
||||
let res = self.rt.block_on(call.send_raw()).context(ApiError)?;
|
||||
if res == "Ok." {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::message(res.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, hash: &str) -> Result<Option<String>, Error> {
|
||||
let res = self.rt.block_on(self.api.torrent_management().properties_raw(hash)).context(ApiError)?;
|
||||
if res == "" {
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
use argh::FromArgs;
|
||||
|
||||
use std::path::{PathBuf};
|
||||
|
||||
use crate::action::Action;
|
||||
|
||||
#[derive(FromArgs, Debug)]
|
||||
/// interact with your qBittorrent instance from the command line
|
||||
pub struct Cli {
|
||||
#[argh(option, short = 'c')]
|
||||
/// path to config file (defaults to ~/.config/qbt/.qbt.toml)
|
||||
pub config: Option<PathBuf>,
|
||||
|
||||
#[argh(subcommand)]
|
||||
pub command: Action,
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ use xdg::{BaseDirectories, BaseDirectoriesError};
|
|||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::cli::Cli;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct Config {
|
||||
pub qbittorrent: ClientConfig,
|
||||
|
@ -46,7 +48,15 @@ impl Config {
|
|||
}
|
||||
|
||||
pub fn from_default_path() -> Result<Config, ConfigError> {
|
||||
Ok(Self::from_path(&Self::default_path()?)?)
|
||||
Self::from_path(&Self::default_path()?)
|
||||
}
|
||||
|
||||
pub fn from_cli(cli: &Cli) -> Result<Config, ConfigError> {
|
||||
if let Some(cfg_path) = &cli.config {
|
||||
Self::from_path(cfg_path)
|
||||
} else {
|
||||
Self::from_default_path()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_host(&self) -> String {
|
||||
|
|
18
src/error.rs
18
src/error.rs
|
@ -7,13 +7,23 @@ use crate::config::ConfigError;
|
|||
#[snafu(visibility(pub))]
|
||||
/// The possible error cases
|
||||
pub enum Error {
|
||||
#[snafu(display("Configuration file reading or parsing error"))]
|
||||
#[snafu(display("{}\nConfiguration file reading or parsing error (see above)", source))]
|
||||
Config { source: ConfigError },
|
||||
#[snafu(display("Torrent/magnet reading or parsing error"))]
|
||||
#[snafu(display("{}\nTorrent/magnet reading or parsing error", source))]
|
||||
Imdl { source: imdl::error::Error },
|
||||
#[snafu(display("qBittorrent API communication error"))]
|
||||
#[snafu(display("{}\nqBittorrent API communication error", source))]
|
||||
Api { source: std::io::Error },
|
||||
#[snafu(display("Internal qBittorrent API error"))]
|
||||
#[snafu(display("{}\nInternal qBittorrent API error", source))]
|
||||
InternalApi { source: qbittorrent_web_api::api_impl::Error },
|
||||
#[snafu(display("Other error:\n{}", message))]
|
||||
Message { message: String },
|
||||
//GenericIOError(std::io::Error),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn message(message: impl Into<String>) -> Error {
|
||||
Self::Message {
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -10,11 +10,20 @@ mod error;
|
|||
use crate::error::{Error, ConfigSnafu as ConfigError};
|
||||
mod utils;
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
let config = Config::from_default_path().context(ConfigError)?;
|
||||
fn fallible_main() -> Result<(), Error> {
|
||||
let cli = Cli::from_args();
|
||||
let config = Config::from_cli(&cli).context(ConfigError)?;
|
||||
// TODO: Make ActionExec type return Option<String>? where None means no data was found and so we abort with a proper exit code
|
||||
cli.command.exec(&config)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let res = fallible_main();
|
||||
if res.is_err() {
|
||||
let err = res.unwrap_err();
|
||||
eprintln!("{}", err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ pub fn input_path<T: AsRef<Path>>(path: T) -> Result<Input, std::io::Error> {
|
|||
|
||||
/// Extracts the infohash of a magnet link
|
||||
pub fn magnet_hash<T: AsRef<str>>(magnet: T) -> String {
|
||||
// TODO: error
|
||||
let magnet = MagnetLink::parse(magnet.as_ref()).expect("Parsing magnet failed");
|
||||
//Ok(magnet.name.expect("Magnet link has no name!"))
|
||||
//Ok(String::from_utf8_lossy(&magnet.infohash.inner.bytes).to_string())
|
||||
|
@ -33,12 +34,14 @@ pub fn magnet_hash<T: AsRef<str>>(magnet: T) -> String {
|
|||
|
||||
/// Extracts the name of a magnet link
|
||||
pub fn magnet_name<T: AsRef<str>>(magnet: T) -> String {
|
||||
// TODO: error
|
||||
let magnet = MagnetLink::parse(magnet.as_ref()).expect("Parsing magnet failed");
|
||||
magnet.name.expect("Magnet link has no name!")
|
||||
}
|
||||
|
||||
/// Extracts the infohash of a torrent file
|
||||
pub fn torrent_hash<T: AsRef<Path>>(torrent: T) -> String {
|
||||
// TODO: error
|
||||
let input = input_path(torrent).unwrap();
|
||||
TorrentSummary::from_input(&input).expect("Parsing torrent file failed").torrent_summary_data().info_hash
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user