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, Box> { 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, Box> { 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::().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::>()) } //https://www.mangaworld.ac/ fn extract_episode_from_updated(&self, body: String) -> Result, Box> { 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::().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::>()) } // async fn episode_openable_link(&self, card: Chapter) -> Result> { // 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> { // 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, Box>{ // let body = self.fetch_search_page(query, page).await?; // self.extract_episode_from_search(body) // } async fn fetch_updated_page(&self, page: usize)-> Result> { 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, Box> { let mut hs = HashMap::::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); } }