#[macro_use]
extern crate log;
extern crate dlscan_tools;
extern crate rayon;
extern crate reqwest;
pub use dlscan_tools::*;
use rayon::prelude::*;
use reqwest::{blocking::get, Result, StatusCode};
use std::sync::mpsc::SyncSender;
use std::{
convert::AsRef,
fs::{remove_file, File},
io::copy,
iter::Iterator,
string::ToString,
};
use zip::{read::ZipArchive, result::ZipResult};
pub struct ScanTrad<'a>(&'a str);
pub struct LelScan<'b>(&'b str);
pub struct MangaJar<'c>(&'c str);
pub struct MangaHub<'d>(&'d str);
pub struct ScanOp<'e>(&'e str);
impl<'a> Scraping for ScanTrad<'a> {}
impl<'b> Scraping for LelScan<'b> {}
impl<'c> Scraping for MangaJar<'c> {}
impl<'d> Scraping for MangaHub<'d> {}
impl<'e> Scraping for ScanOp<'e> {}
impl ScanTrad<'_> {
fn unzip_chapter(arch: &str, manga: &str, snder: &SyncSender<Page>) -> ZipResult<()> {
let mut zip = ZipArchive::new(File::open(arch)?)?;
let chap = &arch[..arch.len() - 4];
for index in 0..zip.len() {
let mut buff = Vec::new();
copy(&mut zip.by_index(index)?, &mut buff)?;
if let Err(e) = snder.send((
index as u32,
chap.to_owned(),
manga.to_owned(),
"scantrad".to_owned(),
buff,
)) {
error!("Failed to send Page - cause: {}", e);
}
}
remove_file(arch)?;
info!("{} - Chapter {} Completed", manga, chap);
Ok(())
}
}
impl ScanScraping for ScanTrad<'_> {
fn subpath<T: AsRef<str>>(path: T) -> String {
"https://scantrad.net/".to_owned() + path.as_ref()
}
fn gen_list(manga_list: &[&str]) -> Result<Vec<String>> {
Ok(
Self::links_from(&Self::subpath("mangas"), "a.home-manga", "href", |y| {
manga_list.contains(&&y[1..])
})?
.into_par_iter()
.map(|x| x[1..].to_owned())
.collect(),
)
}
fn start_dl(manga_list: &[&str], snder: SyncSender<Page>) -> Result<()> {
for name in Self::gen_list(manga_list)? {
for link in Self::links_from(&Self::subpath(&name), "a.chr-button", "href", |y| {
y.find("download") != None
})? {
Self::dl_chapter(&name, &link, &snder)?;
}
}
info!("ScanTrad - Completed");
Ok(())
}
fn dl_chapter(manga: &str, link: &str, snder: &SyncSender<Page>) -> Result<()> {
let name = link.split('/').last().unwrap().to_owned() + ".zip";
if let Err(e) = Self::stack_in_file(get(&Self::subpath(&link[1..]))?, &name) {
error!("Failed to stack file - cause: {}", e);
}
if let Err(e) = Self::unzip_chapter(&name, manga, snder) {
error!("Failed to unzip {} - cause: {}", &name, e);
}
Ok(())
}
}
impl ScanScraping for LelScan<'_> {
fn subpath<T: AsRef<str>>(path: T) -> String {
"https://www.lelscan-vf.com/".to_owned() + path.as_ref()
}
fn gen_list(manga_list: &[&str]) -> Result<Vec<String>> {
Ok(Self::links_from(
&Self::subpath("changeMangaList?type=text"),
"a.alpha-link",
"href",
|y| manga_list.contains(&y.split('/').last().unwrap()),
)?)
}
fn start_dl(manga_list: &[&str], snder: SyncSender<Page>) -> Result<()> {
for name in Self::gen_list(manga_list)? {
let manga = name.split('/').last().unwrap();
for link in Self::links_from(&name, "a", "href", |y| y.find(&name) != None)? {
Self::dl_chapter(&manga, &link, &snder)?;
}
}
info!("LelScan - Completed");
Ok(())
}
fn dl_chapter(manga: &str, link: &str, snder: &SyncSender<Page>) -> Result<()> {
let chap = link.split('/').last().unwrap();
let mut index = 0;
for img in Self::links_from(link, "img.img-responsive", "data-src", |_| true)? {
let mut buff = Vec::new();
copy(&mut get(&img)?, &mut buff).unwrap();
if let Err(e) = snder.send((
index,
chap.to_owned(),
manga.to_owned(),
"lelscan".to_owned(),
buff,
)) {
error!("Failed to send Page - cause: {}", e);
}
index += 1;
}
info!("{} - Chapter {} Completed", manga, chap);
Ok(())
}
}
impl ScanScraping for MangaJar<'_> {
fn subpath<T: AsRef<str>>(path: T) -> String {
"https://mangajar.com/".to_owned() + path.as_ref()
}
fn gen_list(manga_list: &[&str]) -> Result<Vec<String>> {
let mut list = Vec::new();
(1..149)
.into_par_iter()
.filter_map(|i: i32| {
match Self::links_from(
&Self::subpath("manga?page=".to_owned() + &i.to_string()),
"a.card-about",
"href",
|_| true,
) {
Ok(links) => match &*links {
[] => None,
page => Some(
page.to_owned()
.into_par_iter()
.filter(|y| manga_list.contains(&y.split('/').last().unwrap()))
.collect(),
),
},
Err(e) => {
error!("Cannot request '.../search/page/{}' - cause: {}", i, e);
None
}
}
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|mut vec| list.append(&mut vec));
Ok(list)
}
fn start_dl(manga_list: &[&str], snder: SyncSender<Page>) -> Result<()> {
for name in Self::gen_list(manga_list)? {
let manga = name.split('/').last().unwrap();
for link in Self::links_from(
&Self::subpath(name[1..].to_owned() + "/chaptersList"),
"a",
"href",
|y| y != "javascript:void(0)",
)? {
Self::dl_chapter(&manga, &Self::subpath(&link[1..]), &snder)?;
}
}
info!("MangaJar - Completed");
Ok(())
}
fn dl_chapter(manga: &str, link: &str, snder: &SyncSender<Page>) -> Result<()> {
let chap = link.split('/').last().unwrap();
let mut index = 0;
for img in Self::links_from(link, "img", "src", |y| {
y.find("https://static.mangajar.com/pages/") != None
})? {
let mut buff = Vec::new();
copy(&mut get(&img)?, &mut buff).unwrap();
if let Err(e) = snder.send((
index,
chap.to_owned(),
manga.to_owned(),
"mangajar".to_owned(),
buff,
)) {
error!("Failed to send Page - cause: {}", e);
}
index += 1;
}
info!("{} - Chapter {} Completed", manga, chap);
Ok(())
}
}
impl ScanScraping for MangaHub<'_> {
fn subpath<T: AsRef<str>>(path: T) -> String {
"https://mangahub.io/".to_owned() + path.as_ref()
}
fn gen_list(manga_list: &[&str]) -> Result<Vec<String>> {
let mut list = Vec::new();
(1..100)
.into_par_iter()
.filter_map(|i| {
match Self::links_from(
&Self::subpath(format!("search/page/{}", i)),
"a",
"href",
|y| y.find("manga/") != None,
) {
Ok(links) => match &*links {
[] => None,
page => Some(
page.to_owned()
.into_par_iter()
.filter(|y| manga_list.contains(&y.split('/').last().unwrap()))
.collect(),
),
},
Err(e) => {
error!("Cannot request '.../search/page/{}' - cause: {}", i, e);
None
}
}
})
.collect::<Vec<_>>()
.into_iter()
.for_each(|mut vec| list.append(&mut vec));
list.sort();
list.dedup();
Ok(list)
}
fn start_dl(manga_list: &[&str], snder: SyncSender<Page>) -> Result<()> {
for name in Self::gen_list(manga_list)? {
let manga = name.split('/').last().unwrap();
for link in Self::links_from(&name, "a._2U6DJ", "href", |_| true)? {
Self::dl_chapter(&manga, &link, &snder)?;
}
}
info!("MangaHub - Completed");
Ok(())
}
fn dl_chapter(manga: &str, link: &str, snder: &SyncSender<Page>) -> Result<()> {
let chap = &link.split('/').last().unwrap()[8..];
let url = &Self::links_from(link, "img.PB0mN", "src", |_| true)?[0];
'images: for i in 1.. {
let img = url[0..url.rfind('/').unwrap() + 1].to_owned() + &i.to_string();
for ext in &[".jpg", ".png", ".webp"] {
let image = img.to_owned() + ext;
match get(&image) {
Ok(mut content) if content.status() == StatusCode::OK => {
let mut buff = Vec::new();
copy(&mut content, &mut buff).unwrap();
if let Err(e) = snder.send((
i,
chap.to_owned(),
manga.to_owned(),
"mangahub".to_owned(),
buff,
)) {
error!("Failed to send Page - cause: {}", e);
}
continue 'images;
}
Err(e) => return Err(e),
_ => (),
}
}
break;
}
info!("{} - Chapter {} Completed", manga, chap);
Ok(())
}
}
impl ScanScraping for ScanOp<'_> {
fn subpath<T: AsRef<str>>(path: T) -> String {
"https://scan-op.com/".to_owned() + path.as_ref()
}
fn gen_list(manga_list: &[&str]) -> Result<Vec<String>> {
Ok(Self::links_from(
&Self::subpath("changeMangaList?type=text"),
"a.alpha-link",
"href",
|y| manga_list.contains(&y.split('/').last().unwrap()),
)?)
}
fn start_dl(manga_list: &[&str], sender: SyncSender<Page>) -> Result<()> {
for name in Self::gen_list(manga_list)? {
let manga = name.split('/').last().unwrap();
for link in Self::links_from(&name, "a", "href", |y| y.find(&name) != None)? {
Self::dl_chapter(&manga, &link, &sender)?;
}
}
info!("ScanOp - Completed");
Ok(())
}
fn dl_chapter(manga: &str, link: &str, snder: &SyncSender<Page>) -> Result<()> {
let chap = link.split('/').last().unwrap();
let mut index = 0;
for img in Self::links_from(link, "img.img-responsive", "data-src", |_| true)? {
let mut buff = Vec::new();
copy(&mut get(&img)?, &mut buff).unwrap();
if let Err(e) = snder.send((
index,
chap.to_owned(),
manga.to_owned(),
"scanop".to_owned(),
buff,
)) {
error!("Failed to send Page - cause: {}", e);
}
index += 1;
}
info!("{} - Chapter {} Completed", manga, chap);
Ok(())
}
}