const axios = require('axios'); const cheerio = require("cheerio"); const decode = require("magnet-uri"); const Promises = require("../../lib/promises"); const { getRandomUserAgent } = require("../../lib/requestHelper"); const defaultTimeout = 10000; const baseUrl = 'https://www.erai-raws.info'; const Categories = { ANIMES: 'anime', EPISODES: 'episodes' }; function browse(config = {}, retries = 2) { if (retries === 0) { return Promise.reject(new Error(`Failed browse request`)); } const page = config.page || 1; const category = config.category; return singleRequest(`${baseUrl}/${category}/page/${page}/`, config) .then((body) => parseTableBody(body) .then(animes => Promises.sequence(animes.map(anime => () => singleRequest(anime.animeLink)))) .then(animeBodies => Promise.all(animeBodies.map(animeBody => parseTorrentPage(animeBody)))) .then(animeInfos => animeInfos.reduce((a, b) => a.concat(b), []))) .catch((err) => browse(config, retries - 1)); } function singleRequest(requestUrl, config = {}) { const timeout = config.timeout || defaultTimeout; const options = { headers: { 'User-Agent': getRandomUserAgent() }, timeout: timeout, }; return axios.get(requestUrl, options).then((response) => { const body = response.data; if (!body || (Buffer.isBuffer(body) && !body.size)) { throw new Error(`No body: ${requestUrl}`); } else if ( body.includes("502: Bad gateway") || body.includes("403 Forbidden") ) { throw new Error(`Invalid body contents: ${requestUrl}`); } return body; }); } function parseTableBody(body) { return new Promise((resolve, reject) => { const $ = cheerio.load(body); if (!$) { reject(new Error("Failed loading body")); } const links = $('[itemprop=\'headline\'] a, .content-area a.aa_ss_ops_new') .map((i, element) => ({ name: $(element).text(), animeLink: $(element).attr("href"), })).get(); resolve(links); }); } function parseTorrentPage(body) { return new Promise(async (resolve, reject) => { const $ = cheerio.load(body); if (!$) { reject(new Error("Failed loading body")); } const entries = $('.tab-content table, .content-area table') .map((i, entry) => { const languages = $(entry).find('.tooltip3').map((_, l) => $(l).attr('data-title')).get().join('/'); const magnets = $(entry).find('a[href^="magnet"]').map((_, m) => $(m).attr('href')).get(); return { languages, magnets } }).get(); const torrents = entries .map(entry => entry.magnets .map(magnet => decode(magnet)) .map(decodedMagnet => ({ title: decodedMagnet.name, infoHash: decodedMagnet.infoHash, trackers: decodedMagnet.tr, languages: entry.languages }))) .reduce((a, b) => a.concat(b), []); resolve(torrents); }); } module.exports = { browse, Categories };