import chalk from "chalk" ; import fetch from "node-fetch-extra" ; import { JSDOM } from "jsdom" ; import { error } from "./index" ; import { Chapter , ScraperError , ScraperResponse } from "../types" ; import { Scraper , SearchOptions } from "./types" ; import { getProviderId , isProviderId } from "../routers/manga-page" ; import updateManga from "../util/updateManga" ; export class manganeloClass extends Scraper { constructor ( ) { super ( ) ; this . provider = "Manganelo" ; this . searchDisplay = "Manganato" ; this . canSearch = true ; this . nsfw = false ; } public async search ( query , options ? ) { const { resultCount } = { resultCount : 15 , ... options } ; let pageUrl ; if ( query === "" ) { pageUrl = "https://manganato.com/genre-all?type=topview" ; } else { pageUrl = `https://manganato.com/search/story/${ encodeURIComponent ( query . replace ( /[^a-zA-Z]/g , " " ) . trim ( ) . replace ( / /g , "_" ) ) }` ; } console . log ( pageUrl ) ; const pageReq = await fetch ( pageUrl ) ; const pageHtml = await pageReq . text ( ) ; const dom = new JSDOM ( pageHtml ) ; const document = dom . window . document ; const anchors = [ ... document . querySelectorAll ( ".genres-item-info .a-h:first-child" ) , ... document . querySelectorAll ( ".item-title" ) , ] ; const ids = anchors . map ( ( anchor ) => anchor . href . split ( "/" ) . pop ( ) ) . slice ( 0 , resultCount ) ; const searchResultData = await Promise . all ( ids . map ( ( id ) => updateManga ( "manganelo" , id ) ) ) ; return searchResultData ; } /**
     * The scrape function
     */ public async scrape ( slug , chapterId ) { const maxTimeout = new Promise ( ( resolve ) => { setTimeout ( ( ) => { resolve ( error ( 0 , "This request took too long" ) ) ; } , 25e3 ) ; } ) ; const scraping = this . doScrape ( slug , chapterId ) ; const raceResult = await Promise . race ( [ maxTimeout , scraping ] ) ; if ( raceResult . success === false && raceResult . err === "This request took too long" ) { console . error ( chalk . red ( "[MANGANELO]" ) + ` A request for '${ slug }' at '${ chapterId }' took too long and has timed out` ) ; } return raceResult ; } private async doScrape ( slug , chapterId ) { try { slug = slug . startsWith ( "manga-" ) ? slug : `manga-${ slug }` ; const pageReq = await fetch ( `https://readmanganato.com/${ slug }` ) ; const pageHtml = await pageReq . text ( ) ; const dom = new JSDOM ( pageHtml ) ; const document = dom . window . document ; const title = document . querySelector ( "h1" ) . textContent ; let posterUrl = ( document . querySelector ( ".info-image img" ) ?? { } ) . src || "" ; if ( posterUrl . startsWith ( "/" ) ) posterUrl = "https://manganato.com/" + posterUrl ; if ( ! posterUrl ) posterUrl = "https://jipfr.nl/jip.jpg" ; const genreWrapper = [ ... document . querySelectorAll ( ".variations-tableInfo tr" ) , ] . find ( ( tr ) => tr . textContent . includes ( "Genres" ) ) ; const genreLinks = [ ... genreWrapper . querySelectorAll ( ".a-h" ) ] ; const genres = genreLinks . map ( ( v ) => v . textContent ) ; const altTitleWrapper = document . querySelector ( ".info-alternative" ) . parentNode . parentNode ; const alternateTitles = altTitleWrapper . querySelector ( "h2" ) . textContent . split ( ";" ) . map ( ( v ) => v . trim ( ) ) ; const statusWrapper = document . querySelector ( ".info-status" ) . parentNode . parentNode ; const status = statusWrapper . querySelectorAll ( "td" ) [ 1 ] . textContent . toLowerCase ( ) ; const chapters = [ ... document . querySelectorAll ( ".row-content-chapter li" ) , ] . reverse ( ) . map ( ( row ) : Chapter => { const label = row . querySelector ( "a" ) . textContent . split ( ":" ) [ 0 ] ; const slug = row . querySelector ( "a" ) . href . split ( "/" ) . pop ( ) . replace ( /-/g , "_" ) ; const chapter = Number ( slug . split ( "_" ) . pop ( ) ) ; let date = new Date ( row . querySelector ( ".chapter-time" ) . textContent ) ; if ( ! date . getTime ( ) ) date = new Date ( ) ; return { label , hrefString : slug , season : 1 , chapter , date , combined : chapter } ; } ) ; let chapterImages = [ ] ; if ( chapterId != "-1" ) { const url = `https://readmanganato.com/${ slug }/${ chapterId . replace ( /_/g , "-" ) }` ; const chapterPageReq = await fetch ( url ) ; const chapterPageHtml = await chapterPageReq . text ( ) ; const dom = new JSDOM ( chapterPageHtml ) ; const chapterDocument = dom . window . document ; const images = [ ... chapterDocument . querySelectorAll ( ".container-chapter-reader img" ) , ] ; chapterImages = images . map ( ( v ) => v . getAttribute ( "src" ) ) ; } const descriptionParagraphs = document . querySelector ( "#panel-story-info-description" ) . textContent . split ( " :" ) . slice ( 1 ) . join ( " :" ) . split ( /\n|<br>/g ) ; const providerId = getProviderId ( this . provider ) ; return { constant : { title , slug : slug . replace ( /manga-/g , "" ) , posterUrl , alternateTitles , descriptionParagraphs , genres , nsfw : false } , data : { chapters , chapterImages , status } , success : true , provider : isProviderId ( providerId ) ? providerId : null } ; } catch ( err ) { console . error ( chalk . red ( "[MANGANELO]" ) + ` A request for '${ slug }' at '${ chapterId }' has errored` ) ; return error ( - 1 , err ) ; } } } const manganelo = new manganeloClass ( ) ; export default manganelo ;