1use ibdl_common::post::{extension::Extension, NameType};
3use ibdl_extractors::extractor_config::ServerConfig;
4use once_cell::sync::OnceCell;
5use std::{collections::HashMap, path::PathBuf};
6
7use clap::{Parser, Subcommand};
8
9use crate::generate_output_path_precise;
10
11use self::{
12 commands::{pool::Pool, post::Post, search::TagSearch},
13 extra::validate_imageboard,
14};
15
16pub mod commands;
17pub(crate) mod extra;
18
19pub static AVAILABLE_SERVERS: OnceCell<HashMap<String, ServerConfig>> = OnceCell::new();
20
21#[derive(Debug, Subcommand)]
22pub enum Commands {
23 Search(TagSearch),
25 Pool(Pool),
27 Post(Post),
29}
30
31#[derive(Parser, Debug)]
32#[clap(name = "Imageboard Downloader", author, version, about, long_about = None)]
33pub struct Cli {
34 #[clap(subcommand)]
35 pub mode: Commands,
36
37 #[clap(short, long, ignore_case = true, default_value_t = ServerConfig::default(), global = true, value_parser = validate_imageboard)]
41 pub imageboard: ServerConfig,
42
43 #[clap(long, global = true)]
45 pub servers: bool,
46
47 #[clap(short = 'o', value_name = "PATH", help_heading = "SAVE", global = true)]
49 pub output: Option<PathBuf>,
50
51 #[clap(
55 short = 'd',
56 value_name = "NUMBER",
57 global = true,
58 value_parser(clap::value_parser!(u8).range(1..=20)),
59 default_value_t = 5,
60 help_heading = "DOWNLOAD",
61 global = true,
62 )]
63 pub simultaneous_downloads: u8,
64
65 #[clap(short, long, action, help_heading = "GENERAL", global = true)]
71 pub auth: bool,
72
73 #[clap(
77 long = "id",
78 value_parser,
79 global = true,
80 default_value_t = false,
81 help_heading = "SAVE"
82 )]
83 pub save_file_as_id: bool,
84
85 #[clap(
89 long,
90 value_parser,
91 default_value_t = false,
92 help_heading = "SAVE",
93 global = true
94 )]
95 pub cbz: bool,
96
97 #[clap(
99 long,
100 value_parser,
101 default_value_t = false,
102 help_heading = "SAVE",
103 global = true
104 )]
105 pub annotate: bool,
106
107 #[clap(
109 short = 'y',
110 value_parser,
111 default_value_t = false,
112 help_heading = "SAVE",
113 global = true
114 )]
115 pub overwrite: bool,
116}
117
118impl Cli {
119 pub const fn name_type(&self) -> NameType {
120 if self.save_file_as_id {
121 NameType::ID
122 } else {
123 NameType::MD5
124 }
125 }
126
127 pub fn get_extension(&self) -> Option<Extension> {
128 match &self.mode {
129 Commands::Search(args) => {
130 if let Some(ext) = &args.force_extension {
131 return Some(Extension::guess_format(ext));
132 }
133 }
134 Commands::Pool(args) => {
135 if let Some(ext) = &args.force_extension {
136 return Some(Extension::guess_format(ext));
137 }
138 }
139 Commands::Post(_) => {}
140 }
141 None
142 }
143
144 pub fn generate_save_path(&self) -> Result<PathBuf, std::io::Error> {
145 let raw_save_path = if let Some(precise_path) = &self.output {
146 precise_path.to_owned()
147 } else {
148 std::env::current_dir()?
149 };
150
151 let dirname = if self.output.is_some() {
152 generate_output_path_precise(&raw_save_path, self.cbz)
153 } else {
154 raw_save_path
155 };
156
157 Ok(dirname)
158 }
159}