11import { load as parseHTML } from 'cheerio' ;
22import { fetchApi } from '@libs/fetch' ;
33import { Plugin } from '@/types/plugin' ;
4+ import { NovelStatus } from '@libs/novelStatus' ;
5+ import { Filters , FilterTypes } from '@libs/filterInputs' ;
46import { defaultCover } from '@libs/defaultCover' ;
57import dayjs from 'dayjs' ;
68import { storage } from '@libs/storage' ;
7- import { NovelStatus } from '@libs/novelStatus' ;
89
910class Novelight implements Plugin . PagePlugin {
1011 id = 'novelight' ;
1112 name = 'Novelight' ;
12- version = '1.1.1 ' ;
13+ version = '1.1.2 ' ;
1314 icon = 'src/en/novelight/icon.png' ;
1415 site = 'https://novelight.net/' ;
1516
@@ -22,8 +23,39 @@ class Novelight implements Plugin.PagePlugin {
2223 } ,
2324 } ;
2425
25- async popularNovels ( page : number ) : Promise < Plugin . NovelItem [ ] > {
26- const url = `${ this . site } catalog/?ordering=popularity&page=${ page } ` ;
26+ async popularNovels (
27+ pageNo : number ,
28+ {
29+ showLatestNovels,
30+ filters,
31+ } : Plugin . PopularNovelsOptions < typeof this . filters > ,
32+ ) : Promise < Plugin . NovelItem [ ] > {
33+ let url = `${ this . site } catalog/` ;
34+ if ( showLatestNovels ) {
35+ url += `?ordering=-time_updated&page=${ pageNo } ` ;
36+ } else if ( filters ) {
37+ const params = new URLSearchParams ( ) ;
38+ for ( const country of filters . country . value ) {
39+ params . append ( 'country' , country ) ;
40+ }
41+ for ( const genre of filters . genres . value ) {
42+ params . append ( 'genre' , genre ) ;
43+ }
44+ for ( const translation of filters . translation . value ) {
45+ params . append ( 'translation' , translation ) ;
46+ }
47+ for ( const status of filters . status . value ) {
48+ params . append ( 'status' , status ) ;
49+ }
50+ for ( const novel_type of filters . novel_type . value ) {
51+ params . append ( 'type' , novel_type ) ;
52+ }
53+ params . append ( 'ordering' , filters . sort . value ) ;
54+ params . append ( 'page' , pageNo . toString ( ) ) ;
55+ url += `?${ params . toString ( ) } ` ;
56+ } else {
57+ url += `?&ordering=popularity&page=${ pageNo } ` ;
58+ }
2759
2860 const body = await fetchApi ( url ) . then ( r => r . text ( ) ) ;
2961
@@ -74,10 +106,18 @@ class Novelight implements Plugin.PagePlugin {
74106 for ( const child of info ) {
75107 const type = loadedCheerio ( child ) . find ( '.sub-header' ) . text ( ) . trim ( ) ;
76108 if ( type === 'Status' ) {
77- status = loadedCheerio ( child ) . find ( 'div.info' ) . text ( ) . trim ( ) ;
109+ status = loadedCheerio ( child )
110+ . find ( 'div.info' )
111+ . text ( )
112+ . trim ( )
113+ . toLowerCase ( ) ;
78114 }
79115 if ( type === 'Translation' ) {
80- translation = loadedCheerio ( child ) . find ( 'div.info' ) . text ( ) . trim ( ) ;
116+ translation = loadedCheerio ( child )
117+ . find ( 'div.info' )
118+ . text ( )
119+ . trim ( )
120+ . toLowerCase ( ) ;
81121 }
82122 if ( type === 'Author' ) {
83123 novel . author = loadedCheerio ( child ) . find ( 'div.info' ) . text ( ) . trim ( ) ;
@@ -110,18 +150,26 @@ class Novelight implements Plugin.PagePlugin {
110150 ?. match ( / ( [ 0 - 9 ] + ) / ) ?. [ 1 ] ?? '1' ,
111151 ) ;
112152
113- const chaptersRaw = await fetchApi (
114- `${ this . site } / book/ajax/chapter-pagination?csrfmiddlewaretoken=${ csrftoken } &book_id=${ bookId } &page=${ totalPages - parseInt ( page ) + 1 } ` ,
153+ const r = await fetchApi (
154+ `${ this . site } book/ajax/chapter-pagination?csrfmiddlewaretoken=${ csrftoken } &book_id=${ bookId } &page=${ totalPages - parseInt ( page ) + 1 } ` ,
115155 {
116156 headers : {
117157 'Host' : this . site . replace ( 'https://' , '' ) . replace ( '/' , '' ) ,
118158 'Referer' : this . site + novelPath ,
119159 'X-Requested-With' : 'XMLHttpRequest' ,
120160 } ,
121161 } ,
122- )
123- . then ( r => r . json ( ) )
124- . then ( r => r . html ) ;
162+ ) ;
163+
164+ let chaptersRaw ;
165+ try {
166+ chaptersRaw = await r . json ( ) ;
167+ chaptersRaw = chaptersRaw . html ;
168+ } catch ( error ) {
169+ console . error ( 'Error Parsing Response' ) ;
170+ console . error ( error ) ;
171+ throw new Error ( error ) ;
172+ }
125173
126174 const chapter : Plugin . ChapterItem [ ] = [ ] ;
127175
@@ -214,6 +262,106 @@ class Novelight implements Plugin.PagePlugin {
214262
215263 return novels ;
216264 }
265+
266+ filters = {
267+ sort : {
268+ label : 'Sort Results By' ,
269+ value : 'popularity' ,
270+ options : [
271+ { label : 'Title (A>Z)' , value : 'title' } ,
272+ { label : 'Publication Date' , value : '-time_created' } ,
273+ { label : 'Update Date (Newest)' , value : '-time_updated' } ,
274+ { label : 'Year Release' , value : '-year_of_release' } ,
275+ { label : 'Popularity' , value : 'popularity' } ,
276+ ] ,
277+ type : FilterTypes . Picker ,
278+ } ,
279+ translation : {
280+ label : 'Translation Status' ,
281+ value : [ ] ,
282+ options : [
283+ { label : 'Ongoing' , value : 'ongoing' } ,
284+ { label : 'Completed' , value : 'completed' } ,
285+ { label : 'Paused' , value : 'paused' } ,
286+ { label : 'Dropped' , value : 'dropped' } ,
287+ { label : 'None' , value : 'none' } ,
288+ ] ,
289+ type : FilterTypes . CheckboxGroup ,
290+ } ,
291+ status : {
292+ label : 'Status' ,
293+ value : [ ] ,
294+ options : [
295+ { label : 'Releasing' , value : 'releasing' } ,
296+ { label : 'Completed' , value : 'completed' } ,
297+ { label : 'Cancelled' , value : 'cancelled' } ,
298+ { label : 'Not yet released' , value : 'not+yet+released' } ,
299+ ] ,
300+ type : FilterTypes . CheckboxGroup ,
301+ } ,
302+ novel_type : {
303+ label : 'Type' ,
304+ value : [ ] ,
305+ options : [
306+ { label : 'Fan Fiction' , value : '4' } ,
307+ { label : 'Light Novel' , value : '1' } ,
308+ { label : 'Published Novel' , value : '2' } ,
309+ { label : 'Web Novel' , value : '3' } ,
310+ ] ,
311+ type : FilterTypes . CheckboxGroup ,
312+ } ,
313+ genres : {
314+ label : 'Genres' ,
315+ value : [ ] ,
316+ options : [
317+ { label : 'Thriller' , value : '1' } ,
318+ { label : 'Supernatural' , value : '2' } ,
319+ { label : 'Sports' , value : '3' } ,
320+ { label : 'Slice of Life' , value : '4' } ,
321+ { label : 'Sci-Fi' , value : '5' } ,
322+ { label : 'Romance' , value : '6' } ,
323+ { label : 'Psychological' , value : '7' } ,
324+ { label : 'Mystery' , value : '8' } ,
325+ { label : 'Mecha' , value : '9' } ,
326+ { label : 'Horror' , value : '10' } ,
327+ { label : 'Fantasy' , value : '11' } ,
328+ { label : 'Ecchi' , value : '12' } ,
329+ { label : 'Drama' , value : '13' } ,
330+ { label : 'Comedy' , value : '14' } ,
331+ { label : 'Adventure' , value : '15' } ,
332+ { label : 'Action' , value : '16' } ,
333+ { label : 'Adult' , value : '17' } ,
334+ { label : 'Isekai' , value : '18' } ,
335+ { label : 'Wuxia' , value : '19' } ,
336+ { label : 'Shounen' , value : '20' } ,
337+ { label : 'Yuri' , value : '21' } ,
338+ { label : 'Shoujo' , value : '22' } ,
339+ { label : 'Shoujo Ai' , value : '23' } ,
340+ { label : 'Harem' , value : '24' } ,
341+ { label : 'Seinen' , value : '25' } ,
342+ { label : 'Tragedy' , value : '26' } ,
343+ { label : 'Mature' , value : '27' } ,
344+ { label : 'Martial Arts' , value : '28' } ,
345+ { label : 'Gender Bender' , value : '29' } ,
346+ { label : 'School Life' , value : '30' } ,
347+ { label : 'Xuanhuan' , value : '31' } ,
348+ { label : 'Yaoi' , value : '32' } ,
349+ { label : 'Historical' , value : '33' } ,
350+ ] ,
351+ type : FilterTypes . CheckboxGroup ,
352+ } ,
353+ country : {
354+ label : 'Country' ,
355+ value : [ ] ,
356+ options : [
357+ { label : 'China' , value : '1' } ,
358+ { label : 'Japan' , value : '2' } ,
359+ { label : 'Korea' , value : '3' } ,
360+ { label : 'Other' , value : '6' } ,
361+ ] ,
362+ type : FilterTypes . CheckboxGroup ,
363+ } ,
364+ } satisfies Filters ;
217365}
218366
219367export default new Novelight ( ) ;
0 commit comments