diff --git a/src/sources/en/pawread.js b/src/sources/en/pawread.js new file mode 100644 index 000000000..6ce1bdc51 --- /dev/null +++ b/src/sources/en/pawread.js @@ -0,0 +1,144 @@ +import { fetchHtml } from '@utils/fetch/fetch'; +import * as cheerio from 'cheerio'; + +const sourceId = 147; +const sourceName = 'PawRead'; + +const baseUrl = 'https://pawread.com/'; + +const popularNovels = async page => { + const totalPages = 7; + const url = `${baseUrl}list/click/?page=${page}/`; + + const body = await fetchHtml({ url, sourceId }); + + const loadedCheerio = cheerio.load(body); + + let novels = []; + + loadedCheerio('div.col-lg-2').each(function () { + const novelName = loadedCheerio(this).find('a').text(); + const novelCover = loadedCheerio(this).find('img').attr('src'); + const novelUrl = + baseUrl + loadedCheerio(this).find('a').attr('href').slice(1); + + const novel = { sourceId, novelName, novelCover, novelUrl }; + + novels.push(novel); + }); + + return { totalPages, novels }; +}; + +const parseNovelAndChapters = async novelUrl => { + const body = await fetchHtml({ url: novelUrl, sourceId: sourceId }); + + let loadedCheerio = cheerio.load(body); + + let novel = { + sourceId, + sourceName, + url: novelUrl, + novelUrl, + }; + + novel.novelName = loadedCheerio('.col-md-9 > h1:nth-child(2)').text().trim(); + + novel.novelCover = loadedCheerio('.col-md-3 > div') + .attr('style') + .replace(/.*\((.*?)\)/g, '$1'); + + novel.author = loadedCheerio( + '#views_info > div:nth-child(4) > span:nth-child(2)', + ) + .text() + .replace(/(Author: )/g, ''); + + novel.status = loadedCheerio('.label').text().trim(); + + novel.genre = loadedCheerio('div.mt20:nth-child(4)') + .text() + .trim() + .replace(/\s/g, ','); + + novel.summary = loadedCheerio('#simple-des').text().trim(); + + let chapters = []; + + loadedCheerio('div.filtr-item').each(function () { + const chapterName = loadedCheerio(this).find('.c_title').text(); + const releaseDate = loadedCheerio(this) + .find('.c_title') + .next() + .next() + .text(); + const chapterUrl = + baseUrl + + loadedCheerio(this) + .find('.item-box') + .attr('onclick') + .replace(/.*?(novel.*html).*/g, '$1'); + + chapters.push({ chapterName, releaseDate, chapterUrl }); + }); + + novel.chapters = chapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const body = await fetchHtml({ + url: chapterUrl, + sourceId: sourceId, + }); + + let loadedCheerio = cheerio.load(body); + + const chapterName = loadedCheerio( + 'div.panel:nth-child(2) > div > div > h3', + ).text(); + const chapterText = loadedCheerio('#chapter_item').html(); + + const chapter = { + sourceId, + novelUrl, + chapterUrl, + chapterName, + chapterText, + }; + + return chapter; +}; + +const searchNovels = async searchTerm => { + const url = `${baseUrl}search/?keywords=${searchTerm}`; + + const body = await fetchHtml({ url, sourceId }); + + let loadedCheerio = cheerio.load(body); + + let novels = []; + + loadedCheerio('div.col-lg-2').each(function () { + const novelName = loadedCheerio(this).find('a').text(); + const novelCover = loadedCheerio(this).find('img').attr('src'); + const novelUrl = + baseUrl + loadedCheerio(this).find('a').attr('href').slice(1); + + const novel = { sourceId, novelName, novelCover, novelUrl }; + + novels.push(novel); + }); + + return novels; +}; + +const PawReadScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default PawReadScraper; diff --git a/src/sources/id/sakuranovel.js b/src/sources/id/sakuranovel.js index 200c0deda..79f1fc1f9 100644 --- a/src/sources/id/sakuranovel.js +++ b/src/sources/id/sakuranovel.js @@ -50,9 +50,16 @@ const parseNovelAndChapters = async novelUrl => { novel.novelCover = loadedCheerio('.series-thumb img').attr('src'); - novel.author = loadedCheerio( - '.series-infolist > li:nth-child(3) > span:nth-child(2)', - ).text(); + loadedCheerio('.series-infolist > li').each(function () { + const detailName = loadedCheerio(this).find('b').text().trim(); + const detail = loadedCheerio(this).find('b').next().text().trim(); + + switch (detailName) { + case 'Author': + novel.author = detail; + break; + } + }); novel.status = loadedCheerio('.status').text().trim(); diff --git a/src/sources/multisrc/wpmangastream/WPMangaStreamScraper.js b/src/sources/multisrc/wpmangastream/WPMangaStreamScraper.js index 13e9d99b0..a10845f77 100644 --- a/src/sources/multisrc/wpmangastream/WPMangaStreamScraper.js +++ b/src/sources/multisrc/wpmangastream/WPMangaStreamScraper.js @@ -90,7 +90,7 @@ class WPMangaStreamScraper { novel.genre = loadedCheerio('.genxed').text().trim().replace(/\s/g, ','); - novel.summary = loadedCheerio('.entry-content') + novel.summary = loadedCheerio('div[itemprop="description') .find('h3 , p.a') .remove() .end() diff --git a/src/sources/sourceManager.ts b/src/sources/sourceManager.ts index e2fb9db30..fccfa46dc 100644 --- a/src/sources/sourceManager.ts +++ b/src/sources/sourceManager.ts @@ -134,6 +134,7 @@ import { PandaMtlScraper, } from './multisrc/wqmangastream/WQMangaStreamGenerator'; import AgitoonScraper from './kr/Agitoon'; +import PawReadScraper from './en/pawread'; interface PopularNovelsResponse { totalPages: number; @@ -286,6 +287,7 @@ export const sourceManager = (sourceId: number): Scraper => { 144: NobleMtlScraper, // @ts-ignore 145: AgitoonScraper, // @ts-ignore 146: PandaMtlScraper, // @ts-ignore + 147: PawReadScraper, // @ts-ignore }; return scrapers[sourceId]; diff --git a/src/sources/sources.json b/src/sources/sources.json index 3ff3bd1ba..ffc473cfb 100644 --- a/src/sources/sources.json +++ b/src/sources/sources.json @@ -873,5 +873,12 @@ "icon": "https://pandamtl.com/wp-includes/images/w-logo-blue-white-bg.png", "url": "https://pandamtl.com/", "lang": "English" + }, + { + "sourceId": 147, + "sourceName": "PawRead", + "icon": "https://www.pawread.com/favicon.ico", + "url": "https://pawread.com/", + "lang": "English" } ]