diff --git a/src/components/NovelCover.js b/src/components/NovelCover.js index d1dd1be5..83a38da6 100644 --- a/src/components/NovelCover.js +++ b/src/components/NovelCover.js @@ -200,6 +200,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 4.5, paddingVertical: 4, borderRadius: 4, + flex: 1, }, extensionIcon: { width: 42, diff --git a/src/screens/Browse/Browse.js b/src/screens/Browse/Browse.js index d43e0781..03ccb0cc 100644 --- a/src/screens/Browse/Browse.js +++ b/src/screens/Browse/Browse.js @@ -110,7 +110,7 @@ const Browse = ({ navigation }) => { extraData={pinned} ListHeaderComponent={ - {(showNovelUpdates || showMyAnimeList) && ( + {showMyAnimeList && ( <> { > Discover - {showNovelUpdates && ( + {/* {showNovelUpdates && ( @@ -132,7 +132,7 @@ const Browse = ({ navigation }) => { icon={require("../../../assets/novelupdates.png")} theme={theme} /> - )} + )} */} {showMyAnimeList && ( { /> Discover - { dispatch(enableDiscover("showNovelUpdates")) } /> - + */} { } }, []); + const setImmersiveMode = () => { + StatusBar.setHidden(true); + hideNavigationBar(); + }; + const scrollToSavedProgress = useCallback((event) => { StatusBar.setHidden(true); hideNavigationBar(); @@ -279,133 +285,163 @@ const Chapter = ({ route, navigation }) => { return ( <> - - (scrollViewRef.current = ref)} - contentContainerStyle={[ - styles.screenContainer, - { backgroundColor: readerBackground(reader.theme) }, - ]} - onScroll={onScroll} - onContentSizeChange={(x, y) => setContentSize(y)} - showsVerticalScrollIndicator={false} - > - - {error ? ( - - - { - getChapter(chapterId); - setLoading(true); - setError(); - }} - /> - + + + ) : ( + + ) + ) : ( + <> + + (scrollViewRef.current = ref)} + contentContainerStyle={[ + styles.screenContainer, + { backgroundColor: readerBackground(reader.theme) }, + ]} + onScroll={onScroll} + onContentSizeChange={(x, y) => setContentSize(y)} + showsVerticalScrollIndicator={false} + > + {error ? ( + + - Retry - - - - ) : loading ? ( - - - - ) : ( - - {images.length > 0 && - images.map((image, index) => ( - { + getChapter(chapterId); + setLoading(true); + setError(); + }} /> - ))} - - + Retry + + + + ) : loading ? ( + + + + ) : ( + - {chapter.chapterText - .trim() - .replace(/\[https.*?\]/g, "")} - - - )} - - - + {images.length > 0 && + images.map((image, index) => ( + + ))} + + + {chapter.chapterText + .trim() + .replace(/\[https.*?\]/g, "")} + + + + )} + + + + + - - - - - {showScrollPercentage && ( - - {scrollPercentage + "%"} - + + {showScrollPercentage && ( + + {scrollPercentage + "%"} + + )} + )} ); diff --git a/src/screens/Novel/components/NovelHeader.js b/src/screens/Novel/components/NovelHeader.js index 77269c9e..d0d06aad 100644 --- a/src/screens/Novel/components/NovelHeader.js +++ b/src/screens/Novel/components/NovelHeader.js @@ -1,5 +1,12 @@ import React, { memo } from "react"; -import { View, Text, StyleSheet, Clipboard, Pressable } from "react-native"; +import { + View, + Text, + StyleSheet, + Clipboard, + Pressable, + Button, +} from "react-native"; import * as WebBrowser from "expo-web-browser"; import { TouchableRipple, IconButton } from "react-native-paper"; @@ -186,7 +193,7 @@ const NovelInfoHeader = ({ followed={novel.followed} theme={theme} /> - {novel.genre && novel.genre !== "" && ( + {novel.genre.length > 0 && novel.genre !== "" && ( )} { + const totalPages = 100; + let url = `${baseUrl}series-ranking/?rank=sixmonths&pg=` + page; + + const result = await fetch(url, { + method: "GET", + headers: headers, + }); + const body = await result.text(); + + const $ = cheerio.load(body); + + const novels = []; + + $("div.search_main_box_nu").each(function (res) { + const novelCover = $(this).find("img").attr("src"); + const novelName = $(this).find(".search_title > a").text(); + const novelUrl = $(this) + .find(".search_title > a") + .attr("href") + .split("/")[4]; + + const novel = { + sourceId, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + + return { totalPages, novels }; +}; + +const parseNovelAndChapters = async (novelUrl) => { + const url = `${baseUrl}series/${novelUrl}`; + + const result = await fetch(url, { + method: "GET", + headers: headers, + }); + const body = await result.text(); + + $ = cheerio.load(body); + + let novel = { + sourceId, + sourceName, + url, + novelUrl, + }; + + novel.novelName = $(".seriestitlenu").text(); + + novel.novelCover = $(".seriesimg > img").attr("src"); + + novel.author = $("#showauthors").text().trim(); + + novel.genre = $(".book-generes").text().trim(); + + novel.status = $("#editstatus").text().includes("Ongoing") + ? "Ongoing" + : "Completed"; + + novel.summary = $("#editdescription").text().trim(); + + let novelChapters = []; + + const novelId = $("input#mypostid").attr("value"); + + let formData = new FormData(); + formData.append("action", "nd_getchapters"); + formData.append("mygrr", 0); + formData.append("mypostid", parseInt(novelId)); + + const data = await fetch( + "https://www.novelupdates.com/wp-admin/admin-ajax.php", + { + method: "POST", + headers, + body: formData, + } + ); + const text = await data.text(); + + $ = cheerio.load(text); + + $("li.sp_li_chp").each(function () { + const chapterName = $(this).text().trim(); + + const releaseDate = null; + + const chapterUrl = + "https:" + $(this).find("a").first().next().attr("href"); + + novelChapters.push({ chapterName, releaseDate, chapterUrl }); + }); + + novel.chapters = novelChapters.reverse(); + + return novel; +}; + +const parseChapter = async (novelUrl, chapterUrl) => { + const url = chapterUrl; + + const result = await fetch(url, { + method: "GET", + headers: headers, + }); + const body = await result.text(); + + $ = cheerio.load(body); + + let chapterName = ""; + + let chapterText = body; + + let nextChapter = null; + let prevChapter = null; + + const chapter = { + sourceId, + novelUrl, + chapterUrl, + chapterName, + chapterText, + nextChapter, + prevChapter, + }; + + return chapter; +}; + +const searchNovels = async (searchTerm) => { + const url = + "https://www.novelupdates.com/?s=" + + searchTerm + + "&post_type=seriesplans"; + + const res = await fetch(url, { + method: "GET", + headers: headers, + }); + const body = await res.text(); + + $ = cheerio.load(body); + + let novels = []; + + $("div.search_main_box_nu").each(function (res) { + const novelCover = $(this).find("img").attr("src"); + const novelName = $(this).find(".search_title > a").text(); + const novelUrl = $(this) + .find(".search_title > a") + .attr("href") + .split("/")[4]; + + const novel = { + sourceId, + novelName, + novelCover, + novelUrl, + }; + + novels.push(novel); + }); + return novels; +}; + +const NovelUpdatesScraper = { + popularNovels, + parseNovelAndChapters, + parseChapter, + searchNovels, +}; + +export default NovelUpdatesScraper; diff --git a/src/sources/en/wuxiablog.js b/src/sources/en/wuxiablog.js index a9a41e5b..74bd8616 100644 --- a/src/sources/en/wuxiablog.js +++ b/src/sources/en/wuxiablog.js @@ -97,6 +97,35 @@ const parseNovelAndChapters = async (novelUrl) => { novelChapters.push(chapter); }); + let moreChaptersUrl = + baseUrl + + "temphtml/_tempChapterList_all_" + + $("div#more").attr("data-nid") + + ".html"; + + let moreChapters = await fetch(moreChaptersUrl); + let moreChaptersString = await moreChapters.text(); + + $ = cheerio.load(moreChaptersString); + + $("a").each(function () { + const chapterName = $(this).text(); + + const releaseDate = $(this)[0] + .nextSibling.nodeValue.replace(/-/g, "/") + .trim(); + + const chapterUrl = $(this).attr("href").replace(url, ""); + + const chapter = { + chapterName, + releaseDate, + chapterUrl, + }; + + novelChapters.push(chapter); + }); + novel.chapters = novelChapters.reverse(); return novel; diff --git a/src/sources/sources.js b/src/sources/sources.js index 2cf36334..0f693b36 100644 --- a/src/sources/sources.js +++ b/src/sources/sources.js @@ -48,12 +48,19 @@ import { } from "./multisrc/madara/MadaraGenerator"; import WuxiaBlogScraper from "./en/wuxiablog"; import WuxiaCityScraper from "./en/wuxiacity"; +import NovelUpdatesScraper from "./en/novelupdates"; export const sources = [ /** * English */ - + { + sourceId: 50, + sourceUrl: "https://www.novelupdates.com/", + sourceName: "Novel Updates", + icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/novelupdates/icon.png?raw=true", + lang: "English", + }, { sourceId: 1, url: "https://boxnovel.com/", @@ -548,5 +555,8 @@ export const getSource = (sourceId) => { case 49: { return WuxiaCityScraper; } + case 50: { + return NovelUpdatesScraper; + } } };