use anyhow::Context as _;
mod args; pub(crate) use args::*;
mod args_config; pub(crate) use args_config::*;
mod cmd_clean; pub(crate) use cmd_clean::*;
mod cmd_group; pub(crate) use cmd_group::*;
mod cmp; pub(crate) use cmp::*;
mod config; pub(crate) use config::*;
mod float; pub(crate) use float::*;
mod fmt; pub(crate) use fmt::*;
mod global; pub(crate) use global::*;
mod group; pub(crate) use group::*;
mod group_torrent; pub(crate) use group_torrent::*;
mod info_hash; pub(crate) use info_hash::*;
mod match_; pub(crate) use match_::*;
mod parse; pub(crate) use parse::*;
mod pin_reason; pub(crate) use pin_reason::*;
mod requirement; pub(crate) use requirement::*;
mod rule; pub(crate) use rule::*;
mod rule_result; pub(crate) use rule_result::*;
mod serde_util; pub(crate) use serde_util::*;
mod torrent; pub(crate) use torrent::*;
mod torrent_state; pub(crate) use torrent_state::*;
mod tracker; pub(crate) use tracker::*;
mod units; pub(crate) use units::*;
#[cfg(test)] mod requirement_test;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args: crate::Args = clap::Parser::parse();
let mut config = args.config.read()?;
if config.age_d_max_weight == 0.0
&& config.age_d_min_weight == 0.0
&& config.copies_weight == 0.0
&& config.last_activity_d_weight == 0.0
&& config.no_scored_torrents_weight == 0.0
&& config.seeder_count_weight == 0.0
&& config.size_weight == 0.0
{
eprintln!("WARN: All weights are zero, setting seeder-count-weight to 1.0");
config.seeder_count_weight = 1.0;
}
let http = reqwest::Client::builder()
.user_agent("qbt-clean/0")
.connect_timeout(std::time::Duration::from_secs(60))
.default_headers((&config.qbt_headers).try_into()?)
.timeout(std::time::Duration::from_secs(600))
.cookie_store(true)
.build().unwrap();
let mut qbt = config.qbt_url.clone();
qbt.set_username("").map_err(|()| anyhow::Error::msg("Invalid qbt_url"))?;
qbt.set_password(None).map_err(|()| anyhow::Error::msg("Invalid qbt_url"))?;
http.post(qbt.join("/api/v2/auth/login")?)
.form(&[
("username", config.qbt_url.username()),
("password", config.qbt_url.password().unwrap_or("")),
])
.send().await.context("Sending login request")?
.error_for_status().context("Login request status")?;
eprintln!("Logged in.");
let global = crate::Global {
config,
http,
now: std::time::SystemTime::now(),
qbt,
};
let main_result = async {
match args.command {
crate::Command::Clean => cmd_clean(&global, false).await,
crate::Command::Group(a) => cmd_group(a, &global).await,
crate::Command::Simulate => cmd_clean(&global, true).await,
}
}.await;
let r = global.http.post(global.qbt.join("/api/v2/auth/logout")?)
.send().await?
.error_for_status();
if let Err(err) = r {
eprintln!("Warning: Faled to log out: {}", err);
}
main_result
}