You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
9.5 KiB

const {parse} = require('node-html-parser');
const {decodeHTML} = require('../lib')
module.exports = class ReaperModule
{
/**
* @property {Scanlator} scanlator - Scanlator name
* @typedef {String} Scanlator
* @pattern /^[\w-]+-scans$/
*/
constructor()
{
this.scanlator = 'Reaper-scans';
this.BaseLink = 'https://reaper-scans.com/';
this.timeout = 5000;
}
/**
*
* @param {String} query
* @returns {Array<Manga>}
* @typedef {Object} Manga
* @property {Link} link - Manga Link
* @property {String} title - Manga Title
* @property {String} Status - Manga Status
* @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);
let payload = [];
for(var result of document.querySelectorAll('a'))
{
let aux = {
link:result.rawAttrs.split('"')[1],
title:result.rawAttrs.split('"')[3],
img:result.querySelectorAll('.limit > img')[0].rawAttrs.split('"')[1],
status:result.querySelector('.status')?.rawText||'Ongoing',
latestChap:parseInt(result.childNodes[1].childNodes[1].childNodes[0].rawText.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('data-src="')[1].split('"')[0],
status:result.querySelector('.status')?.rawText||'Ongoing',
latestChap:parseInt(result.childNodes[1].childNodes[1].childNodes[0].rawText.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')[2];
const chapters = parse(chapterlist).querySelectorAll('li');
var payload = [];
try {
for(var chapter of chapters)
{
var aux = {
num:parseInt(chapter.rawAttrs.split('"')[1]),
link:chapter.childNodes[0].childNodes[0].childNodes[1].rawAttrs.split('"')[1],
date:chapter.childNodes[0].childNodes[0].childNodes[1].childNodes[3].rawText,
};
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);
var List = [];
let mangaLink = document.querySelectorAll('.allc')[0].querySelector('a')._rawAttrs.href;
for(var image of document.querySelectorAll('p')[1].childNodes)
{
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].innerText
description = decodeHTML(description);
if(description.split('/>').length>1) description = description.split('/>')[1]
const img = parsed.querySelectorAll('img')[1].rawAttrs.split('src="')[1].split('"')[0].includes('data:')? parsed.querySelectorAll('img')[1].rawAttrs.split('data-src="')[1].split('"')[0]:parsed.querySelectorAll('img')[1].rawAttrs.split('src="')[1].split('"')[0];
let table = parsed.querySelectorAll('.infotable')[0].childNodes[0].structuredText.split('\n');
let tags = parsed.querySelectorAll('.seriestugenre')[0].structuredText.split('\n')[0].split(' ');
let latestChap = parseInt(parsed.querySelectorAll('.epcurlast')[0].rawText.split(' ')[1])
table.splice(-6);
const aux = {};
for (let i = 0; i < table.length; i += 2) {
const key = table[i].trim();
aux[key] = table[i + 1].trim();
}
return {description, img, ...aux, tags, title:auxTitle, latestChap, link:Link}
}
}
/**
*
* @param {String} title Manga Title
* @returns {Boolean}
*/
async hasTitle(title)
{
const Search = await this.Search(title);
if(!Array.isArray(Search)) return false
return Search.filter(Manga => {return Manga.title === title})[0];
}
}