Skip to content

Commit ee5bc52

Browse files
committed
add: novelhi (no filter)
1 parent 5be7a59 commit ee5bc52

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

plugins/english/novelhi.ts

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import { fetchApi } from '@libs/fetch';
2+
import { Plugin } from '@/types/plugin';
3+
import { load as parseHTML } from 'cheerio';
4+
import { NovelStatus } from '@libs/novelStatus';
5+
import { defaultCover } from '@libs/defaultCover';
6+
7+
class NovelHi implements Plugin.PluginBase {
8+
id = 'novelhi';
9+
name = 'NovelHi';
10+
icon = 'src/en/novelhi/icon.png';
11+
site = 'https://novelhi.com/';
12+
version = '1.0.0';
13+
14+
// flag indicates whether access to LocalStorage, SesesionStorage is required.
15+
webStorageUtilized?: boolean;
16+
17+
// Cache for storing extended metadata from the list API | ie: copypasta from readfrom.ts
18+
loadedNovelCache: CachedNovel[] = [];
19+
20+
parseNovels(novels: NovelData[]): CachedNovel[] {
21+
const ret: CachedNovel[] = novels.map(item => ({
22+
name: item.bookName,
23+
path: `s/${item.simpleName}`,
24+
cover: item.picUrl || defaultCover,
25+
summary: item.bookDesc,
26+
author: item.authorName,
27+
status: item.bookStatus,
28+
genres: item.genres.map(g => g.genreName).join(', '),
29+
}));
30+
31+
// Manage cache size
32+
this.loadedNovelCache.push(...ret);
33+
if (this.loadedNovelCache.length > 100) {
34+
this.loadedNovelCache = this.loadedNovelCache.slice(-100);
35+
}
36+
37+
return ret;
38+
}
39+
40+
async popularNovels(
41+
pageNo: number,
42+
{ showLatestNovels }: Plugin.PopularNovelsOptions,
43+
): Promise<Plugin.NovelItem[]> {
44+
const params = new URLSearchParams();
45+
46+
params.append('curr', `${pageNo}`);
47+
params.append('limit', '10');
48+
params.append('keyword', '');
49+
50+
const jsonUrl = `${this.site}book/searchByPageInShelf?` + params.toString();
51+
const response = await fetchApi(jsonUrl);
52+
const json: ApiResponse = await response.json();
53+
54+
return this.parseNovels(json.data.list);
55+
}
56+
57+
async parseNovel(novelPath: string): Promise<Plugin.SourceNovel> {
58+
const data = await fetchApi(this.site + novelPath);
59+
const text = await data.text();
60+
const loadedCheerio = parseHTML(text);
61+
62+
const translate = loadedCheerio('#translate <').html();
63+
if (translate) {
64+
console.error('This Novel has been removed and is no longer available');
65+
throw Error('This Novel has been removed and is no longer available');
66+
}
67+
68+
const novel: Plugin.SourceNovel = {
69+
path: novelPath,
70+
name: loadedCheerio('meta[name=keywords]').attr('content') || 'Untitled',
71+
cover: loadedCheerio('.cover,.decorate-img').attr('src') || defaultCover,
72+
};
73+
74+
let moreNovelInfo = this.loadedNovelCache.find(n => n.path === novelPath);
75+
76+
if (!moreNovelInfo) {
77+
moreNovelInfo = (await this.searchNovels(novel.name, 1)).find(
78+
novel => novel.path === novelPath,
79+
);
80+
}
81+
if (moreNovelInfo) {
82+
novel.genres = moreNovelInfo.genres;
83+
novel.author = moreNovelInfo.author;
84+
novel.status =
85+
moreNovelInfo.status === '1'
86+
? NovelStatus.Completed
87+
: NovelStatus.Ongoing;
88+
const summary = moreNovelInfo.summary.replace(/<br\s*\/?>/gi, '\n');
89+
novel.summary = parseHTML(summary).text().trim();
90+
}
91+
92+
const chapters: Plugin.ChapterItem[] = [];
93+
const bookId = loadedCheerio('#bookId').attr('value');
94+
if (bookId && !translate) {
95+
const params = new URLSearchParams();
96+
params.append('bookId', bookId);
97+
params.append('curr', '1');
98+
params.append('limit', '42121');
99+
100+
const url = `${this.site}book/queryIndexList?` + params.toString();
101+
const res = await fetchApi(url);
102+
const resJson: ApiChapter = await res.json();
103+
104+
resJson?.data?.list?.forEach(chapter =>
105+
chapters.push({
106+
name: chapter.indexName,
107+
path: novelPath + '/' + chapter.indexNum,
108+
releaseTime: chapter.createTime,
109+
}),
110+
);
111+
}
112+
113+
novel.chapters = chapters.reverse();
114+
return novel;
115+
}
116+
117+
async parseChapter(chapterPath: string): Promise<string> {
118+
const url = this.site + chapterPath;
119+
const result = await fetchApi(url).then(res => res.text());
120+
121+
const loadedCheerio = parseHTML(result);
122+
loadedCheerio('#showReading script,ins').remove();
123+
const chapterText = loadedCheerio('#showReading').html();
124+
if (!chapterText) {
125+
return loadedCheerio('#translate <').html() || '';
126+
}
127+
return chapterText;
128+
}
129+
130+
async searchNovels(
131+
searchTerm: string,
132+
pageNo: number,
133+
): Promise<Plugin.NovelItem[]> {
134+
const params = new URLSearchParams();
135+
136+
params.append('curr', `${pageNo}`);
137+
params.append('limit', '10');
138+
params.append('keyword', `${searchTerm}`);
139+
140+
const jsonUrl = `${this.site}book/searchByPageInShelf?` + params.toString();
141+
const response = await fetchApi(jsonUrl);
142+
const json: ApiResponse = await response.json();
143+
144+
return this.parseNovels(json.data.list);
145+
}
146+
}
147+
148+
export default new NovelHi();
149+
150+
type CachedNovel = Plugin.NovelItem & {
151+
summary: string;
152+
genres: string;
153+
author: string;
154+
status: string;
155+
};
156+
157+
type NovelData = {
158+
id: string;
159+
bookName: string;
160+
picUrl: string;
161+
simpleName: string;
162+
authorName: string;
163+
bookDesc: string;
164+
bookStatus: string;
165+
lastIndexName: string;
166+
genres: {
167+
genreId: string;
168+
genreName: string;
169+
}[];
170+
};
171+
172+
type ChapterData = {
173+
id: string;
174+
bookId: string;
175+
indexNum: string;
176+
indexName: string;
177+
createTime: string;
178+
};
179+
180+
type ApiResponse = {
181+
code: string;
182+
msg: string;
183+
data: {
184+
pageNum: string;
185+
pageSize: string;
186+
total: string;
187+
list: NovelData[];
188+
};
189+
};
190+
191+
type ApiChapter = {
192+
code: string;
193+
msg: string;
194+
data: {
195+
pageNum: string;
196+
pageSize: string;
197+
total: string;
198+
list: ChapterData[];
199+
};
200+
};
3.04 KB
Loading

0 commit comments

Comments
 (0)