'use strict'; const { SlowHttp } = require('../lib/http'); const { fallbackDirection } = require('../../reading-direction'); const parser = require('../plugins/weebcentral'); const { parse } = require('../plugins/registry'); const { sourceDate } = require('../../chapter-dates'); function weebCentralInfo(value) { let url; try { url = new URL(String(value)); } catch { return null; } if (url.protocol !== 'https:' || url.hostname !== 'weebcentral.com') return null; const match = /^\/series\/([A-Z0-9]+)(?:\/([^/?#]+))?\/?$/i.exec(url.pathname); if (!match) return null; const title = decodeURIComponent(match[2] || match[1]).replace(/[-_]+/g, ' ').trim(); return { source: 'weebcentral', id: match[1].toUpperCase(), title, url: `https://weebcentral.com/series/${match[1]}${match[2] ? `/${match[2]}` : ''}` }; } const parseChapters = (html, baseUrl) => parser.catalog({ html, url: baseUrl }).chapters; const parsePageUrls = (html, baseUrl) => parser.pages({ html, url: baseUrl }).pages; async function discoverWeebCatalog(seriesUrl, http) { const seriesHtml = await (await http.get(seriesUrl, { accept: 'text/html' })).text(); const { title, listUrl } = parse('weebcentral', 'series', { html: seriesHtml, url: seriesUrl }); const listHtml = listUrl ? await (await http.get(listUrl, { accept: 'text/html', catalog: true })).text() : seriesHtml; const parsed = parse('weebcentral', 'catalog', { html: listHtml, url: seriesUrl }); const chapterLinks = parsed.chapterLinks; const chapters = parsed.chapters.sort((a, b) => Number(a.book?.number || 1) - Number(b.book?.number || 1) || Number(a.releaseKind === 'volume') - Number(b.releaseKind === 'volume') || Number(a.number) - Number(b.number)); return { title, chapters, chapterLinks, ...(chapterLinks && !chapters.length ? { availability: { reason: 'unrecognized-labels', message: `WeebCentral lists ${chapterLinks} chapter links, but their numbering labels are not recognized by the parser.` } } : {}), }; } async function discoverWeebChapter(chapter, http) { const pageHtml = await (await http.get(chapter.url, { accept: 'text/html' })).text(); const { manifestUrl } = parse('weebcentral', 'chapter', { html: pageHtml, url: chapter.url }); const source = sourceDate(chapter.uploadedAt, 'WeebCentral', chapter.uploadBatch); const fragment = await (await http.get(`${manifestUrl}&reading_style=long_strip¤t_page=1`, { accept: 'text/html' })).text(); const parsed = parse('weebcentral', 'pages', { html: fragment, url: manifestUrl }); const pages = parsed.pages.map(url => ({ url, headers: { referer: chapter.url } })); if (!pages.length) throw new Error(`No pages found for chapter ${chapter.number}`); return { number: chapter.number, title: chapter.title || '', ...(chapter.special ? { special: true, label: chapter.label, sourceId: chapter.id, sourceNumber: chapter.volume, releaseKind: chapter.releaseKind, volume: chapter.volume } : {}), ...(chapter.book ? { book: chapter.book } : {}), ...(source ? { dates: { source } } : {}), source: { name: 'WeebCentral', url: chapter.url }, pages, }; } async function discoverWeebCentral(seriesUrl, options = {}) { const http = new SlowHttp(options.http || {}); const catalog = await discoverWeebCatalog(seriesUrl, http); const chapters = catalog.chapters .sort((a, b) => Number(b.number) - Number(a.number)) .slice(0, options.limit || 3) .sort((a, b) => Number(a.number) - Number(b.number)); const output = []; for (const chapter of chapters) { output.push(await discoverWeebChapter(chapter, http)); } return { version: 1, series: { title: catalog.title, ...fallbackDirection(), sources: [{ name: 'WeebCentral', url: seriesUrl }], scraper: { ids: { weebcentral: seriesUrl.split('/series/')[1]?.split('/')[0] } } }, http: options.http || {}, chapters: output, }; } module.exports = { weebCentralInfo, discoverWeebCentral, discoverWeebCatalog, discoverWeebChapter, parseChapters, parsePageUrls };