#[path = "support/mod.rs"]
mod support;
use anyhow::{Context as _, Result, bail};
use clap::Parser;
use indicatif::{ProgressBar, ProgressStyle};
use std::path::PathBuf;
use sproto::actions::list::FileType;
#[derive(Parser)]
#[command(
name = "sproto-dl",
about = "Download a single file from Synology Drive"
)]
struct Args {
remote_path: String,
local_path: PathBuf,
#[command(flatten)]
conn: support::ConnectionArgs,
}
#[tokio::main]
async fn main() -> Result<()> {
support::init_tracing();
let args = Args::parse();
let client = args.conn.connect().await?;
let view_id = args.conn.resolve_view(&client).await?;
let (parent, filename) = match args.remote_path.rsplit_once('/') {
Some(("", name)) => ("/", name),
Some((parent, name)) => (parent, name),
None => bail!("remote path must be absolute (start with /)"),
};
let nodes = client
.list_dir(view_id, parent)
.await
.with_context(|| format!("failed to list '{parent}'"))?;
let file = nodes
.iter()
.find(|n| n.name == filename && n.file_type == FileType::File)
.with_context(|| format!("file '{filename}' not found in '{parent}'"))?;
let pb = ProgressBar::new(file.file_size);
pb.set_style(
#[allow(
clippy::literal_string_with_formatting_args,
reason = "indicatif template syntax"
)]
ProgressStyle::default_bar()
.template("{msg} [{bar:40}] {bytes}/{total_bytes} ({bytes_per_sec})")
.unwrap()
.progress_chars("=> "),
);
pb.set_message(filename.to_string());
let mut writer = support::ProgressWriter::new(args.local_path.clone(), pb.clone());
client
.download_to(&file.file_id, &mut writer)
.await
.context("download failed")?;
pb.finish_with_message(format!("Saved to {}", args.local_path.display()));
Ok(())
}