use std::{env, process::Command as StdCmd}; use anyhow::{bail, Context, Result}; use clap::Parser; use log::debug; use url::Url; use yt::{ downloader::{Downloadable, Downloader}, YtccListData, }; use crate::args::{Args, Command}; mod args; fn main() -> Result<()> { let args = Args::parse(); cli_log::init_cli_log!(); let playspec: Vec<Downloadable> = match args.subcommand { Command::Id { ids } => { let mut output = Vec::with_capacity(ids.len()); for id in ids { debug!("Adding {}", id); let mut ytcc = StdCmd::new("ytcc"); ytcc.args([ "--output", "json", "list", "--watched", "--unwatched", "--attributes", "url", "--ids", id.to_string().as_str(), ]); let json = serde_json::from_slice::<Vec<YtccListData>>( &ytcc.output().context("Failed to get url from id")?.stdout, ) .context("Failed to deserialize json output")?; if json.is_empty() { bail!("Could not find a video with id: {}", id); } assert_eq!(json.len(), 1); let json = json.first().expect("Has only one element"); debug!("Id resolved to: '{}'", &json.url); output.push(Downloadable { url: Url::parse(&json.url)?, id: Some(json.id), }) } output } Command::Url { urls } => { let mut output = Vec::with_capacity(urls.len()); for url in urls { output.push(Downloadable { url: Url::parse(&url).context("Failed to parse url")?, id: None, }) } output } }; debug!("Initializing downloader"); let downloader = Downloader::new(playspec)?; downloader .consume() .context("Failed to consume downloader")?; Ok(()) }