1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
pub use clap;
use clap::ValueEnum;
use ibdl_common::{post::rating::Rating, ImageBoards};
pub use owo_colors;
use std::ops::Deref;
use std::path::{Path, PathBuf};

pub mod async_queue;
pub mod cli;
pub mod error;
pub mod progress_bars;

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct ImageBoardArg(ImageBoards);

#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct RatingArg(pub Rating);

impl ValueEnum for RatingArg {
    fn value_variants<'a>() -> &'a [Self] {
        &[
            Self(Rating::Safe),
            Self(Rating::Questionable),
            Self(Rating::Explicit),
        ]
    }
    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
        match self.0 {
            Rating::Safe => {
                Some(clap::builder::PossibleValue::new("safe").help(
                    "Represents posts that are don't involve nothing suggestive or sensitive",
                ))
            }
            Rating::Questionable => Some(clap::builder::PossibleValue::new("questionable").help(
                "Represents posts that have some degree of nudity or sexually suggestive elements",
            )),
            Rating::Explicit => Some(clap::builder::PossibleValue::new("explicit").help(
                "Represents posts that have explicit elements of pornography, gore, death, etc",
            )),
            _ => None,
        }
    }
}

impl Deref for RatingArg {
    type Target = Rating;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl ValueEnum for ImageBoardArg {
    fn value_variants<'a>() -> &'a [Self] {
        &[
            Self(ImageBoards::Danbooru),
            Self(ImageBoards::E621),
            Self(ImageBoards::Rule34),
            Self(ImageBoards::Gelbooru),
            Self(ImageBoards::Realbooru),
            Self(ImageBoards::Konachan),
        ]
    }

    fn to_possible_value(&self) -> ::std::option::Option<clap::builder::PossibleValue> {
        match self.0 {
            ImageBoards::Danbooru => {
                Some(
                    clap::builder::PossibleValue::new("danbooru")
                        .help(
                            "Represents the website https://danbooru.donmai.us or it's safe variant https://safebooru.donmai.us",
                        ),
                )
            }
            ImageBoards::E621 => {
                Some(
                    clap::builder::PossibleValue::new("e621")
                        .help(
                            "Represents the website https://e621.net or it's safe variant https://e926.net",
                        ),
                )
            }
            ImageBoards::Rule34 => {
                Some(
                    clap::builder::PossibleValue::new("rule34")
                        .help("Represents the website https://rule34.xxx"),
                )
            }
            ImageBoards::Realbooru => {
                Some(
                    clap::builder::PossibleValue::new("realbooru")
                        .help("Represents the website http://realbooru.com"),
                )
            }
            ImageBoards::Konachan => {
                Some(
                    clap::builder::PossibleValue::new("konachan")
                        .help(
                            "Represents the website https://konachan.com or it's safe variant https://konachan.net",
                        ),
                )
            }
            ImageBoards::Gelbooru => {
                Some(
                    clap::builder::PossibleValue::new("gelbooru")
                        .help("Represents the website https://gelbooru.com"),
                )
            }
        }
    }
}

impl Deref for ImageBoardArg {
    type Target = ImageBoards;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

#[inline]
pub fn generate_output_path(
    main_path: &Path,
    imageboard: ImageBoards,
    tags: &[String],
    cbz_mode: bool,
) -> PathBuf {
    let tag_string = tags.join(" ");
    let tag_path_string = if tag_string.contains("fav:") {
        String::from("Favorites")
    } else if cfg!(windows) {
        tag_string.replace(':', "_")
    } else {
        tag_string
    };

    let pbuf = main_path.join(Path::new(&imageboard.to_string()));

    if cbz_mode {
        return pbuf.join(Path::new(&format!("{}.cbz", tag_path_string)));
    }
    pbuf.join(Path::new(&tag_path_string))
}

/// This function creates the destination directory without creating additional ones related to
/// the selected imageboard or tags used.
#[inline]
pub fn generate_output_path_precise(main_path: &Path, cbz_mode: bool) -> PathBuf {
    if cbz_mode {
        return PathBuf::from(&format!("{}.cbz", main_path.display()));
    }
    main_path.to_path_buf()
}