import chalk from "chalk" ; import fetch from "node-fetch-extra" ; import Fuse from "fuse.js" ; import { error } from "./index" ; import { Chapter , ScraperError , ScraperResponse } from "../types" ; import { Scraper } from "./types" ; import { getProviderId , isProviderId } from "../routers/manga-page" ; import updateManga from "../util/updateManga" ; interface GuyaSeriesList { [ seriesName ] : { description : string ; slug : string ; cover : string ; last_updated : number ; } ; } interface GuyaSeries { title : string ; slug : string ; description : string ; cover : string ; preferred_sort : string [ ] ; chapters : { [ chapterNumber ] : { volume : string ; title : string ; folder : string ; preferred_sort ? : string [ ] ; groups : { [ groupId ] : string [ ] ; } ; release_date : { [ groupId ] : number ; } ; } ; } ; next_release_page : boolean ; } export class guyaClass extends Scraper { constructor ( ) { super ( ) ; this . provider = "Guya" ; this . canSearch = true ; this . nsfw = false ; } public async search ( query ) { let pageUrl = "https://guya.moe/api/get_all_series/" ; const pageReq = await fetch ( pageUrl ) ; const pageJson = await pageReq . json ( ) ; let ids = [ ] ; if ( query . length ) { const fuse = new Fuse ( Object . keys ( pageJson ) , { threshold : 0.3 , distance : 200 } ) ; ids = fuse . search ( query ) . map ( ( { item } ) => pageJson [ item ] . slug ) ; } else { ids = Object . values ( pageJson ) . map ( ( { slug } ) => slug ) ; } const searchResultData = await Promise . all ( ids . map ( ( id ) => updateManga ( "guya" , id ) ) ) ; return searchResultData ; } /**
     * The scrape function
     */ public async scrape ( slug , chapterId = null ) { 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 ( "[GUYA]" ) + ` A request for '${ slug }' at '${ chapterId }' took too long and has timed out` ) ; } return raceResult ; } private async doScrape ( slug , chapterId = null ) { try { const pageReq = await fetch ( `https://guya.moe/api/series/${ slug }/` ) ; const pageJson = await pageReq . json ( ) ; const title = pageJson . title ; const description = pageJson . description ?? '' ; const isOngoing = pageJson . next_release_page ; const posterUrl = `https://guya.moe${ pageJson . cover }` ; const genres = [ ] ; const alternateTitles = [ ] ; const { chapters : chapterData , preferred_sort : seriesPreferredSort } = pageJson ; let chapterImages = [ ] ; if ( chapterId && typeof chapterId === "string" ) { const { groups , folder , preferred_sort : chapterPreferredSort } = chapterData [ chapterId ] ; const preferredSort = chapterPreferredSort ?? seriesPreferredSort ; const bestGroup = Object . keys ( groups ) . sort ( ( a , b ) => preferredSort . indexOf ( a ) - preferredSort . indexOf ( b ) ) [ 0 ] ?? Object . keys ( groups ) [ 0 ] ; const pages = groups [ bestGroup ] ; chapterImages = pages . map ( ( page ) => `https://guya.moe/media/manga/${ slug }/chapters/${ folder }/${ bestGroup }/${ page }` ) ; } let chapters = Object . entries ( chapterData ) . map ( ( [ chapter , data ] ) => { const { volume , release_date : releaseDates } = data ; const releaseDate = Object . values ( releaseDates ) . sort ( ( a , b ) => a - b ) [ 0 ] ; const season = Number ( volume ) ; const chapterId = Number ( chapter ) ; return { chapter : chapterId , season , label : `Chapter ${ chapter }` , date : new Date ( releaseDate * 1000 ) , hrefString : chapter , combined : season * 1e5 + chapterId } ; } ) . sort ( ( a , b ) => a . combined - b . combined ) ; const providerId = getProviderId ( this . provider ) ; return { constant : { title , slug , posterUrl , alternateTitles , descriptionParagraphs : [ description ] , genres , nsfw : false } , data : { chapters , chapterImages , status : isOngoing ? "ongoing" : "ended" } , success : true , provider : isProviderId ( providerId ) ? providerId : null } ; } catch ( e ) { return { success : false , status : 0 , err : e } ; } } } const guya = new guyaClass ( ) ; export default guya ;