Parse chapter

This commit is contained in:
Rajarshee Chatterjee
2021-06-10 11:51:22 +05:30
parent 6aa977a562
commit 4858f22a88
8 changed files with 176 additions and 60 deletions
+4
View File
@@ -6,9 +6,11 @@ import { getDeviceOrientation } from "../Services/utils/helpers";
const NovelList = ({
data,
onScroll,
renderItem,
refreshControl,
ListEmptyComponent,
ListFooterComponent,
}) => {
const { displayMode, novelsPerRow } = useSettings();
@@ -36,6 +38,8 @@ const NovelList = ({
renderItem={renderItem}
refreshControl={refreshControl}
ListEmptyComponent={ListEmptyComponent}
ListFooterComponent={ListFooterComponent}
onScroll={onScroll}
/>
);
};
+10 -15
View File
@@ -7,7 +7,7 @@ import { pinSourceAction } from "../../../redux/source/source.actions";
import FastImage from "react-native-fast-image";
const ExtensionCard = ({ item, theme, isPinned }) => {
const { sourceId, sourceName, sourceCover, sourceLanguage, status } = item;
const { sourceId, sourceName, icon, lang } = item;
const navigation = useNavigation();
const dispatch = useDispatch();
@@ -27,7 +27,7 @@ const ExtensionCard = ({ item, theme, isPinned }) => {
>
<>
<Image
source={{ uri: sourceCover }}
source={{ uri: icon }}
style={styles.extensionIcon}
resizeMode="contain"
/>
@@ -41,19 +41,14 @@ const ExtensionCard = ({ item, theme, isPinned }) => {
>
{sourceName}
</Text>
<View style={{ flexDirection: "row" }}>
<Text
style={{
color: theme.textColorSecondary,
fontSize: 12,
}}
>
{sourceLanguage}
</Text>
<Text style={styles.sourceStatus}>
{status === 0 && "• Down"}
</Text>
</View>
<Text
style={{
color: theme.textColorSecondary,
fontSize: 12,
}}
>
{lang}
</Text>
</View>
<View
style={{ flexDirection: "row", alignItems: "center" }}
+54 -22
View File
@@ -13,6 +13,8 @@ import ErrorView from "../../Components/ErrorView";
import { useDispatch } from "react-redux";
import { setAppSettings } from "../../redux/settings/settings.actions";
import { getSource } from "../../sources/sources";
const Extension = ({ navigation, route }) => {
const { sourceId, sourceName, sourceUrl } = route.params;
@@ -22,35 +24,38 @@ const Extension = ({ navigation, route }) => {
const { displayMode } = useSettings();
const [loading, setLoading] = useState(true);
const [novels, setNovels] = useState();
const [novels, setNovels] = useState([]);
const [page, setPage] = useState(1);
const [error, setError] = useState();
const [searchText, setSearchText] = useState("");
const getSourceUrl = () => {
if (sourceId === 1) {
return `https://lnreader-extensions.vercel.app/api/1/novels/1/?o=rating`;
} else {
return `https://lnreader-extensions.vercel.app/api/${sourceId}/novels/`;
}
};
// const getSourceUrl = () => {
// if (sourceId === 1) {
// return `https://lnreader-extensions.vercel.app/api/1/novels/1/?o=rating`;
// } else {
// return `https://lnreader-extensions.vercel.app/api/${sourceId}/novels/`;
// }
// };
const getSearchUrl = () => {
if (sourceId === 1) {
return `https://lnreader-extensions.vercel.app/api/1/search/?s=${searchText}&?o=rating`;
} else {
return `https://lnreader-extensions.vercel.app/api/${sourceId}/search/?s=${searchText}`;
}
};
// const getSearchUrl = () => {
// if (sourceId === 1) {
// return `https://lnreader-extensions.vercel.app/api/1/search/?s=${searchText}&?o=rating`;
// } else {
// return `https://lnreader-extensions.vercel.app/api/${sourceId}/search/?s=${searchText}`;
// }
// };
const getNovels = async () => {
const getNovels = async (page) => {
try {
const url = getSourceUrl();
const source = getSource(sourceId);
const res = await fetch(url);
const data = await res.json();
// console.log(page);
const res = await source.popularNovels(page);
setNovels(data);
// console.log(res);
setNovels((novels) => novels.concat(res));
setLoading(false);
} catch (error) {
setError(error.message);
@@ -88,9 +93,28 @@ const Extension = ({ navigation, route }) => {
};
useEffect(() => {
getNovels();
getNovels(1);
}, []);
const isCloseToBottom = ({
layoutMeasurement,
contentOffset,
contentSize,
}) => {
const paddingToBottom = 20;
return (
layoutMeasurement.height + contentOffset.y >=
contentSize.height - paddingToBottom
);
};
const onScroll = ({ nativeEvent }) => {
if (!searchText && isCloseToBottom(nativeEvent)) {
getNovels(page + 1);
setPage((page) => page + 1);
}
};
const renderItem = ({ item }) => (
<NovelCover
item={item}
@@ -99,7 +123,7 @@ const Extension = ({ navigation, route }) => {
novelName: item.novelName,
novelCover: item.novelCover,
novelUrl: item.novelUrl,
sourceId: item.extensionId,
sourceId,
})
}
libraryStatus={checkIFInLibrary(item.extensionId, item.novelUrl)}
@@ -174,6 +198,14 @@ const Extension = ({ navigation, route }) => {
data={novels}
renderItem={renderItem}
ListEmptyComponent={listEmptyComponent()}
onScroll={onScroll}
ListFooterComponent={
!searchText && (
<View style={{ paddingVertical: 16 }}>
<ActivityIndicator color={theme.colorAccent} />
</View>
)
}
/>
)}
</View>
+15 -14
View File
@@ -1,4 +1,5 @@
import { showToast } from "../../Hooks/showToast";
import { getSource } from "../../sources/sources";
export const fetchSources = async () => {
const url = `https://lnreader-extensions.vercel.app/api/`;
@@ -10,35 +11,35 @@ export const fetchSources = async () => {
};
export const fetchNovel = async (sourceId, novelUrl) => {
const url = `https://lnreader-extensions.vercel.app/api/${sourceId}/novel/${novelUrl}`;
const source = getSource(sourceId);
let data = await fetch(url);
let res = await data.json();
const res = await source.parseNovelAndChapters(novelUrl);
const novel = {
novelUrl: res.novelUrl,
sourceUrl: res.sourceUrl,
sourceUrl: res.url,
source: res.sourceName,
sourceId: res.extensionId,
sourceId: res.sourceId,
novelName: res.novelName,
novelCover: res.novelCover,
novelSummary: res.novelSummary,
author: res["Author(s)"],
artist: res["Artist(s)"],
status: res.Status,
genre: res["Genre(s)"],
novelSummary: res.summary,
author: res.author,
artist: res.artist,
status: res.status,
genre: res.genre,
followed: 0,
chapters: res.novelChapters,
chapters: res.chapters,
};
// console.log(novel);
return novel;
};
export const fetchChapter = async (sourceId, novelUrl, chapterUrl) => {
const url = `https://lnreader-extensions.vercel.app/api/${sourceId}/novel/${novelUrl}${chapterUrl}`;
const source = getSource(sourceId);
let res = await fetch(url);
let chapter = await res.json();
let chapter = await source.parseChapter(novelUrl, chapterUrl);
return chapter;
};
+1
View File
@@ -57,6 +57,7 @@ export const setNovel = (novel) => async (dispatch) => {
export const getNovelAction =
(followed, sourceId, novelUrl, novelId, sort, filter) =>
async (dispatch) => {
console.log(followed, sourceId, novelUrl, novelId, sort, filter);
try {
dispatch({ type: LOADING_NOVEL });
+2 -6
View File
@@ -1,15 +1,11 @@
import { GET_SOURCES, PIN_SOURCES, SEARCH_SOURCES } from "./source.types";
import { fetchSources } from "../../Services/Source/source";
import { showToast } from "../../Hooks/showToast";
import { sources } from "../../sources/sources";
export const getSourcesAction = () => async (dispatch) => {
try {
const res = await fetchSources();
dispatch({
type: GET_SOURCES,
payload: res,
});
dispatch({ type: GET_SOURCES, payload: sources });
} catch (error) {
showToast(error.message);
}
+71 -3
View File
@@ -54,7 +54,7 @@ const parseNovelAndChapters = async (novelUrl) => {
const novelCover = $(".novel-cover > a > img").attr("src");
let author, artist, genre, summary;
let author, artist, genre, summary, status;
$(".novel-detail-item").each(function (result) {
const detailName = $(this).find(".novel-detail-header > h6").text();
@@ -62,7 +62,7 @@ const parseNovelAndChapters = async (novelUrl) => {
switch (detailName) {
case "Genre":
genre = detail.replace(/[\t\n]/g, ",");
genre = detail.trim().replace(/[\t\n]/g, ",");
break;
case "Author(s)":
author = detail.trim();
@@ -73,6 +73,9 @@ const parseNovelAndChapters = async (novelUrl) => {
case "Description":
summary = detail;
break;
case "Status":
status = detail;
break;
}
});
@@ -111,10 +114,12 @@ const parseNovelAndChapters = async (novelUrl) => {
sourceId,
sourceName,
url,
novelUrl,
novelName,
novelCover,
genre,
author,
status,
artist,
summary,
chapters,
@@ -123,4 +128,67 @@ const parseNovelAndChapters = async (novelUrl) => {
return novel;
};
export { popularNovels, parseNovelAndChapters };
const parseChapter = async (novelUrl, chapterUrl) => {
const url = `${baseUrl}/${novelUrl}/${chapterUrl}/`;
const result = await fetch(url);
const body = await result.text();
$ = cheerio.load(body);
$(".block-title > h1").find("a").remove();
const chapterName = $(".block-title > h1").text().replace(" - ", "");
$(".desc")
.find("hr")
.each(function (result) {
$(this).remove();
});
$(".alert").remove();
$(".hidden").remove();
let chapterText = $(".desc").html();
// chapterText = parseHtml(chapterText).replace(
// /\n\nSponsored Content\n\n|If audio player doesn't work, press Stop then Play button again/g,
// ""
// );
let nextChapter = null;
if ($("a.next.next-link").length) {
nextChapter = $("a.next.next-link")
.attr("href")
.replace(`${baseUrl}/${novelUrl}/`, "");
}
let prevChapter = null;
if ($("a.prev.prev-link").length) {
prevChapter = $("a.prev.prev-link")
.attr("href")
.replace(`${baseUrl}/${novelUrl}/`, "");
}
const chapter = {
extensionId: 2,
novelUrl,
chapterUrl,
chapterName,
chapterText,
nextChapter,
prevChapter,
};
return chapter;
};
const ReadLightNovelScraper = {
popularNovels,
parseNovelAndChapters,
parseChapter,
};
export default ReadLightNovelScraper;
+19
View File
@@ -0,0 +1,19 @@
import ReadLightNovelScraper from "./en/readlightnovel";
export const sources = [
{
sourceId: 2,
sourceName: "ReadLightNovel",
url: "https://www.readlightnovel.org",
lang: "English",
icon: "https://github.com/rajarsheechatterjee/lnreader-extensions/blob/main/src/en/readlightnovel/icon.png?raw=true",
},
];
export const getSource = (sourceId) => {
switch (sourceId) {
case 2: {
return ReadLightNovelScraper;
}
}
};