Files
AniyomiRust/src/source/mangaworld.rs
T
2026-04-01 00:35:07 +02:00

180 lines
8.3 KiB
Rust

use std::collections::HashMap;
use reqwest::get;
use scraper::{Html, Selector};
use tokio::io::split;
use crate::source::{Chapter, EpisodeListItem, MangaSource, SourceType};
pub struct Mangaworld {
url: String,
hostname:String,
sourcetype: SourceType
}
#[async_trait::async_trait]
impl MangaSource for Mangaworld {
fn get_hostname(&self)->String {
self.hostname.clone()
}
fn get_url(&self) -> String {
self.url.clone()
}
fn new(hostname: String, url: String) -> Self {
Self {
url,
hostname,
sourcetype: crate::source::SourceType::Manga
}
}
async fn listupdated(&self, page: usize) -> Result<Vec<crate::source::Chapter>, Box<dyn std::error::Error + Send + Sync>> {
let body = self.fetch_updated_page(page).await?;
self.extract_episode_from_updated(body)
}
//https://www.mangaworld.mx/archive?keyword=
fn extract_episode_from_search(&self, body: String) -> Result<Vec<crate::source::Chapter>, Box<dyn std::error::Error + Send + Sync>> {
let document = Html::parse_document(&body);
let sel_inner = Selector::parse("div.entry").unwrap();
// let sel_episode_number = Selector::parse("a.xanh").unwrap();
let sel_anime_name = Selector::parse("a.manga-title").unwrap();
let cards = document.select(&sel_inner)
.filter_map(|card| {
// let carde = card.select(&sel_episode_number).next()?;
// let index = carde.inner_html().trim().split(" ").last().unwrap().parse::<usize>().unwrap_or(0);
// log!("index: {}", index);
let carda = card.select(&sel_anime_name).next()?;
// log!("Card a found");
let url = carda.value().attr("href").unwrap_or("").trim().to_owned();
// log!("Card url: {}",url);
let title = carda.inner_html().trim().to_owned();
// log!("Card title: {}", title);
Some(Chapter {
title,
index: 0,
url,
section: 0
})
});
Ok(cards.collect::<Vec<Chapter>>())
}
//https://www.mangaworld.ac/
fn extract_episode_from_updated(&self, body: String) -> Result<Vec<crate::source::Chapter>, Box<dyn std::error::Error + Send + Sync>> {
let document = Html::parse_document(&body);
let sel_inner = Selector::parse("div.entry").unwrap();
let sel_episode_number = Selector::parse("a.xanh").unwrap();
let sel_anime_name = Selector::parse("a.manga-title").unwrap();
let cards = document.select(&sel_inner)
.filter_map(|card| {
let carde = card.select(&sel_episode_number).next()?;
let index = carde.inner_html().trim().split(" ").last().unwrap().parse::<usize>().unwrap_or(0);
// log!("index: {}", index);
let carda = card.select(&sel_anime_name).next()?;
// log!("Card a found");
let url = carda.value().attr("href").unwrap_or("").trim().to_owned();
// log!("Card url: {}",url);
let title = carda.inner_html().trim().to_owned();
// log!("Card title: {}", title);
Some(Chapter {
title,
index,
url,
section: 0
})
});
Ok(cards.collect::<Vec<Chapter>>())
}
// async fn episode_openable_link(&self, card: Chapter) -> Result<String, Box<dyn std::error::Error>> {
// let id= Self::id_extract(&card.url).unwrap();
// let u = format!("{}/api/episode/serverPlayerAnimeWorld?id={}", self.url, id);
// let r = get(u).await?.error_for_status()?.text().await?;
// let b = Html::parse_document(&r);
// let select_source = Selector::parse("source").unwrap();
// Ok(b.select(&select_source).next().unwrap().value().attr("src").unwrap_or("").to_owned())
// }
async fn fetch_search_page(&self, query: String, page: usize) -> Result<String, Box<dyn std::error::Error + Send + Sync>> {
// if page < 1 { page = 1};
let u = format!("{}?keyword={}&page={}",self.get_url(), query, page);
let r = reqwest::get(u).await?.error_for_status()?.text().await?;
return Ok(r);
}
// async fn search(&self, query: String, page: usize) -> Result<Vec<crate::source::Episode>, Box<dyn std::error::Error + Send + Sync>>{
// let body = self.fetch_search_page(query, page).await?;
// self.extract_episode_from_search(body)
// }
async fn fetch_updated_page(&self, page: usize)-> Result<String, Box<dyn std::error::Error + Send + Sync>> {
let p = std::cmp::max(1, page);
let u = format!("{}",self.get_url());
let a = get(u).await?.error_for_status()?.text().await?;
return Ok(a);
}
async fn lib_url_parse(&self, url: String) -> Result<HashMap<String, EpisodeListItem>, Box<dyn std::error::Error + Send + Sync>> {
let mut hs = HashMap::<String, EpisodeListItem>::new();
if let Ok(a) = get(url).await?.error_for_status()?.text().await {
let b = Html::parse_document(&a);
// let select_chapters_wrapper = Selector::parse("").unwrap();
let select_volume_element = Selector::parse(".chapters-wrapper .volume-element").unwrap();
let select_volume_name = Selector::parse(".volume .volume-name").unwrap();
let select_episodes = Selector::parse("div.chapter a.chap").unwrap();
let select_span = Selector::parse("span").unwrap();
// for ep in b.select(&select_episodes) {
// // let alink = ep.value();
// if let Some(span) = ep.select(&select_span).next() {
// hs.insert(span.inner_html(), EpisodeListItem {
// title: format!("Volume {:>4} Capitolo {:>4}",,span.inner_html()),
// url: alink.attr("href").unwrap_or("").trim().to_owned()
// });
// }
// }
for vol in b.select(&select_volume_element) {
if let Some(volname) = vol.select(&select_volume_name).next() {
let volume = volname.text().next();
for ep in vol.select(&select_episodes) {
if let Some(span) = ep.select(&select_span).next() {
let alink = ep.value();
let chapter = span.inner_html();
let x = volume
.and_then(|s| s.split_whitespace().nth(1))
.and_then(|second| second.split_once('.'));
let y = chapter.split_whitespace().nth(1)
.and_then(|second| second.split_once('.'));
let title_vol = match x {
Some((vola,volb)) => {
if volb.is_empty() {
format!("Volume {:>4}", vola)
} else {
format!("Volume {:>4}.{}", vola,volb)
}
},
_ => "".to_owned()
};
let title_cha = match y {
Some((cha,chb)) => {
if chb.is_empty() {
format!("Capitolo {:>4}", cha)
} else {
format!("Capitolo {:>4}.{}", cha,chb)
}
},
_ => "".to_owned()
};
let title_sep = if !title_vol.is_empty() && !title_cha.is_empty() {" "} else {""};
hs.insert(span.inner_html(), EpisodeListItem {
title: format!("{}{}{}", title_vol,title_sep, title_cha),
url: alink.attr("href").unwrap_or("").trim().to_owned()
});
}
}
}
}
}
return Ok(hs);
}
}