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
use anyhow::Result;
use async_trait::async_trait;
use client::{ClientBuilder, Info};
use regex::RegexSet;
use std::{path::Path, time::Duration};
use tokio::fs;
use url::Url;

pub mod client;
pub use client::Client;

pub mod extractors;
use extractors::{hentai_foundry::HentaiFoundry, youtube::Youtube};

#[derive(Debug)]
pub struct Video {
    pub title: String,
    pub duration: Duration,
    pub tags: Vec<String>,
    pub description: Option<String>,
    pub author: Option<String>,
}
#[derive(Debug)]
pub struct Image {
    pub width: Option<u32>,
    pub height: Option<u32>,
    pub url: Url,
}

#[async_trait]
pub trait Extractor {
    fn url_tester(&self) -> RegexSet;
    async fn get_info(&self, url: &str) -> Result<Info>;
}

#[async_trait]
pub trait VideoExtractor: Extractor {
    async fn get_video(&self, url: &str) -> Result<Video>;
}

#[async_trait]
pub trait ImageExtractor: Extractor {
    async fn get_image(url: &str) -> Result<Image>;
}

pub async fn start(url: &str) -> Result<()> {
    let client = ClientBuilder::new().build()?;

    // youtube::main(url).await?;

    // let video = Youtube::get_video(url).await?;
    let image = HentaiFoundry::get_image(url).await?;

    dbg!(&image);

    println!("{}", &image.url);
    // instagram::download().await?;

    Ok(())
}

/// A struct containing vital information about a comic.
#[derive(Debug)]
pub struct ImageAlbum {
    /// The authors of the comic
    pub authors: Vec<String>,
    pub categories: Vec<String>,
    /// The characters appearing in the comic.
    pub characters: Vec<String>,
    pub cover: Page,
    /// The unique identifier of the comic.
    ///
    /// This is guaranteed to be unique only on the original site,
    /// as such it should always be used in conjunction with the site property.
    pub id: String,
    pub groups: Vec<String>,
    /// The language this comic is avaible.
    ///
    /// This is usually one but it is a vec for api reason.
    pub languages: Vec<String>, // TODO: Explain why it's a vec in detail
    pub pages: Vec<Page>,
    /// The site this comic was downloaded from
    pub site: String,
    pub tags: Vec<String>,
    pub title: String,
    /// Whether or not the comic was translated from another language.
    pub translated: bool,
    /// Upload date in UNIX time-stamp format.
    pub upload_date: f64,
}

#[derive(Debug)]
pub struct Page {
    pub file_name: String,
    pub heigth: Option<u32>,
    pub url: Url,
    pub width: Option<u32>,
}

impl ImageAlbum {
    pub async fn download(&self) -> Result<()> {
        for page in self.pages.iter() {
            let path = format!("temp/{}/{}", self.site, self.id);
            println!("{}", &path);

            fs::create_dir_all(&path).await?;

            let full_path = format!("{}/{}", &path, page.file_name);
            let full_path = Path::new(&full_path);

            println!("{:#?}", full_path);

            let image = reqwest::get(page.url.to_owned()).await?.bytes().await?;
            fs::write(full_path, image).await?;
        }

        Ok(())
    }
}