diff --git a/src/Screens/Extension/Extension.js b/src/Screens/Extension/Extension.js index 65f71e4d..759fbcd4 100644 --- a/src/Screens/Extension/Extension.js +++ b/src/Screens/Extension/Extension.js @@ -66,7 +66,8 @@ const Extension = ({ navigation, route }) => { }; const clearSearchbar = () => { - getNovels(); + setNovels([]); + getNovels(1); setLoading(true); setSearchText(""); }; diff --git a/src/sources/en/fastnovel.js b/src/sources/en/fastnovel.js new file mode 100644 index 00000000..73a1428c --- /dev/null +++ b/src/sources/en/fastnovel.js @@ -0,0 +1,177 @@ +import cheerio from "react-native-cheerio"; +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://fastnovel.net"; +const searchUrl = `https://fastnovel.net/search/`; + +const popularNovels = async (page) => { + const url = `${baseUrl}/list/most-popular.html?page=${page}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".film-item").each(function (result) { + const novelName = $(this).find(".name").text(); + const novelCover = $(this).find(".img").attr("data-original"); + const novelUrl = $(this).find("a").attr("href").substring(1); + + const novel = { + sourceId: 3, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 3; + + novel.sourceName = "FastNovel"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("h1").text(); + + novel.novelCover = $(".book-cover").attr("data-original"); + + novel.summary = $("div.film-content > p").text(); + + novel.author = $("li > label") + .filter(function () { + return $(this).text().trim() === "Author:"; + }) + .next() + .text(); + + novel.genre = $("li") + .filter(function () { + return $(this).find("label").text().trim() === "Genre:"; + }) + .text() + .replace("Genre:", ""); + + novel.artist = null; + + novel.Status = null; + + let novelChapters = []; + + $(".chapter").each(function (result) { + const chapterName = $(this).text(); + const releaseDate = null; + let chapterUrl = $(this).attr("href"); + chapterUrl = chapterUrl.replace(`/${novelUrl}/`, ""); + + const novel = { + chapterName, + releaseDate, + chapterUrl, + }; + + novelChapters.push(novel); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $(".episode-name").text(); + let chapterText = $("#chapter-body").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + nextChapter = $("div.btn-group > a") + .filter(function () { + return $(this).text().trim() === "Next Chapter"; + }) + .attr("href") + .replace("/", ""); + + let prevChapter = null; + + prevChapter = $("div.btn-group > a") + .filter(function () { + return $(this).text().trim() === "Prev Chapter"; + }) + .attr("href") + .replace("/", ""); + + const chapter = { + sourceId: 3, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".film-item").each(function (result) { + const novelName = $(this).find("div.title > p.name").text(); + const novelCover = $(this).find(".img").attr("data-original"); + const novelUrl = $(this).find("a").attr("href").substring(1); + + const novel = { + sourceId: 3, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const fastNovelScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default fastNovelScraper; diff --git a/src/sources/en/foxaholic.js b/src/sources/en/foxaholic.js new file mode 100644 index 00000000..399d5b2b --- /dev/null +++ b/src/sources/en/foxaholic.js @@ -0,0 +1,212 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://foxaholic.com/"; + +const popularNovels = async (page) => { + let url = baseUrl + "novel/?m_orderby=rating"; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".page-item-detail").each(function (result) { + const novelName = $(this).find(".h5 > a").text(); + const novelCover = $(this).find("img").attr("data-src"); + + let novelUrl = $(this).find(".h5 > a").attr("href").split("/")[4]; + novelUrl += "/"; + + const novel = { + sourceId: 22, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}novel/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 22; + + novel.sourceName = "Foxaholic"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".post-title > h1") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.novelCover = $(".summary_image > a > img").attr("data-src"); + + $(".post-content_item").each(function (result) { + detailName = $(this) + .find(".summary-heading > h5") + .text() + .replace(/[\t\n]/g, "") + .trim(); + detail = $(this) + .find(".summary-content") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel[detailName] = detail; + }); + + novel.genre = novel.Genre.replace(/, /g, ","); + novel.author = novel.Author; + novel.Status = null; + novel.artist = null; + + delete novel.Genre; + delete novel.Author; + + $(".description-summary > div.summary__content").find("em").remove(); + + novel.summary = $(".description-summary > div.summary__content") + .text() + .replace(/[\t\n]/g, ""); + + let novelChapters = []; + + const novelId = $("#manga-chapters-holder").attr("data-id"); + + let formData = new FormData(); + formData.append("action", "manga_get_chapters"); + formData.append("manga", novelId); + + const data = await fetch("https://foxaholic.com/wp-admin/admin-ajax.php", { + method: "POST", + body: formData, + }); + const text = await data.text(); + + $ = cheerio.load(text); + + $(".wp-manga-chapter").each(function (result) { + chapterName = $(this) + .find("a") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + releaseDate = $(this).find("span").text().trim(); + + chapterUrl = $(this).find("a").attr("href").split("/"); + + chapterUrl[6] + ? (chapterUrl = chapterUrl[5] + "/" + chapterUrl[6]) + : (chapterUrl = chapterUrl[5]); + + novelChapters.push({ chapterName, releaseDate, chapterUrl }); + }); + + novel.chapters = novelChapters.reverse(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}novel/${novelUrl}/${chapterUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1#chapter-heading").text(); + let chapterText = $(".reading-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($(".nav-next").length) { + nextChapter = $(".nav-next").find("a").attr("href").split("/"); + nextChapter[6] + ? (nextChapter = nextChapter[5] + "/" + nextChapter[6]) + : (nextChapter = nextChapter[5]); + } + + let prevChapter = null; + + if ($(".nav-previous").length) { + prevChapter = $(".nav-previous").find("a").attr("href").split("/"); + prevChapter[6] + ? (prevChapter = prevChapter[5] + "/" + prevChapter[6]) + : (prevChapter = prevChapter[5]); + } + + novelUrl += "/"; + chapterUrl = optionalUrl + chapterUrl; + + const chapter = { + sourceId: 22, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".c-tabs-item__content").each(function (result) { + const novelName = $(this).find(".h4 > a").text(); + const novelCover = $(this).find("img").attr("data-src"); + + let novelUrl = $(this).find(".h4 > a").attr("href").split("/")[4]; + novelUrl += "/"; + const novel = { + sourceId: 22, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const FoxaHolicScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default FoxaHolicScraper; diff --git a/src/sources/en/freewebnovel.js b/src/sources/en/freewebnovel.js new file mode 100644 index 00000000..010efdb7 --- /dev/null +++ b/src/sources/en/freewebnovel.js @@ -0,0 +1,213 @@ +import cheerio from "react-native-cheerio"; +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://freewebnovel.com/"; + +const popularNovels = async (page) => { + let url = baseUrl + "most-popular-novel/"; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".li-row").each(function (result) { + const novelName = $(this).find(".tit").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this) + .find("h3 > a") + .attr("href") + .replace(".html", "") + .slice(1); + + novelUrl += "/"; + + const novel = { + sourceId: 13, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}${novelUrl}.html`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 13; + + novel.sourceName = "FreeWebNovel"; + + novel.url = url; + + novel.novelUrl = `${novelUrl.replace(".html", "")}/`; + + novel.novelName = $("h1.tit").text(); + + novel.novelCover = $(".pic > img").attr("src"); + + novel.genre = $("[title=Genre]") + .next() + .text() + .replace(/[\t\n]/g, ""); + + novel.author = $("[title=Author]") + .next() + .text() + .replace(/[\t\n]/g, ""); + + novel.artist = null; + + novel.Status = $("[title=Status]") + .next() + .text() + .replace(/[\t\n]/g, ""); + + novel.Alternative = $("[title='Alternative names']") + .next() + .text() + .replace(/[\t\n]/g, ""); + + let novelSummary = $(".inner").html(); + novel.summary = htmlToText(novelSummary); + + let novelChapters = []; + + let latestChapter; + + $("h3.tit").each(function (res) { + if ($(this).find("a").text() === novel.novelName) { + // console.log($(this).find("a").text()); + // console.log(novel.novelName); + latestChapter = $(this).next().find("span.s3").text().match(/\d+/); + } + }); + + latestChapter = latestChapter[0]; + + for (let i = 1; i <= parseInt(latestChapter); i++) { + const chapterName = "Chapter " + i; + + const releaseDate = null; + + const chapterUrl = "chapter-" + i; + + const chapter = { chapterName, releaseDate, chapterUrl }; + + novelChapters.push(chapter); + } + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${novelUrl}/${chapterUrl}.html`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let chapterName = $("h1.tit").text(); + + let chapterText = $("div.txt").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($("[title='Read Next chapter']").length) { + nextChapter = $("[title='Read Next chapter']") + .attr("href") + .replace("/" + novelUrl + "/", "") + .replace(".html", ""); + } + + let prevChapter = null; + + if ($("[title='Read Privious Chapter']").length) { + prevChapter = $("[title='Read Privious Chapter']") + .attr("href") + .replace("/" + novelUrl + "/", "") + .replace(".html", ""); + } + + chapterUrl = chapterUrl; + + const chapter = { + sourceId: 13, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = baseUrl + "search/"; + + const formData = new FormData(); + formData.append("searchkey", searchTerm); + + const result = await fetch(url, { + method: "POST", + body: formData, + }); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".li-row > .li > .con").each(function (result) { + const novelName = $(this).find(".tit").text(); + const novelCover = $(this).find(".pic > a > img").attr("data-cfsrc"); + + let novelUrl = $(this) + .find("h3 > a") + .attr("href") + .replace(".html", "") + .slice(1); + + novelUrl += "/"; + + const novel = { + sourceId: 13, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const FreeWebNovelScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default FreeWebNovelScraper; diff --git a/src/sources/en/jpmtl.js b/src/sources/en/jpmtl.js new file mode 100644 index 00000000..41ebbc53 --- /dev/null +++ b/src/sources/en/jpmtl.js @@ -0,0 +1,179 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://jpmtl.com/"; + +const popularNovels = async (page) => { + let url = + "https://jpmtl.com/v2/book/show/browse?query=&categories=&content_type=0&direction=0&page=2&limit=20&type=5&status=all&language=3&exclude_categories="; + + const result = await fetch(url); + const body = await result.json(); + + let novels = []; + + body.map((item) => { + const novelName = item.title; + const novelCover = item.cover; + const novelUrl = item.id + "/"; + + const novel = { sourceId: 14, novelName, novelCover, novelUrl }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}books/${novelUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 14; + + novel.sourceName = "JPMTL"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("h1.book-sidebar__title").text(); + + novel.novelCover = $(".book-sidebar").find("img").attr("src"); + + $(".post-content_item").each(function (result) { + detailName = $(this) + .find(".summary-heading > h5") + .text() + .replace(/[\t\n]/g, "") + .trim(); + detail = $(this) + .find(".summary-content") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel[detailName] = detail; + }); + + novel.summary = $(".main-book__synopsis").text(); + + novel.genre = ""; + + $("a.main-book__category").each(function (result) { + novel.genre += $(this).text(); + }); + + novel.author = $(".book-sidebar__author > .book-sidebar__info") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + let novelChapters = []; + + const chapterListUrl = `https://jpmtl.com/v2/chapter/${novelUrl}/list?state=published&structured=true&d`; + + const chapterResult = await fetch(chapterListUrl); + const volumes = await chapterResult.json(); + + volumes.map((volume) => { + volume.chapters.map((chapter) => { + const chapterName = chapter.title; + const releaseDate = chapter.created_at; + const chapterUrl = chapter.id; + + const obj = { + sourceId: 14, + chapterName, + releaseDate, + chapterUrl, + }; + + novelChapters.push(obj); + }); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}books/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + console.log(url); + + $ = cheerio.load(body); + + const chapterName = $(".chapter-content__title").text(); + let chapterText = $(".chapter-content__content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + let prevChapter = null; + + $(".chapter-wrapper__nav").each(function (result) { + const chId = $(this) + .attr("href") + .replace("/books/" + novelUrl + "/", ""); + if (chId < chapterUrl) { + prevChapter = chId; + } else { + nextChapter = chId; + } + }); + + novelUrl += "/"; + + const chapter = { + sourceId: 14, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `https://jpmtl.com/v2/book/show/browse?query=${searchTerm}&categories=&content_type=2&direction=0&page=1&limit=20&type=5&status=all&language=3&exclude_categories=`; + + const result = await fetch(url); + const body = await result.json(); + + const novels = []; + + body.map((item) => { + const novelName = item.title; + const novelCover = item.cover; + const novelUrl = item.id + "/"; + + const novel = { sourceId: 14, novelName, novelCover, novelUrl }; + + novels.push(novel); + }); + + return novels; +}; + +const JPMTLScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default JPMTLScraper; diff --git a/src/sources/en/kisslightnovels.js b/src/sources/en/kisslightnovels.js new file mode 100644 index 00000000..2ffd5dca --- /dev/null +++ b/src/sources/en/kisslightnovels.js @@ -0,0 +1,188 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://kisslightnovels.info/"; + +const popularNovels = async (page) => { + const result = await fetch(baseUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".page-item-detail").each(function (result) { + const novelName = $(this).find("h5 > a").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("h5 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}novel/`, ""); + + const novel = { + sourceId: 11, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}novel/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 11; + + novel.sourceName = "KissLightNovels"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".post-title > h1") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.novelCover = $(".summary_image > a > img").attr("src"); + + $(".post-content_item").each(function (result) { + detailName = $(this) + .find(".summary-heading > h5") + .text() + .replace(/[\t\n]/g, "") + .trim(); + detail = $(this) + .find(".summary-content") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel[detailName] = detail; + }); + + $(".description-summary > div.summary__content").find("em").remove(); + + novel.summary = $(".description-summary > div.summary__content") + .text() + .replace(/[\t\n]/g, ""); + + let novelChapters = []; + + $(".wp-manga-chapter").each(function (result) { + chapterName = $(this) + .find("a") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + releaseDate = $(this) + .find("span") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + chapterUrl = $(this).find("a").attr("href").replace(url, ""); + + novelChapters.push({ chapterName, releaseDate, chapterUrl }); + }); + + novel.chapters = novelChapters.reverse(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}novel/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + $("#snippet-box").remove(); + + const chapterName = $("div.text-left > h4").text(); + let chapterText = $(".reading-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($(".nav-next").length) { + nextChapter = $(".nav-next") + .find("a") + .attr("href") + .replace(baseUrl + "novel/" + novelUrl + "/", ""); + } + + let prevChapter = null; + + if ($(".nav-previous").length) { + prevChapter = $(".nav-previous") + .find("a") + .attr("href") + .replace(baseUrl + "novel/" + novelUrl + "/", ""); + } + + const chapter = { + sourceId: 11, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga&m_orderby=rating`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".c-tabs-item__content").each(function (result) { + const novelName = $(this).find("h4 > a").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("h4 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}novel/`, ""); + + const novel = { + sourceId: 11, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const kissLightNovelScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default kissLightNovelScraper; diff --git a/src/sources/en/lightnovelpub.js b/src/sources/en/lightnovelpub.js new file mode 100644 index 00000000..1c1d7753 --- /dev/null +++ b/src/sources/en/lightnovelpub.js @@ -0,0 +1,198 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://www.lightnovelpub.com/"; + +const popularNovels = async (page) => { + let url = baseUrl + "browse/all/popular/all/1"; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".novel-item.ads").remove(); + + $(".novel-item").each(function (result) { + const novelName = $(this) + .find(".novel-title") + .text() + .replace(/[\t\n]/g, ""); + + const novelCover = $(this).find("img").attr("data-src"); + + let novelUrl = $(this) + .find(".novel-title > a") + .attr("href") + .replace(`/novel/`, ""); + novelUrl += "/"; + + const novel = { + sourceId: 15, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}novel/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 15; + + novel.sourceName = "LightNovelPub"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("h1.novel-title") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.novelCover = $("figure.cover > img").attr("src"); + + novel.genre = ""; + + $("div.categories > ul > li").each(function (result) { + novel.genre += + $(this) + .text() + .replace(/[\t\n]/g, "") + ","; + }); + + $("div.header-stats > span").each(function (result) { + if ($(this).find("small").text() === "Status") { + novel.Status = $(this).find("strong").text(); + } + }); + + novel.genre = novel.genre.slice(0, -1); + + novel.author = $(".author > a > span").text(); + + novelSummary = $(".summary > .content").html(); + novel.summary = htmlToText(novelSummary); + + let novelChapters = []; + + let firstChapterNo, totalChapters; + + totalChapters = $(".header-stats > span").first().text().match(/\d+/)[0]; + firstChapterNo = $(".chapter-no").first().text().match(/\d+/)[0]; + + for (let i = firstChapterNo; i <= totalChapters; i++) { + const chapterName = "Chapter " + i; + + const releaseDate = null; + + const chapterUrl = "chapter-" + i; + + const chapter = { chapterName, releaseDate, chapterUrl }; + + novelChapters.push(chapter); + } + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}novel/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h2").text(); + let chapterText = $("#chapter-container").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if (!$("a.nextchap.isDisabled").length) { + nextChapter = $("a.nextchap") + .attr("href") + .replace("/novel/" + novelUrl + "/", ""); + } + + let prevChapter = null; + + if (!$("a.prevchap.isDisabled").length) { + prevChapter = $("a.prevchap") + .attr("href") + .replace("/novel/" + novelUrl + "/", ""); + } + + const chapter = { + sourceId: 15, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}lnwsearchlive?inputContent=${searchTerm}`; + + const result = await scraper(url); + + $ = cheerio.load(result); + + let novels = []; + + let results = JSON.parse($("body").text()); + + $ = cheerio.load(results.resultview); + + $(".novel-item").each(function (result) { + const novelName = $(this).find("h4.novel-title").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").replace(`/novel/`, ""); + novelUrl += "/"; + + const novel = { + sourceId: 15, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const lightNovelPubScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default lightNovelPubScraper; diff --git a/src/sources/en/mtlnovel.js b/src/sources/en/mtlnovel.js new file mode 100644 index 00000000..72c16280 --- /dev/null +++ b/src/sources/en/mtlnovel.js @@ -0,0 +1,196 @@ +import cheerio from "react-native-cheerio"; +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://www.mtlnovel.com"; + +const popularNovels = async (page) => { + const url = `${baseUrl}/alltime-rank/page/${page}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.box.wide").each(function (result) { + const novelName = $(this).find("a.list-title").text().slice(4); + const novelCover = $(this).find("amp-img").attr("src"); + + let novelUrl = $(this).find("a.list-title").attr("href"); + novelUrl = novelUrl.replace("https://www.mtlnovel.com/", ""); + + const novel = { + sourceId: 5, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}/${novelUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 5; + + novel.sourceName = "MTLNovel"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("h1.entry-title").text(); + + novel.novelCover = $(".nov-head > amp-img").attr("src"); + + novel.summary = $("div.desc > h2").next().text(); + + novel.author = $("tr > td") + .filter(function () { + return $(this).prev().text().trim() === "Author"; + }) + .next() + .text() + .replace("Auhtor:", ""); + + novel.Status = $("tr > td") + .filter(function () { + return $(this).prev().text().trim() === "Status"; + }) + .next() + .text() + .replace("Status:", ""); + + novel.genre = $("td") + .filter(function () { + return $(this).prev().text().trim() === "Genre"; + }) + .next() + .text() + .replace("Genre:", ""); + + novel.artist = null; + + const chapterListUrl = url + "/chapter-list/"; + + const getChapters = async () => { + const result = await fetch(chapterListUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novelChapters = []; + + $("div.ch-list") + .find("a.ch-link") + .each(function (result) { + const chapterName = $(this).text().replace("~ ", ""); + const releaseDate = null; + + let chapterUrl = $(this).attr("href"); + chapterUrl = chapterUrl.replace( + `https://www.mtlnovel.com/${novelUrl}/`, + "" + ); + + novelChapters.push({ + chapterUrl, + chapterName, + releaseDate, + }); + }); + return novelChapters.reverse(); + }; + + novel.chapters = await getChapters(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = chapterUrl; + console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1.main-title").text(); + let chapterText = $("div.par").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + if ($("a.next").attr("href")) { + nextChapter = $("a.next").attr("href").replace(`/${novelUrl}/`, ""); + } + + let prevChapter = null; + if ($("a.prev").attr("href")) { + prevChapter = $("a.prev").attr("href").replace(`/${novelUrl}/`, ""); + } + + chapter = { + sourceId: 5, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const searchUrl = + "https://www.mtlnovel.com/wp-admin/admin-ajax.php?action=autosuggest&q=" + + searchTerm + + "&__amp_source_origin=https%3A%2F%2Fwww.mtlnovel.com"; + + const res = await fetch(searchUrl); + const result = await res.text(); + + $ = cheerio.load(result); + + let body = JSON.parse($("body").text()); + + let novels = []; + + body.items[0].results.map((item) => { + const novelName = item.title.replace(/<\/?strong>/g, ""); + const novelCover = item.thumbnail; + const novelUrl = item.permalink.replace( + "https://www.mtlnovel.com/", + "" + ); + + const novel = { sourceId: 5, novelName, novelCover, novelUrl }; + + novels.push(novel); + }); + + return novels; +}; + +const mtlNovelScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default mtlNovelScraper; diff --git a/src/sources/en/novelfull.js b/src/sources/en/novelfull.js new file mode 100644 index 00000000..d1bd5623 --- /dev/null +++ b/src/sources/en/novelfull.js @@ -0,0 +1,206 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://novelfull.com"; + +const popularNovels = async (page) => { + const url = `${baseUrl}/most-popular?page=${page}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.col-truyen-main > div.list-truyen > .row").each(function (result) { + const novelName = $(this).find("h3.truyen-title > a").text(); + + let novelCover = $(this).find("img").attr("src"); + novelCover = baseUrl + novelCover; + + let novelUrl = $(this) + .find("h3.truyen-title > a") + .attr("href") + .replace(".html", "") + .substring(1); + novelUrl = `${novelUrl}/`; + + const novel = { + sourceId: 8, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}/${novelUrl.slice(0, -1)}.html`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 8; + + novel.sourceName = "NovelFull"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("div.book > img").attr("alt"); + + novel.novelCover = baseUrl + $("div.book > img").attr("src"); + + novel.summary = $("div.desc-text").text(); + + novel.author = $("div.info > div > h3") + .filter(function () { + return $(this).text().trim() === "Author:"; + }) + .siblings() + .text(); + + novel.genre = $("div.info > div") + .filter(function () { + return $(this).find("h3").text().trim() === "Genre:"; + }) + .text() + .replace("Genre:", ""); + + novel.artist = null; + + novel.Status = $("div.info > div > h3") + .filter(function () { + return $(this).text().trim() === "Status:"; + }) + .next() + .text(); + + const novelId = $("#rating").attr("data-novel-id"); + + const getChapters = async (novelId) => { + const chapterListUrl = + baseUrl + "/ajax/chapter-option?novelId=" + novelId; + + const data = await fetch(chapterListUrl); + const chapters = await data.text(); + + $ = cheerio.load(chapters); + + let novelChapters = []; + + $("select > option").each(function (result) { + let chapterName = $(this).text(); + let releaseDate = null; + let chapterUrl = $(this).attr("value"); + chapterUrl = chapterUrl.replace(`/${novelUrl}/`, ""); + + novelChapters.push({ + chapterName, + releaseDate, + chapterUrl, + }); + }); + return novelChapters; + }; + + novel.chapters = await getChapters(novelId); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $(".chapter-title").attr("title"); + let chapterText = $("#chapter-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + if ($("a#next_chap").attr("href")) { + nextChapter = $("a#next_chap") + .attr("href") + .replace(`/${novelUrl}/`, ""); + } + + let prevChapter = null; + if ($("a#prev_chap").attr("href")) { + prevChapter = $("a#prev_chap") + .attr("href") + .replace(`/${novelUrl}/`, ""); + } + + const chapter = { + sourceId: 8, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const searchUrl = `https://novelfull.com/search?keyword=`; + + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.col-truyen-main > div.list-truyen > .row").each(function (result) { + let novelUrl = $(this) + .find("h3.truyen-title > a") + .attr("href") + .replace(".html", "") + .substring(1); + novelUrl = `${novelUrl}/`; + + const novelName = $(this).find("h3.truyen-title > a").text(); + let novelCover = $(this).find("img").attr("src"); + novelCover = baseUrl + novelCover; + + const novel = { + sourceId: 8, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const novelFullScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default novelFullScraper; diff --git a/src/sources/en/novelhall.js b/src/sources/en/novelhall.js new file mode 100644 index 00000000..fae7eae0 --- /dev/null +++ b/src/sources/en/novelhall.js @@ -0,0 +1,178 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://www.novelhall.com/"; + +const popularNovels = async (page) => { + const result = await fetch(baseUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.section1") + .find("li") + .each(function (result) { + const novelName = $(this).find(".book-info > h2 > a").text(); + const novelCover = $(this).find("img").attr("src"); + const novelUrl = $(this).find("a").attr("href").substring(1); + + const novel = { + sourceId: 6, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 6; + + novel.sourceName = "NovelHall"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("h1").text(); + + novel.novelCover = $("div.book-img > img").attr("src"); + + novel.summary = $("div.intro") + .text() + .replace(/[\t\n]/g, ""); + + novel.author = $("span.blue").first().text().replace("Author:", ""); + + novel.genre = $("a.red").text(); + + novel.artist = null; + + novel.Status = $("span.blue").first().next().text().replace("Status:", ""); + + let novelChapters = []; + + $("div.book-catalog.hidden-xs#morelist") + .find("li.post-11") + .each(function (result) { + let chapterName = $(this).find("a").text(); + + let releaseDate = null; + + let chapterUrl = $(this).find("a").attr("href"); + + if (chapterUrl) { + chapterUrl = chapterUrl.replace(`/${novelUrl}/`, ""); + } + + const chapter = { + chapterName, + releaseDate, + chapterUrl, + }; + + novelChapters.push(chapter); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1").text(); + let chapterText = $("div.entry-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + nextChapter = $('a[rel="next"]').attr("href"); + if (nextChapter) { + nextChapter = nextChapter.replace(`/${novelUrl}/`, ""); + } + + let prevChapter = null; + prevChapter = $('a[rel="prev"]').attr("href"); + if (prevChapter) { + prevChapter = prevChapter.replace(`/${novelUrl}/`, ""); + } + + chapter = { + sourceId: 6, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const searchUrl = `${baseUrl}index.php?s=so&module=book&keyword=`; + + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("tr").each(function (result) { + let novelName = $(this).find("td:nth-child(2)").text(); + novelName = novelName.replace(/[\t\n]/g, ""); + + const novelCover = "https://cdn.novelupdates.com/imgmid/noimagemid.jpg"; + + let novelUrl = $(this).find("td:nth-child(2) >").attr("href"); + if (novelUrl) { + novelUrl = novelUrl.slice(1); + } + + novel = { + sourceId: 6, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const novelhallScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default novelhallScraper; diff --git a/src/sources/en/noveltrench.js b/src/sources/en/noveltrench.js new file mode 100644 index 00000000..a23612e9 --- /dev/null +++ b/src/sources/en/noveltrench.js @@ -0,0 +1,200 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://noveltrench.com/"; + +const popularNovels = async (page) => { + let url = baseUrl + "manga/page/" + page; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".page-item-detail").each(function (result) { + const novelName = $(this).find(".h5 > a").text(); + const novelCover = $(this).find("img").attr("data-src"); + + let novelUrl = $(this).find(".h5 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}manga/`, ""); + + const novel = { + sourceId: 9, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}manga/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 9; + + novel.sourceName = "NovelTrench"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".post-title > h1") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.novelCover = $(".summary_image > a > img").attr("data-src"); + + $(".post-content_item").each(function (result) { + detailName = $(this) + .find(".summary-heading > h5") + .text() + .replace(/[\t\n]/g, "") + .trim(); + detail = $(this) + .find(".summary-content") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + switch (detailName) { + case "Genre(s)": + novel.genre = detail.trim().replace(/[\t\n]/g, ","); + break; + case "Author(s)": + novel.author = detail.trim(); + break; + case "Artist(s)": + novel.status = detail.trim(); + break; + } + }); + + $(".description-summary > div.summary__content").find("em").remove(); + + novel.summary = $(".description-summary > div.summary__content") + .text() + .replace(/[\t\n]/g, ""); + + let novelChapters = []; + + $(".wp-manga-chapter").each(function (result) { + chapterName = $(this) + .find("a") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + releaseDate = $(this) + .find("span") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + chapterUrl = $(this).find("a").attr("href").replace(url, ""); + + novelChapters.push({ chapterName, releaseDate, chapterUrl }); + }); + + novel.chapters = novelChapters.reverse(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = chapterUrl; + + console.log(url); + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1#chapter-heading").text(); + let chapterText = $(".reading-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($(".nav-next").length) { + nextChapter = $(".nav-next") + .find("a") + .attr("href") + .replace(baseUrl + "manga/" + novelUrl + "/", ""); + } + + let prevChapter = null; + + if ($(".nav-previous").length) { + prevChapter = $(".nav-previous") + .find("a") + .attr("href") + .replace(baseUrl + "manga/" + novelUrl + "/", ""); + } + + const chapter = { + sourceId: 9, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".c-tabs-item__content").each(function (result) { + const novelName = $(this).find(".h4 > a").text(); + const novelCover = $(this).find("img").attr("data-src"); + + let novelUrl = $(this).find(".h4 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}manga/`, ""); + + const novel = { + sourceId: 9, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const novelTrenchScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default novelTrenchScraper; diff --git a/src/sources/en/novelupdatescc.js b/src/sources/en/novelupdatescc.js new file mode 100644 index 00000000..3b46aadc --- /dev/null +++ b/src/sources/en/novelupdatescc.js @@ -0,0 +1,159 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://www.novelupdates.cc/"; + +const popularNovels = async (page) => { + const result = await fetch(baseUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".section-item").each(function (result) { + const novelName = $(this).find(".book-name").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").slice(1); + + const novel = { + sourceId: 18, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 18; + + novel.sourceName = "NovelUpdates.cc"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".book-name").text(); + + novel.novelCover = $("div.book-img > img").attr("src"); + + novel.genre = $("div.book-catalog > span.txt").text(); + + novel.Status = $("div.book-state > span.txt").text(); + + novel.author = $("div.author > span.name").text(); + + novelSummary = $("div.content > p.desc").html(); + novel.summary = htmlToText(novelSummary); + + let novelChapters = []; + + $(".chapter-item").each(function (result) { + const chapterName = $(this).find(".chapter-name").text(); + const releaseDate = null; + const chapterUrl = $(this).attr("href").slice(1); + + novelChapters.push({ + chapterName, + releaseDate, + chapterUrl, + }); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1.chapter-title").text(); + let chapterText = $("div.chapter-entity").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($("a.next").length) { + nextChapter = $("a.next").attr("href").slice(1); + } + + let prevChapter = null; + + if ($("a.prev").length) { + prevChapter = $("a.prev").attr("href").slice(1); + } + + const chapter = { + sourceId: 18, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}search/${searchTerm}/1`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".list-item").each(function (result) { + $(this).find("font").remove(); + + const novelName = $(this).find(".book-name").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").slice(1); + + const novel = { + sourceId: 18, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const novelUpdatesCcScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default novelUpdatesCcScraper; diff --git a/src/sources/en/readlightnovelcc.js b/src/sources/en/readlightnovelcc.js new file mode 100644 index 00000000..95c4dc54 --- /dev/null +++ b/src/sources/en/readlightnovelcc.js @@ -0,0 +1,159 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://m.readlightnovel.cc/"; + +const popularNovels = async (page) => { + const result = await fetch(baseUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".section-item").each(function (result) { + const novelName = $(this).find(".book-name").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").slice(1); + + const novel = { + sourceId: 19, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 19; + + novel.sourceName = "ReadLightNovel.cc"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".book-name").text(); + + novel.novelCover = $("div.book-img > img").attr("src"); + + novel.genre = $("div.book-catalog > span.txt").text(); + + novel.Status = $("div.book-state > span.txt").text(); + + novel.author = $("div.author > span.name").text(); + + novelSummary = $("div.content > p.desc").html(); + novel.summary = htmlToText(novelSummary); + + let novelChapters = []; + + $(".chapter-item").each(function (result) { + const chapterName = $(this).find(".chapter-name").text(); + const releaseDate = null; + const chapterUrl = $(this).attr("href").slice(1); + + novelChapters.push({ + chapterName, + releaseDate, + chapterUrl, + }); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1.chapter-title").text(); + let chapterText = $("div.chapter-entity").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($("a.next").length) { + nextChapter = $("a.next").attr("href").slice(1); + } + + let prevChapter = null; + + if ($("a.prev").length) { + prevChapter = $("a.prev").attr("href").slice(1); + } + + const chapter = { + sourceId: 19, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}search/${searchTerm}/1`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".list-item").each(function (result) { + $(this).find("font").remove(); + + const novelName = $(this).find(".book-name").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").slice(1); + + const novel = { + sourceId: 19, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const readLightNovelCcScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default readLightNovelCcScraper; diff --git a/src/sources/en/readnovelfull.js b/src/sources/en/readnovelfull.js new file mode 100644 index 00000000..a4cde009 --- /dev/null +++ b/src/sources/en/readnovelfull.js @@ -0,0 +1,205 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://readnovelfull.com"; + +const popularNovels = async (page) => { + const url = `${baseUrl}/most-popular-novel?page=${page}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.col-novel-main > div.list-novel > .row").each(function (result) { + let novelUrl = $(this) + .find("h3.novel-title > a") + .attr("href") + .replace(".html", "") + .substring(1); + novelUrl = `${novelUrl}/`; + + const novelName = $(this).find("h3.novel-title > a").text(); + const novelCover = $(this).find("img").attr("src"); + + const novel = { + sourceId: 4, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}/${novelUrl.slice(0, -1)}.html`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 4; + + novel.sourceName = "ReadNovelFull"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("div.book > img").attr("alt"); + + novel.novelCover = $("div.book > img").attr("src"); + + novel.summary = $("div.desc-text").text(); + + novel.author = $("li > h3") + .filter(function () { + return $(this).text().trim() === "Author:"; + }) + .siblings() + .text(); + + novel.genre = $("li") + .filter(function () { + return $(this).find("h3").text().trim() === "Genre:"; + }) + .text() + .replace("Genre:", ""); + + novel.artist = null; + + novel.Status = $("li > h3") + .filter(function () { + return $(this).text().trim() === "Status:"; + }) + .siblings() + .text(); + + const novelId = $("#rating").attr("data-novel-id"); + + const getChapters = async (novelId) => { + const chapterListUrl = + "https://readnovelfull.com/ajax/chapter-archive?novelId=" + novelId; + + const data = await fetch(chapterListUrl); + const chapters = await data.text(); + + $ = cheerio.load(chapters); + + let novelChapters = []; + + $(".panel-body") + .find("li") + .each(function (result) { + let chapterName = $(this).find("a").attr("title"); + let releaseDate = null; + let chapterUrl = $(this).find("a").attr("href"); + chapterUrl = chapterUrl.replace(`/${novelUrl}/`, ""); + + novelChapters.push({ + chapterName, + releaseDate, + chapterUrl, + }); + }); + return novelChapters; + }; + + novel.chapters = await getChapters(novelId); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $(".chr-title").attr("title"); + let chapterText = $("#chr-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + if ($("a#next_chap").attr("href")) { + nextChapter = $("a#next_chap") + .attr("href") + .replace(`/${novelUrl}/`, ""); + } + + let prevChapter = null; + if ($("a#prev_chap").attr("href")) { + prevChapter = $("a#prev_chap") + .attr("href") + .replace(`/${novelUrl}/`, ""); + } + + const chapter = { + sourceId: 4, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const searchUrl = `https://readnovelfull.com/search?keyword=`; + + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.col-novel-main > div.list-novel > .row").each(function (result) { + let novelUrl = $(this) + .find("h3.novel-title > a") + .attr("href") + .replace(".html", "") + .substring(1); + novelUrl = `${novelUrl}/`; + + const novelName = $(this).find("h3.novel-title > a").text(); + const novelCover = $(this).find("img").attr("src"); + + const novel = { + sourceId: 4, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const readNovelFullScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default readNovelFullScraper; diff --git a/src/sources/en/tapread.js b/src/sources/en/tapread.js new file mode 100644 index 00000000..98388e7c --- /dev/null +++ b/src/sources/en/tapread.js @@ -0,0 +1,175 @@ +import cheerio from "react-native-cheerio"; +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "http://www.tapread.com"; + +const popularNovels = async (page) => { + const result = await fetch(baseUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $('.section-item[data-classify="1"]').each(function (result) { + const novelName = $(this).find(".book-name").text(); + const novelCover = "http:" + $(this).find("img").attr("src"); + let novelUrl = $(this).attr("data-id"); + novelUrl += "/"; + + const novel = { + sourceId: 17, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}/book/detail/${novelUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 17; + + novel.sourceName = "TapRead"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".book-name").text(); + + novel.novelCover = "http:" + $("div.book-img > img").attr("src"); + + novel.genre = $("div.book-catalog > span.txt").text(); + + novel.Status = $("div.book-state > span.txt").text(); + + novel.author = $("div.author > span.name").text(); + + novelSummary = $("div.content > p.desc").text(); + + const getChapters = async (novelId) => { + const chapterListUrl = "http://www.tapread.com/ajax/book/contents"; + + let formData = new FormData(); + formData.append("bookId", novelId); + + const data = await fetch(chapterListUrl, { + method: "POST", + body: formData, + }); + + const chapters = await data.json(); + + let novelChapters = []; + + chapters.result.chapterList.map((chapter) => { + let chapterName = chapter.chapterName; + const releaseDate = chapter.pubTime; + const chapterUrl = chapter.chapterId.toString(); + + if (chapter.lock) { + chapterName = "🔒 " + chapterName; + } + + novelChapters.push({ + chapterUrl, + chapterName, + releaseDate, + }); + }); + + return novelChapters; + }; + + novel.chapters = await getChapters(novelUrl); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + let formData = new FormData(); + formData.append("bookId", novelUrl); + formData.append("chapterId", chapterUrl); + + const url = "http://www.tapread.com/ajax/book/chapter"; + + const result = await fetch(url, { + method: "POST", + body: formData, + }); + const body = await result.json(); + + const chapterName = body.result.chapterName; + const chapterText = htmlToText(body.result.content); + const nextChapter = + body.result.nextChapterId === 0 + ? null + : body.result.nextChapterId.toString(); + const prevChapter = body.result.preChapterId.toString(); + novelUrl += "/"; + + const chapter = { + sourceId: 17, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + let formData = new FormData(); + formData.append("storyType", 1); + formData.append("pageNo", 1); + formData.append("searchText", searchTerm); + + const url = "http://www.tapread.com/ajax/search/story"; + + const data = await fetch(url, { + method: "POST", + body: formData, + }); + + const body = await data.json(); + + const novels = []; + + body.result.storyList.map((novel) => { + const novelName = novel.storyName.replace( + 'Demon', + "" + ); + const novelUrl = novel.storyId + "/"; + const novelCover = "http://static.tapread.com" + novel.coverUrl; + + novels.push({ sourceId: 17, novelName, novelCover, novelUrl }); + }); + + return novels; +}; + +const tapReadScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default tapReadScraper; diff --git a/src/sources/en/vipnovel.js b/src/sources/en/vipnovel.js new file mode 100644 index 00000000..03800f5b --- /dev/null +++ b/src/sources/en/vipnovel.js @@ -0,0 +1,204 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://vipnovel.com/"; + +const popularNovels = async (page) => { + let url = baseUrl; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".page-item-detail").each(function (result) { + const novelName = $(this).find("h5 > a").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("h5 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}vipnovel/`, ""); + + const novel = { + sourceId: 10, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}vipnovel/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 10; + + novel.sourceName = "VipNovel"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".post-title > h3") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.novelCover = $(".summary_image > a > img").attr("src"); + $(".post-content_item").each(function (result) { + detailName = $(this) + .find(".summary-heading > h5") + .text() + .replace(/[\t\n]/g, "") + .trim(); + detail = $(this) + .find(".summary-content") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + switch (detailName) { + case "Genre(s)": + novel.genre = detail.trim().replace(/[\t\n]/g, ","); + break; + case "Author(s)": + novel.author = detail.trim(); + break; + case "Artist(s)": + novel.status = detail.trim(); + break; + } + }); + + // $(".description-summary > div.summary__content").find("em").remove(); + + let novelSummary = $(".description-summary > div.summary__content").html(); + + novel.summary = htmlToText(novelSummary); + + let novelChapters = []; + + $(".wp-manga-chapter").each(function (result) { + const chapterName = $(this) + .find("a") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + const releaseDate = $(this) + .find("span") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + const chapterUrl = $(this).find("a").attr("href").replace(url, ""); + + const chapter = { chapterName, releaseDate, chapterUrl }; + + novelChapters.push(chapter); + }); + + novel.chapters = novelChapters.reverse(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}vipnovel/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let chapterName = $(".text-center").text(); + + if (!chapterName) { + chapterName = $(".text-left > div> h3").text(); + } + + let chapterText = $(".text-left").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($(".nav-next").length) { + nextChapter = $(".nav-next") + .find("a") + .attr("href") + .replace(baseUrl + "vipnovel/" + novelUrl + "/", ""); + } + + let prevChapter = null; + + if ($(".nav-previous").length) { + prevChapter = $(".nav-previous") + .find("a") + .attr("href") + .replace(baseUrl + "vipnovel/" + novelUrl + "/", ""); + } + + const chapter = { + sourceId: 10, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".c-tabs-item__content").each(function (result) { + const novelName = $(this).find("h4 > a").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("h4 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}vipnovel/`, ""); + + const novel = { + sourceId: 10, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const vipNovelScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default vipNovelScraper; diff --git a/src/sources/en/woopread.js b/src/sources/en/woopread.js new file mode 100644 index 00000000..56bb848e --- /dev/null +++ b/src/sources/en/woopread.js @@ -0,0 +1,202 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://woopread.com/"; + +const popularNovels = async (page) => { + let url = baseUrl + "novellist/?m_orderby=rating"; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".page-item-detail").each(function (result) { + const novelName = $(this).find(".h5 > a").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find(".h5 > a").attr("href"); + novelUrl = novelUrl.replace(baseUrl + "series/", ""); + + const novel = { + sourceId: 21, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}series/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 21; + + novel.sourceName = "WoopRead"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".post-title > h1") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel.novelCover = $(".summary_image > a > img").attr("src"); + + $(".post-content_item").each(function (result) { + detailName = $(this) + .find(".summary-heading > h5") + .text() + .replace(/[\t\n]/g, "") + .trim(); + detail = $(this) + .find(".summary-content") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + novel[detailName] = detail; + }); + + $(".description-summary > div.summary__content").find("em").remove(); + + novel.summary = $(".description-summary > div.summary__content") + .text() + .replace(/[\t\n]/g, ""); + + let novelChapters = []; + + const novelId = $(".rating-post-id").attr("value"); + + let formData = new FormData(); + formData.append("action", "manga_get_chapters"); + formData.append("manga", novelId); + + const data = await fetch("https://woopread.com/wp-admin/admin-ajax.php", { + method: "POST", + body: formData, + }); + const text = await data.text(); + + $ = cheerio.load(text); + + $(".wp-manga-chapter.free-chap").each(function (result) { + chapterName = $(this) + .find("a") + .text() + .replace(/[\t\n]/g, "") + .trim(); + + releaseDate = $(this).find("span").text().replace("Free", "").trim(); + + chapterUrl = $(this).find("a").attr("href").replace(url, ""); + + novelChapters.push({ chapterName, releaseDate, chapterUrl }); + }); + + novel.chapters = novelChapters.reverse(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}series/${novelUrl}/${chapterUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1#chapter-heading").text(); + let chapterText = $(".reading-content").html(); + chapterText = htmlToText(chapterText); + chapterText = chapterText.replace(/(?<=[[])[\n](?=[h])/g, ""); + + let nextChapter = null; + + if ($(".nav-next").length) { + nextChapter = $(".nav-next") + .find("a") + .attr("href") + .replace(baseUrl + "series/" + novelUrl + "/", ""); + } + + let prevChapter = null; + + if ($(".nav-previous").length) { + prevChapter = $(".nav-previous") + .find("a") + .attr("href") + .replace(baseUrl + "series/" + novelUrl + "/", ""); + } + + novelUrl += "/"; + chapterUrl = optionalUrl + chapterUrl + "/"; + + const chapter = { + sourceId: 21, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}?s=${searchTerm}&post_type=wp-manga&op=&author=&artist=&release=&adult=`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".c-tabs-item__content").each(function (result) { + const novelName = $(this).find(".h4 > a").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find(".h4 > a").attr("href"); + novelUrl = novelUrl.replace(`${baseUrl}series/`, ""); + + const novel = { + sourceId: 21, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const WoopReadScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default WoopReadScraper; diff --git a/src/sources/en/wuxiaworld.js b/src/sources/en/wuxiaworld.js new file mode 100644 index 00000000..3ff31270 --- /dev/null +++ b/src/sources/en/wuxiaworld.js @@ -0,0 +1,179 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://www.wuxiaworld.com/"; + +const popularNovels = async (page) => { + const url = `${baseUrl}api/novels`; + + const result = await fetch(url); + const data = await result.json(); + + let novels = []; + + data.items.map((novel) => { + let novelName = novel.name; + let novelCover = novel.coverUrl; + let novelUrl = novel.slug; + + novels.push({ + sourceId: 7, + novelUrl, + novelName, + novelCover, + }); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}novel/${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 7; + + novel.sourceName = "WuxiaWorld"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("h2").text(); + + novel.novelCover = $("img.img-thumbnail").attr("src"); + + novel.summary = $(".fr-view > p").text(); + + novel.author = $("div > dt") + .filter(function () { + return $(this).text().trim() === "Author:"; + }) + .next() + .text(); + + let genres = []; + + $(".genres") + .find("div") + .each(function (res) { + genres.push($(this).find("a").text()); + }); + + novel.genre = genres.join(","); + + novel.artist = null; + + novel.Status = null; + + let novelChapters = []; + + $(".chapter-item").each(function (result) { + let chapterName = $(this).text(); + chapterName = chapterName.replace(/[\t\n]/g, ""); + + const releaseDate = null; + + let chapterUrl = $(this).find("a").attr("href"); + chapterUrl = chapterUrl.replace(`/novel/${novelUrl}/`, ""); + + const chapter = { + chapterName, + releaseDate, + chapterUrl, + }; + + novelChapters.push(chapter); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + let url = `${baseUrl}novel/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let chapterName = $("#sidebar-toggler-container").next().text(); + chapterName = chapterName.replace(/[\t\n]/g, ""); + + $("#chapter-content > script").remove(); + + let chapterText = $("#chapter-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($("li.next > a").attr("href") !== "#") { + nextChapter = $("li.next > a") + .attr("href") + .replace(`/novel/${novelUrl}`, ""); + } + + let prevChapter = null; + + if ($("li.prev > a").attr("href") !== "#") { + prevChapter = $("li.prev > a") + .attr("href") + .replace(`/novel/${novelUrl}`, ""); + } + + const chapter = { + sourceId: 7, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const searchUrl = `https://www.wuxiaworld.com/api/novels/search?query=`; + + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const data = await result.json(); + + let novels = []; + + data.items.map((novel) => { + let novelName = novel.name; + let novelCover = novel.coverUrl; + let novelUrl = novel.slug; + + novels.push({ + sourceId: 7, + novelUrl, + novelName, + novelCover, + }); + }); + + return novels; +}; + +const WuxiaWorldScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default WuxiaWorldScraper; diff --git a/src/sources/en/wuxiaworldcloud.js b/src/sources/en/wuxiaworldcloud.js new file mode 100644 index 00000000..9e5e895a --- /dev/null +++ b/src/sources/en/wuxiaworldcloud.js @@ -0,0 +1,200 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "http://wuxiaworld.cloud/"; + +const popularNovels = async (page) => { + const url = `${baseUrl}/popular-novel`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.col-novel-main > div.list-novel > .row").each(function (result) { + let novelUrl = $(this) + .find("h3.novel-title > a") + .attr("href") + .replace(baseUrl + "novel/", ""); + novelUrl = `${novelUrl}/`; + + const novelName = $(this).find("h3.novel-title > a").text(); + const novelCover = $(this).find("img").attr("src"); + + const novel = { + sourceId: 20, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}novel/${novelUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 20; + + novel.sourceName = "WuxiaWorld.cloud"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $("div.book > img").attr("alt"); + + novel.novelCover = $("div.book > img").attr("src"); + + novel.summary = $("div.desc-text").text(); + + novel.author = $("div.info > div > h3") + .filter(function () { + return $(this).text().trim() === "Author:"; + }) + .siblings() + .text(); + + novel.genre = $("div.info > div") + .filter(function () { + return $(this).find("h3").text().trim() === "Genre:"; + }) + .text() + .replace("Genre:", "") + .replace(/\s/g, ""); + + novel.artist = null; + + novel.Status = $("li > h3") + .filter(function () { + return $(this).text().trim() === "Status:"; + }) + .siblings() + .text(); + + const novelId = $("#rating").attr("data-novel-id"); + + const getChapters = async (novelId) => { + const chapterListUrl = + baseUrl + "ajax/chapter-option?novelId=" + novelId; + + const data = await fetch(chapterListUrl); + const chapters = await data.text(); + + $ = cheerio.load(chapters); + + let novelChapters = []; + + $("select > option").each(function (result) { + let chapterName = $(this).text(); + let releaseDate = null; + let chapterUrl = $(this).attr("value"); + chapterUrl = chapterUrl.replace(baseUrl, ""); + + novelChapters.push({ + chapterName, + releaseDate, + chapterUrl, + }); + }); + return novelChapters; + }; + + novel.chapters = await getChapters(novelId); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + chapterUrl = encodeURI(chapterUrl); + + const url = `${baseUrl}${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $(".chr-title").attr("title"); + let chapterText = $("#chr-content").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + if ($("a#next_chap").attr("href")) { + nextChapter = $("a#next_chap").attr("href").replace(baseUrl, ""); + } + + let prevChapter = null; + if ($("a#prev_chap").attr("href")) { + prevChapter = $("a#prev_chap").attr("href").replace(baseUrl, ""); + } + + const chapter = { + sourceId: 20, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const searchUrl = `http://wuxiaworld.cloud/search?keyword=`; + + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.col-novel-main > div.list-novel > .row").each(function (result) { + let novelUrl = $(this) + .find("h3.novel-title > a") + .attr("href") + .replace(baseUrl + "novel/", ""); + novelUrl = `${novelUrl}/`; + + const novelName = $(this).find("h3.novel-title > a").text(); + const novelCover = $(this).find("img").attr("src"); + + const novel = { + sourceId: 20, + novelUrl, + novelName, + novelCover, + }; + + novels.push(novel); + }); + + return novels; +}; + +const WuxiaWorldCloudScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default WuxiaWorldCloudScraper; diff --git a/src/sources/en/wuxiaworldco.js b/src/sources/en/wuxiaworldco.js new file mode 100644 index 00000000..727886db --- /dev/null +++ b/src/sources/en/wuxiaworldco.js @@ -0,0 +1,163 @@ +import cheerio from "react-native-cheerio"; + +import { htmlToText } from "../helpers/htmlToText"; + +const baseUrl = "https://www.wuxiaworld.co/"; + +const popularNovels = async (page) => { + const result = await fetch(baseUrl); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".section-item").each(function (result) { + const novelName = $(this).find(".book-name").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").slice(1); + + const novel = { + sourceId: 16, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}${novelUrl}/`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = {}; + + novel.sourceId = 16; + + novel.sourceName = "WuxiaWorldCo"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".book-name").text(); + + novel.novelCover = $("div.book-img > img").attr("src"); + + novel.genre = $("div.book-catalog > span.txt").text(); + + novel.Status = $("div.book-state > span.txt").text(); + + novel.author = $("div.author > span.name").text(); + + novelSummary = $("div.content > p.desc").html(); + novel.summary = htmlToText(novelSummary); + + let novelChapters = []; + + $(".chapter-item").each(function (result) { + const chapterName = $(this).find(".chapter-name").text(); + const releaseDate = null; + const chapterUrl = $(this).attr("href").split("/")[2]; + + novelChapters.push({ + chapterName, + releaseDate, + chapterUrl, + }); + }); + + novel.chapters = novelChapters; + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + const chapterName = $("h1.chapter-title").text(); + let chapterText = $("div.chapter-entity").html(); + chapterText = htmlToText(chapterText); + + let nextChapter = null; + + if ($("a.next").length) { + nextChapter = $("a.next") + .attr("href") + .replace("/" + novelUrl + "/", ""); + } + + let prevChapter = null; + + if ($("a.prev").length) { + prevChapter = $("a.prev") + .attr("href") + .replace("/" + novelUrl + "/", ""); + } + + const chapter = { + sourceId: 16, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${baseUrl}search/${searchTerm}/1`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".list-item").each(function (result) { + $(this).find("font").remove(); + + const novelName = $(this).find(".book-name").text(); + const novelCover = $(this).find("img").attr("src"); + + let novelUrl = $(this).find("a").attr("href").slice(1); + + const novel = { + sourceId: 16, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const WuxiaWorldCoScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default WuxiaWorldCoScraper; diff --git a/src/sources/en/wuxiaworldsite.js b/src/sources/en/wuxiaworldsite.js new file mode 100644 index 00000000..2f13e0e2 --- /dev/null +++ b/src/sources/en/wuxiaworldsite.js @@ -0,0 +1,200 @@ +import cheerio from "react-native-cheerio"; + +const baseUrl = "https://wuxiaworldsite.co/"; +const searchUrl = "https://wuxiaworldsite.co/search/"; + +const popularNovels = async (page) => { + const url = `${baseUrl}/power-ranking`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".a_item").each((i, el) => { + const novelName = $(el).find("a").attr("title"); + const novelCover = baseUrl + $(el).find("a > img").attr("src"); + + let novelUrl = $(el).find(".name_views > a").attr("href"); + novelId = novelUrl.split("/"); + novelUrl = novelId[2] + "/"; + + const novel = { + sourceId: 12, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}${novelUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + $(".category_list").remove(); + + let novel = {}; + + novel.sourceId = 12; + + novel.sourceName = "WuxiaWorldSite"; + + novel.url = url; + + novel.novelUrl = novelUrl; + + novel.novelName = $(".content-reading > h1").text().trim(); + + novel.novelCover = baseUrl + $(".img-read> img").attr("src"); + + novel.summary = $(".story-introduction-content").text(); + + novel.author = $(".content-reading > p").text(); + + novel.artist = null; + + novel.genre = ""; + + $(".a_tag_item").each((i, el) => { + novel.genre += $(el).text() + ","; + }); + + novel.genre = novel.genre.split(","); + novel.genre.pop(); + + novel.Status = novel.genre.pop(); + + novel.genre = novel.genre.join(","); + + const novelID = $(".show-more-list").attr("data-id"); + + const getChapters = async (novelID) => { + const chapterListUrl = baseUrl + "/get-full-list.ajax?id=" + novelID; + + const data = await fetch(chapterListUrl); + const chapters = await data.text(); + + $ = cheerio.load(chapters); + + let novelChapters = []; + + $(".new-update-content").each((i, el) => { + let chapterName = $(el).text().split(/\t+/); + const releaseDate = chapterName.pop(); + chapterName = chapterName[0]; + let chapterUrl = $(el).attr("href"); + chapterUrl = chapterUrl.split("/").pop(); + + const novel = { + chapterName, + releaseDate, + chapterUrl, + }; + novelChapters.push(novel); + }); + return novelChapters; + }; + + novel.chapters = await getChapters(novelID); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = `${baseUrl}/${novelUrl}/${chapterUrl}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let chapterText = $("#content").html() || ""; + let chapterName = ""; + if (chapterText) { + chapterText = chapterText.split("
"); + chapterName = chapterText.shift(); + } else { + $("p").each((i, el) => { + if ($(el).css("display") !== "none") { + chapterText += $(el).text() + "\n"; + } + }); + chapterText = chapterText.split("\n"); + chapterName = chapterText.shift(); + } + + chapterText = chapterText.join("\n"); + + const prevChapter = $(".pre").attr("href") + ? $(".pre").attr("href").split("/").pop() + : null; + + const nextChapter = $(".next_sesction > a").attr("href") + ? $(".next_sesction > a").attr("href").split("/").pop() + : null; + + novelUrl += "/"; + chapterUrl += "/"; + + const chapter = { + sourceId: 12, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = `${searchUrl}${searchTerm}`; + + const result = await fetch(url); + const body = await result.text(); + + $ = cheerio.load(body); + + let novels = []; + + $(".a_item").each((i, el) => { + const novelName = $(el).find(".name_views > a").attr("title"); + const novelCover = baseUrl + $(el).find("a > img").attr("src"); + let novelUrl = $(el).find(".name_views > a").attr("href"); + novelId = novelUrl.split("/"); + novelUrl = novelId[2] + "/"; + + const novel = { + sourceId: 12, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return novels; +}; + +const WuxiaWorldSiteScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default WuxiaWorldSiteScraper; diff --git a/src/sources/sources.js b/src/sources/sources.js index 22b4ce12..72e31706 100644 --- a/src/sources/sources.js +++ b/src/sources/sources.js @@ -1,6 +1,26 @@ import ComradeMaoScraper from "./en/comrademao"; import ReadLightNovelScraper from "./en/readlightnovel"; import BoxNovelScraper from "./en/boxnovel"; +import fastNovelScraper from "./en/fastnovel"; +import readNovelFullScraper from "./en/readnovelfull"; +import mtlNovelScraper from "./en/mtlnovel"; +import novelhallScraper from "./en/novelhall"; +import WuxiaWorldScraper from "./en/wuxiaworld"; +import novelFullScraper from "./en/novelfull"; +import novelTrenchScraper from "./en/noveltrench"; +import vipNovelScraper from "./en/vipnovel"; +import kissLightNovelScraper from "./en/kisslightnovels"; +import WuxiaWorldSiteScraper from "./en/wuxiaworldsite"; +import FreeWebNovelScraper from "./en/freewebnovel"; +import JPMTLScraper from "./en/jpmtl"; +import lightNovelPubScraper from "./en/lightnovelpub"; +import WuxiaWorldCoScraper from "./en/wuxiaworldco"; +import novelUpdatesCcScraper from "./en/novelupdatescc"; +import readLightNovelCcScraper from "./en/readlightnovelcc"; +import tapReadScraper from "./en/tapread"; +import WuxiaWorldCloudScraper from "./en/wuxiaworldcloud"; +import WoopReadScraper from "./en/woopread"; +import FoxaHolicScraper from "./en/foxaholic"; export const sources = [ { @@ -17,6 +37,146 @@ export const sources = [ lang: "English", icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/readlightnovel/icon.png?raw=true", }, + { + sourceId: 3, + url: "https://fastnovel.net/", + sourceName: "FastNovel", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/fastnovel/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 4, + url: "https://readnovelfull.com/", + sourceName: "ReadNovelFull", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/readnovelfull/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 5, + url: "https://www.mtlnovel.com/", + sourceName: "MTLNovel", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/mtlnovel/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 6, + url: "https://www.novelhall.com/", + sourceName: "NovelHall", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/novelhall/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 7, + url: "https://www.wuxiaworld.com/", + sourceName: "WuxiaWorld", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/wuxiaworld/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 8, + url: "https://novelfull.com/", + sourceName: "NovelFull", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/novelfull/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 9, + url: "https://noveltrench.com/", + sourceName: "NovelTrench", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/noveltrench/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 10, + url: "https://vipnovel.com/", + sourceName: "VipNovel", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/vipnovel/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 11, + url: "https://kisslightnovels.info/", + sourceName: "KissLightNovels", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/kisslightnovels/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 12, + url: "https://wuxiaworldsite.co/", + sourceName: "WuxiaWorldSite", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/wuxiaworldsite/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 13, + url: "https://freewebnovel.com/", + sourceName: "FreeWebNovel", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/freewebnovel/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 14, + url: "https://jpmtl.com/", + sourceName: "JPMTL", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/jpmtl/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 15, + url: "https://www.lightnovelpub.com/", + sourceName: "LightNovelPub", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/lightnovelpub/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 16, + url: "https://www.wuxiaworld.co/", + sourceName: "WuxiaWorld.co", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/wuxiaworldco/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 17, + url: "http://www.tapread.com/", + sourceName: "TapRead", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/tapread/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 18, + url: "https://www.novelupdates.cc/", + sourceName: "NovelUpdates.cc", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/novelupdatescc/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 19, + url: "https://m.readlightnovel.cc/", + sourceName: "ReadLightNovel.cc", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/readlightnovelcc/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 20, + url: "http://wuxiaworld.cloud/", + sourceName: "WuxiaWorld.cloud", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/wuxiaworldcloud/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 21, + url: "https://woopread.com/", + sourceName: "WoopRead", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/woopread/icon.png?raw=true", + lang: "English", + }, + { + sourceId: 22, + url: "https://foxaholic.com/", + sourceName: "Foxaholic", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/foxaholic/icon.png?raw=true", + lang: "English", + }, { sourceId: 27, url: "https://comrademao.com/", @@ -34,8 +194,83 @@ export const getSource = (sourceId) => { case 2: { return ReadLightNovelScraper; } + case 3: { + return fastNovelScraper; + } + case 4: { + return readNovelFullScraper; + } + case 5: { + return mtlNovelScraper; + } + case 6: { + return novelhallScraper; + } + case 7: { + return WuxiaWorldScraper; + } + case 8: { + return novelFullScraper; + } + case 9: { + return novelTrenchScraper; + } + case 10: { + return vipNovelScraper; + } + case 11: { + return kissLightNovelScraper; + } + case 12: { + return WuxiaWorldSiteScraper; + } + case 13: { + return FreeWebNovelScraper; + } + case 14: { + return JPMTLScraper; + } + case 15: { + return lightNovelPubScraper; + } + case 16: { + return WuxiaWorldCoScraper; + } + case 17: { + return tapReadScraper; + } + case 18: { + return novelUpdatesCcScraper; + } + case 19: { + return readLightNovelCcScraper; + } + case 20: { + return WuxiaWorldCloudScraper; + } + case 21: { + return WoopReadScraper; + } + case 22: { + return FoxaHolicScraper; + } + case 23: { + return; + } + case 24: { + return; + } + case 25: { + return; + } + case 26: { + return; + } case 27: { return ComradeMaoScraper; } + case 3: { + return; + } } };