UNPKG

@mashakujou/manhwaweb-scraper

Version:

Scraper ligero para obtener datos de capítulos de Manhwaweb desde su API pública

147 lines (126 loc) 3.91 kB
const axios = require('axios'); let debug = false; function setDebug(flag) { debug = !!flag; } function logDebug(...args) { if (debug) console.log('[DEBUG]', ...args); } function slug(url) { const s = url.split('/').pop(); logDebug('slug:', s); return s; } function urls(id) { const base = 'https://manhwawebbackend-production.up.railway.app/chapters'; const result = { see: `${base}/see/${id}`, seeprev: `${base}/seeprevpost/${id}` }; logDebug('urls:', result); return result; } async function full(url) { const id = slug(url); const { see, seeprev } = urls(id); logDebug('full: fetching see and seeprev'); try { const [seeRes, seeprevRes] = await Promise.all([ axios.get(see), axios.get(seeprev) ]); logDebug('full: responses received'); return { title: `${seeRes.data.name} ${seeRes.data.chapter?.chapter || ''}`, imgs: seeRes.data.chapter?.img || [], prev: seeprevRes.data.chapterAnterior || null, next: seeprevRes.data.chapterSiguiente || null, raw: { see: seeRes.data, seeprevpost: seeprevRes.data } }; } catch (err) { logDebug('full: error', err.message); throw new Error('Error: ' + err.message); } } async function images(url) { const id = slug(url); const { see } = urls(id); logDebug('images: fetching images'); try { const res = await axios.get(see); logDebug('images: response received, images count:', (res.data.chapter?.img || []).length); return res.data.chapter?.img || []; } catch (err) { logDebug('images: error', err.message); throw new Error('Error: ' + err.message); } } async function prevNext(url) { const id = slug(url); const { seeprev } = urls(id); logDebug('prevNext: fetching prev and next chapters'); try { const res = await axios.get(seeprev); logDebug('prevNext: response received'); return { prev: res.data.chapterAnterior || null, next: res.data.chapterSiguiente || null }; } catch (err) { logDebug('prevNext: error', err.message); throw new Error('Error: ' + err.message); } } async function seriesInfo(input) { const id = typeof input === 'string' && input.includes('manhwa/') ? input.split('/').pop() : input; const base = 'https://manhwawebbackend-production.up.railway.app/series/info'; logDebug('seriesInfo: fetching info for id', id); try { const res = await axios.get(`${base}/${id}`); logDebug('seriesInfo: response received'); return res.data; } catch (err) { logDebug('seriesInfo: error', err.message); throw new Error('Error: ' + err.message); } } async function search(q, p = 0, includeFirstChapter = false) { const url = `https://manhwawebbackend-production.up.railway.app/manhwa/library?buscar=${encodeURIComponent(q)}&estado=&tipo=&erotico=&demografia=&order_item=alfabetico&order_dir=desc&page=${p}&generes=`; logDebug('search: fetching search results for query', q); try { const { data } = await axios.get(url); if (!data?.data) { logDebug('search: no data found'); return { results: [], totalPages: 0 }; } const perPage = 20; const totalItems = data.total || data.data.length; const totalPages = Math.ceil(totalItems / perPage); const results = data.data.map(item => { const serieUrl = `https://manhwaweb.com/manhwa/${item._id}`; const chapterUrl = `https://manhwaweb.com/leer/${item._id}-1`; return { title: item.the_real_name, url: serieUrl, ...(includeFirstChapter && { firstChapterUrl: chapterUrl }) }; }); logDebug('search: results count', results.length); return { results, totalPages }; } catch (e) { logDebug('search: error', e.message); return { results: [], totalPages: 0 }; } } module.exports = { slug, urls, full, images, prevNext, seriesInfo, search, setDebug };