rogue_tremolo 0.1.1

Client agnostic torrent synchronization
Documentation
use crate::database::Database;
use crate::options::{get_config, Client, Software};
use crate::torrent::Torrent;
use colored::Colorize;
use log::info;
use qbittorrent_api::Status::Success;
use qbittorrent_api::{QBittorrentClientFactory, QBittorrentClientOptions};
use rogue_logging::Error;
use std::path::PathBuf;
use std::process::ExitCode;

pub async fn push_command(client_id: String, category: Option<String>) -> Result<ExitCode, Error> {
    let options = get_config()?;
    let client = Client::get(client_id, &options)?;
    let db = Database::new(&options, &client)?;
    let torrents = db
        .metadata
        .get_all()
        .await?
        .into_iter()
        .filter(|(_, torrent)| {
            if let Some(category) = category.clone() {
                category == torrent.category
            } else {
                true
            }
        })
        .map(|(hash, torrent)| {
            let path = db
                .files
                .get(hash)
                .expect("get torrent file should not fail")
                .expect("torrent file should exist");
            (path, torrent)
        })
        .collect();
    match client.software {
        Software::Deluge => {
            return Err(Error {
                message: "Push is not implemented for Deluge".to_owned(),
                ..Error::default()
            })
        }
        Software::QBittorrent => add_qbit_torrents(&client, torrents).await?,
    };
    Ok(ExitCode::SUCCESS)
}

async fn add_qbit_torrents(
    client: &Client,
    torrents: Vec<(PathBuf, Torrent)>,
) -> Result<(), Error> {
    let client_options = QBittorrentClientOptions {
        host: client.host.clone(),
        username: client.username.clone().unwrap_or_default(),
        password: client.password.clone(),
        user_agent: None,
        rate_limit_duration: None,
        rate_limit_count: None,
    };
    let factory = QBittorrentClientFactory {
        options: client_options,
    };
    let mut client = factory.create();
    let response = client.login().await?;
    if response != Success {
        return Err(Error {
            action: "login".to_owned(),
            domain: Some("qBittorrent API".to_owned()),
            ..Error::default()
        });
    }
    let mut count = 0;
    for (path, torrent) in torrents {
        let options = torrent.to_qbittorrent_add_options();
        let response = client.add_torrent(options, path).await?;
        if response.result == Some(true) {
            count += 1;
        }
    }
    info!("{} {count} torrents", "Pushed".bold());
    Ok(())
}