const {parse} = require('node-html-parser'); const {decodeHTML} = require('../lib') module.exports = class AsuraModule { /** * @property {Scanlator} scanlator - Scanlator name * @typedef {String} Scanlator * @pattern /^[\w-]+-scans$/ */ constructor() { this.scanlator = 'Asura-scans' this.BaseLink = 'https://asuratoon.com/' this.timeout = 5000; } /** * * @param {String} query * @returns {Array<Manga>} * @typedef {Object} Manga * @property {Link} link - Manga Link * @property {String} title - Manga Title * @property {Link} img - Image Link * @property {Number} latestChap - Latest Chapter Number * @typedef {String} Link */ async Search(query) { return await fetch(this.BaseLink+'?s='+query, {timeout:this.timeout}) .then(handleResponse) .then(handleData) .catch(handleError); function handleResponse(response) { return response.text(); } function handleError(error) { return error; } function handleData(data) { data = data.split('<div class="listupd">')[1].split('<div class="pagination">')[0] const document = parse(data); var payload = []; for(var result of document.querySelectorAll('.bs > .bsx > a')) { var aux = { link:result.rawAttrs.split('"')[1], title:result.rawAttrs.split('"')[3], img:'https://'+result.querySelectorAll('img')[0].rawAttrs.split('"')[1].split('https://')[2], status: result.querySelector('.status')?.rawText || 'Ongoing', latestChap:parseInt(result.querySelector('.epxs').innerText.split(' ')[1]), }; payload.push(aux); } return payload } } /** * * @param {String} query * @returns {Array<Manga>} * @typedef {Object} Manga * @property {Link} link - Manga Link * @property {String} title - Manga Title * @property {Link} img - Image Link * @property {Number} latestChap - Latest Chapter Number * @typedef {String} Link */ async SearchByTag(query, ammount=5) { return await fetch(this.BaseLink+'/genres/'+query, {timeout:this.timeout}) .then(handleResponse) .then(handleData) .catch(handleError); function handleResponse(response) { return response.text(); } function handleError(error) { return error; } function handleData(data) { data = data.split('<div class="listupd">')[1].split('<div class="pagination">')[0] const document = parse(data); var payload = []; var results = document.querySelectorAll('a') var limit = results.length<ammount?results.length:ammount; for(var i =0;i<limit; i++) { const result = results[i]; var aux = { link:result.rawAttrs.split('"')[1], title:decodeHTML(result.rawAttrs.split('"')[3]), img:result.querySelectorAll('.limit > img')[0].rawAttrs.split('src="')[1].split(')/')[1].split('"')[0], status:result.querySelector('.status')?.rawText||'Ongoing', latestChap:parseInt(result.querySelectorAll('.epxs')[0].innerText.split(' ')[1]), }; payload.push(aux); } return payload } } /** * * @param {String} name Manga/Manwha Name * @param {Link} link Manga url ( * @returns {Array<Chapter>} - Chapters Array * @typedef {Object} Chapter * @property {Number} num - Chapter Number * @property {String} link - Chapter Link * @property {String} date - Chapter Release Date * @typedef {String} Link * @pattern ^(https?:\/\/)?([\w\d.-]+)\.([a-z]{2,})(:[0-9]+)?(\/\S*)?$ */ async ChapterList(link, name) { return await fetch(link, {timeout:this.timeout}) .then(handleResponse) .then(handleData) .catch(handleError); function handleResponse(response) { return response.text(); } function handleError(error) { return error; } function handleData(data) { const document = parse(data); const chapterlist = document.querySelectorAll('ul')[1]; const chapters = chapterlist.querySelectorAll('li'); var payload = []; try { for(var chapter of chapters) { var aux = { num:parseInt(chapter.rawAttrs.split('"')[1]), link:chapter.querySelector('.eph-num').innerHTML.split('"')[1], date:chapter.querySelector('.chapterdate').innerText }; payload.push(aux); } } catch (error) { throw new Error('This manga should be called by url', error); } return payload } } /** * * @param {Link} Link Chapter Link * @returns {ChapterList} * @typedef {Obejct} ChapterList * @property {Array<Image>} List * @property {Link} mangaLink - Manga Link * @typedef {String} Image - Image link * @typedef {String} Link * @pattern ^(https?:\/\/)?([\w\d.-]+)\.([a-z]{2,})(:[0-9]+)?(\/\S*)?$ */ async Chapter(Link) { return await fetch(Link, {timeout:this.timeout}) .then(handleResponse) .then(handleData) .catch(handleError); function handleResponse(response) { return response.text(); } function handleError(error) { return error; } function handleData(data) { const document = parse(data); let List = []; let mangaLink = document.querySelectorAll('.allc')[0].querySelector('a')._rawAttrs.href; for(var image of document.getElementById('readerarea').querySelectorAll('img')) { if(image.rawAttrs) { let index = image.rawAttrs.split('"').findIndex(el => el.includes('http')); List.push(image.rawAttrs.split('"')[index].replace(/\n/g, '')); } } return {List, mangaLink} } } /** * * @param {String} Title * @returns {Manga} * @typedef {Object} Manga * @property {Link} Link - Manga Link * @property {Link} img - Image Link * @property {String} description - Latest Chapter Number * @property {String} Type - Manga Type * @property {String} Released - Year of Release * @property {String} Author - Author's name * @property {String} Artist - Artist Team * @property {String} Serialization - Serialization Company * @property {Number} latestChap - Latest Chap number * @property {Array<String>} tags - Manga Tags * @typedef {String} Link */ async GetManga(Link, title) { const auxTitle = title; return await fetch(Link, {timeout:this.timeout}) .then(handleResponse) .then(handleData) .catch(handleError); function handleResponse(response) { return response.text(); } function handleError(error) { return error; } function handleData(data) { const parsed = parse(data) let description = []; parsed.querySelectorAll('.entry-content-single')[0].querySelectorAll('p').forEach(p=>description.push(p.innerText)); description = decodeHTML(description.join(' ')); const img = 'https://'+parsed.querySelectorAll('img')[1].rawAttrs.split('src="')[1].split('https://')[2].split('"')[0]; let tags = parsed.querySelectorAll('.mgen')[0].structuredText.split('\n')[0].split(' '); let latestChap = parseInt(parsed.querySelectorAll('.epcurlast')[0].rawText.split(' ')[1]) let table = parsed.querySelectorAll('.infox')[0].querySelectorAll('.fmed'); table.splice(-3); const aux = {}; for (let i = 0; i < table.length; i++) { const key = decodeHTML(table[i].querySelector('b').innerText); aux[key] = decodeHTML(table[i].querySelector('span').innerText); } aux['Status'] = parsed.querySelectorAll('.imptdt')[0].innerText.split('\n')[1].split(' ')[1]; aux['Type'] = parsed.querySelectorAll('.imptdt')[1].innerText.split('\n')[1].split(' ')[1]; return {description, img, ...aux, tags, title:auxTitle, latestChap} } } async hasTitle(title) { const Search = await this.Search(title); if(!Array.isArray(Search)) return false return Search.filter(Manga => {return Manga.title === title})[0]; } }