@@ -9,11 +9,11 @@ import { storage } from '@libs/storage';
99class NovelFire implements Plugin . PluginBase {
1010 id = 'novelfire' ;
1111 name = 'Novel Fire' ;
12- version = '1.1.9 ' ;
12+ version = '1.2.0 ' ;
1313 icon = 'src/en/novelfire/icon.png' ;
1414 site = 'https://novelfire.net/' ;
1515
16- novelList = [ ] ;
16+ novelList : string [ ] = [ ] ;
1717
1818 singlePage = storage . get ( 'singlePage' ) ;
1919 pluginSettings = {
@@ -40,63 +40,29 @@ class NovelFire implements Plugin.PluginBase {
4040 return $ ;
4141 }
4242
43- async popularNovels (
44- pageNo : number ,
45- {
46- showLatestNovels,
47- filters,
48- } : Plugin . PopularNovelsOptions < typeof this . filters > ,
49- ) : Promise < Plugin . NovelItem [ ] > {
50- if ( pageNo == 1 ) {
51- this . novelList = [ ] ;
52- }
53- let url = this . site + 'search-adv' ;
54- if ( showLatestNovels ) {
55- url += `?ctgcon=and&totalchapter=0&ratcon=min&rating=0&status=-1&sort=date&tagcon=and&page=${ pageNo } ` ;
56- } else if ( filters ) {
57- const params = new URLSearchParams ( ) ;
58- for ( const language of filters . language . value ) {
59- params . append ( 'country_id[]' , language ) ;
60- }
61- params . append ( 'ctgcon' , filters . genre_operator . value ) ;
62- for ( const genre of filters . genres . value ) {
63- params . append ( 'categories[]' , genre ) ;
64- }
65- params . append ( 'totalchapter' , filters . chapters . value ) ;
66- params . append ( 'ratcon' , filters . rating_operator . value ) ;
67- params . append ( 'rating' , filters . rating . value ) ;
68- params . append ( 'status' , filters . status . value ) ;
69- params . append ( 'sort' , filters . sort . value ) ;
70- params . append ( 'page' , pageNo . toString ( ) ) ;
71- url += `?${ params . toString ( ) } ` ;
72- } else {
73- url += `?ctgcon=and&totalchapter=0&ratcon=min&rating=0&status=-1&sort=rank-top&page=${ pageNo } ` ;
74- }
75-
76- const loadedCheerio = await this . getCheerio ( url , false ) ;
43+ parseNovels (
44+ loadedCheerio : CheerioAPI ,
45+ selector = '.novel-item' ,
46+ ) : Plugin . NovelItem [ ] {
47+ return loadedCheerio ( selector )
48+ . map ( ( _ , el ) => {
49+ const titleElement = loadedCheerio ( el ) . find ( '.novel-title > a' ) ;
50+ const fallbackElement = loadedCheerio ( el ) . find ( 'a' ) ;
7751
78- return loadedCheerio ( '.novel-item' )
79- . map ( ( index , ele ) => {
8052 const novelName =
81- loadedCheerio ( ele ) . find ( '.novel-title > a' ) . text ( ) ||
53+ titleElement . text ( ) ||
54+ fallbackElement . attr ( 'title' ) ||
8255 'No Title Found' ;
56+
57+ const imgElement = loadedCheerio ( el ) . find ( '.novel-cover > img' ) ;
8358 const novelCover =
8459 this . site +
85- deSlash (
86- loadedCheerio ( ele ) . find ( '.novel-cover > img' ) . attr ( 'data-src' ) ||
87- '' ,
88- ) ;
89- const novelPath = loadedCheerio ( ele )
90- . find ( '.novel-title > a' )
91- . attr ( 'href' ) ;
60+ deSlash ( imgElement . attr ( 'data-src' ) || imgElement . attr ( 'src' ) || '' ) ;
9261
93- if ( ! novelPath ) return ;
62+ const novelPath =
63+ titleElement . attr ( 'href' ) || fallbackElement . attr ( 'href' ) ;
9464
95- if ( this . novelList . includes ( novelPath ) ) {
96- return ;
97- } else {
98- this . novelList . push ( novelPath ) ;
99- }
65+ if ( ! novelPath ) return null ;
10066
10167 return {
10268 name : novelName ,
@@ -105,15 +71,57 @@ class NovelFire implements Plugin.PluginBase {
10571 } ;
10672 } )
10773 . get ( )
108- . filter ( novel => novel !== null ) ;
74+ . filter ( novel => novel !== null )
75+ . filter ( novel => {
76+ if ( this . novelList . includes ( novel . path ) ) {
77+ return false ;
78+ } else {
79+ this . novelList . push ( novel . path ) ;
80+ return true ;
81+ }
82+ } ) ;
83+ }
84+
85+ async popularNovels (
86+ pageNo : number ,
87+ {
88+ showLatestNovels,
89+ filters,
90+ } : Plugin . PopularNovelsOptions < typeof this . filters > ,
91+ ) : Promise < Plugin . NovelItem [ ] > {
92+ if ( pageNo === 1 ) {
93+ this . novelList = [ ] ;
94+ }
95+ const url = this . site + 'search-adv' ;
96+ const params = new URLSearchParams ( ) ;
97+
98+ for ( const language of filters . language . value ) {
99+ params . append ( 'country_id[]' , language ) ;
100+ }
101+ params . append ( 'ctgcon' , filters . genre_operator . value ) ;
102+ for ( const genre of filters . genres . value ) {
103+ params . append ( 'categories[]' , genre ) ;
104+ }
105+ params . append ( 'totalchapter' , filters . chapters . value ) ;
106+ params . append ( 'ratcon' , filters . rating_operator . value ) ;
107+ params . append ( 'rating' , filters . rating . value ) ;
108+ params . append ( 'status' , filters . status . value ) ;
109+ params . append ( 'sort' , showLatestNovels ? 'date' : filters . sort . value ) ;
110+ params . append ( 'tagcon' , 'and' ) ;
111+ params . append ( 'page' , pageNo . toString ( ) ) ;
112+
113+ const loadedCheerio = await this . getCheerio (
114+ `${ url } ?${ params . toString ( ) } ` ,
115+ false ,
116+ ) ;
117+
118+ return this . parseNovels ( loadedCheerio ) ;
109119 }
110120
111121 async getAllChapters (
112122 novelPath : string ,
113123 post_id : string ,
114124 ) : Promise < Plugin . ChapterItem [ ] > {
115- const allChapters : Plugin . ChapterItem [ ] = [ ] ;
116-
117125 const url = `${ this . site } listChapterDataAjax?post_id=${ post_id } ` ;
118126 const result = await fetchApi ( url ) ;
119127 const body = await result . text ( ) ;
@@ -128,7 +136,7 @@ class NovelFire implements Plugin.PluginBase {
128136
129137 const json = JSON . parse ( body ) ;
130138 const chapters = json . data
131- . map ( index => {
139+ . map ( ( index : { title ?: string ; slug : string ; n_sort : number } ) => {
132140 const chapterName = load ( index . title || index . slug ) . text ( ) ;
133141 const chapterPath = `${ novelPath } /chapter-${ index . n_sort } ` ;
134142 const sortNumber = index . n_sort ;
@@ -141,9 +149,11 @@ class NovelFire implements Plugin.PluginBase {
141149 chapterNumber : Number ( sortNumber ) ,
142150 } ;
143151 } )
144- . filter ( chapter => chapter !== null ) as Plugin . ChapterItem [ ] ;
152+ . filter (
153+ ( chapter : Plugin . ChapterItem | null ) => chapter !== null ,
154+ ) as Plugin . ChapterItem [ ] ;
145155 const sortedChapters = chapters . sort ( function ( a , b ) {
146- return a . chapterNumber - b . chapterNumber ;
156+ return ( a . chapterNumber || 0 ) - ( b . chapterNumber || 0 ) ;
147157 } ) ;
148158
149159 return sortedChapters ;
@@ -161,7 +171,7 @@ class NovelFire implements Plugin.PluginBase {
161171 const retryCount = 10 ;
162172 const sleepTime = 3.5 ; // Rate limit seems to be around ~10s, so usually 3 retries should be enough for another ~30 pages.
163173
164- const chaptersArray : Plugin . ChapterItem [ ] [ ] = [ ] ;
174+ const chaptersArray : Plugin . SourcePage [ ] = [ ] ;
165175
166176 for ( let i = 0 ; i < pagesArray . length ; i += chunkSize ) {
167177 const pagesArrayChunk = pagesArray . slice ( i , i + chunkSize ) ;
@@ -202,11 +212,11 @@ class NovelFire implements Plugin.PluginBase {
202212 }
203213
204214 // Merge all chapters into a single array
205- for ( let chapters of chaptersArray ) {
206- // For some reason it's formatted this way, this fixes it.
207- chapters = chapters . chapters ;
208- for ( let i = 0 ; i < Object . keys ( chapters ) . length ; i ++ ) {
209- allChapters . push ( chapters [ i ] ) ;
215+ for ( const page of chaptersArray ) {
216+ if ( page . chapters ) {
217+ for ( const chapter of page . chapters ) {
218+ allChapters . push ( chapter ) ;
219+ }
210220 }
211221 }
212222 return allChapters ;
@@ -244,19 +254,19 @@ class NovelFire implements Plugin.PluginBase {
244254 . toArray ( )
245255 . join ( ',' ) ;
246256
247- let summary = $ ( '.summary .content' )
248- . find ( 'br' )
249- . replaceWith ( '\n' )
250- . end ( )
251- . text ( )
252- . trim ( ) ;
257+ const summary = $ ( '.summary .content' ) ;
258+ summary . find ( '.expand' ) . remove ( ) ;
259+ summary . find ( 'br' ) . replaceWith ( '\n' ) ;
260+ summary . find ( 'p' ) . before ( '\n' ) . after ( '\n\n' ) ;
253261
254- if ( summary ) {
255- summary = summary . replace ( 'Show More' , '' ) ;
256- novel . summary = summary ;
257- } else {
258- novel . summary = 'No Summary Found' ;
259- }
262+ novel . summary =
263+ summary
264+ . text ( )
265+ . split ( '\n' )
266+ . map ( line => line . trim ( ) )
267+ . join ( '\n' )
268+ ?. replace ( / \n { 3 , } / g, '\n\n' )
269+ . trim ( ) || 'Summary Not Found' ;
260270
261271 novel . author = $ ( '.author .property-item > span' ) . text ( ) ;
262272
@@ -291,7 +301,7 @@ class NovelFire implements Plugin.PluginBase {
291301 novelPath ,
292302 novel . totalPages ,
293303 ) ;
294- if ( novel . totalPages > 1 && novel . chapters . length > 100 ) {
304+ if ( novel . totalPages > 1 && novel . chapters . length > 50 ) {
295305 novel . totalPages = 1 ;
296306 }
297307 }
@@ -350,33 +360,19 @@ class NovelFire implements Plugin.PluginBase {
350360 searchTerm : string ,
351361 page : number ,
352362 ) : Promise < Plugin . NovelItem [ ] > {
353- const url = `${ this . site } search?keyword=${ encodeURIComponent ( searchTerm ) } &page=${ page } ` ;
363+ if ( page === 1 ) {
364+ this . novelList = [ ] ;
365+ }
366+ const params = new URLSearchParams ( ) ;
367+ params . append ( 'keyword' , searchTerm ) ;
368+ params . append ( 'page' , page . toString ( ) ) ;
369+ const url = `${ this . site } search?${ params . toString ( ) } ` ;
354370 const result = await fetchApi ( url ) ;
355371 const body = await result . text ( ) ;
356372
357373 const loadedCheerio = load ( body ) ;
358374
359- return loadedCheerio ( '.novel-list.chapters .novel-item' )
360- . map ( ( index , ele ) => {
361- const novelName =
362- loadedCheerio ( ele ) . find ( 'a' ) . attr ( 'title' ) || 'No Title Found' ;
363- const novelCover =
364- this . site +
365- deSlash (
366- loadedCheerio ( ele ) . find ( '.novel-cover > img' ) . attr ( 'src' ) || '' ,
367- ) ;
368- const novelPath = loadedCheerio ( ele ) . find ( 'a' ) . attr ( 'href' ) ;
369-
370- if ( ! novelPath ) return null ;
371-
372- return {
373- name : novelName ,
374- cover : novelCover ,
375- path : deSlash ( novelPath . replace ( this . site , '' ) ) ,
376- } ;
377- } )
378- . get ( )
379- . filter ( novel => novel !== null ) ;
375+ return this . parseNovels ( loadedCheerio , '.novel-list.chapters .novel-item' ) ;
380376 }
381377
382378 filters = {
0 commit comments