1+ import {
2+ Chapter ,
3+ ChapterDetails ,
4+ HomeSection ,
5+ Manga ,
6+ MangaUpdates ,
7+ PagedResults ,
8+ Request ,
9+ SearchRequest ,
10+ Source ,
11+ SourceInfo ,
12+ TagSection ,
13+ } from "paperback-extensions-common"
14+ import { NovelCoolParser } from "./NovelCoolParser" ;
15+
16+ const BASE = "https://www.novelcool.com"
17+
18+ export const NovelCoolInfo :SourceInfo = {
19+ icon :"icon.png" ,
20+ version :"1.0.1" ,
21+ name :"NovelCool" ,
22+ author :"PythonCoderAS" ,
23+ authorWebsite :"https://github.com/PythonCoderAS" ,
24+ description :"Extension that pulls manga from NovelCool" ,
25+ language :"en" ,
26+ hentaiSource :false ,
27+ websiteBaseURL :BASE
28+ }
29+
30+ export class NovelCool extends Source {
31+
32+ private readonly parser :NovelCoolParser = new NovelCoolParser ( ) ;
33+
34+ getMangaShareUrl ( mangaId :string ) :string {
35+ return `${ BASE } /novel/${ mangaId } .html` ;
36+ }
37+
38+ async getTags ( ) :Promise < TagSection [ ] | null > {
39+ const options :Request = createRequestObject ( {
40+ url :`${ BASE } /search?name=awdasdsadsa` ,
41+ method :'GET'
42+ } ) ;
43+ let response = await this . requestManager . schedule ( options , 1 ) ;
44+ let $ = this . cheerio . load ( response . data ) ;
45+ return this . parser . parseGlobalTagList ( $ ) ;
46+ }
47+
48+ async getHomePageSections ( sectionCallback :( section :HomeSection ) => void ) :Promise < void > {
49+ const options :Request = createRequestObject ( {
50+ url :`${ BASE } ` ,
51+ method :'GET'
52+ } ) ;
53+ let response = await this . requestManager . schedule ( options , 1 ) ;
54+ let $ = this . cheerio . load ( response . data ) ;
55+ let carouselItems = this . parser . parseCarousel ( $ , BASE ) ;
56+ sectionCallback ( createHomeSection ( {
57+ id :"carousel" ,
58+ title :"Popular" ,
59+ items :carouselItems
60+ } ) )
61+ const sections = this . parser . parseHomepage ( $ , BASE ) ;
62+ for ( let i = 0 ; i < sections . length ; i ++ ) {
63+ const section = sections [ i ] ;
64+ sectionCallback ( createHomeSection ( {
65+ id :section . name . toLowerCase ( ) ,
66+ title :section . name ,
67+ items :section . items ,
68+ view_more :true
69+ } ) ) ;
70+ }
71+ }
72+
73+ async doGetWebsiteMangaDirectory ( page :number = 1 , end :number | null = null ) {
74+ const options :Request = createRequestObject ( {
75+ url :`${ BASE } /category/index_${ page } .html` ,
76+ method :'GET'
77+ } ) ;
78+ let response = await this . requestManager . schedule ( options , 1 ) ;
79+ let $ = this . cheerio . load ( response . data ) ;
80+ let results = this . parser . parseMangaListingPage ( $ , BASE ) ;
81+ if ( ! end ) {
82+ end = Number ( $ ( "div.dis-inline-block.para-h8" ) . first ( ) . text ( ) . trim ( ) )
83+ for ( let i = 2 ; i <= end ; i ++ ) {
84+ results = results . concat ( await this . doGetWebsiteMangaDirectory ( i , end ) )
85+ }
86+ }
87+ return results ;
88+ }
89+
90+ async getWebsiteMangaDirectory ( metadata :any ) :Promise < PagedResults > {
91+ return createPagedResults ( {
92+ results :await this . doGetWebsiteMangaDirectory ( )
93+ } ) ;
94+ }
95+
96+ async doGetPages ( chapterId :string , page :number = 1 , end :number | null = null ) :Promise < string [ ] > {
97+ const options :Request = createRequestObject ( {
98+ url :`${ BASE } /chapter/${ chapterId } -10-${ page } .html` ,
99+ method :'GET'
100+ } ) ;
101+ let response = await this . requestManager . schedule ( options , 1 ) ;
102+ let $ :CheerioStatic = this . cheerio . load ( response . data ) ;
103+ let pages :string [ ] = this . parser . parsePages ( $ ) ;
104+ if ( end === null ) {
105+ end = $ ( "select.sl-page option" ) . length
106+ for ( let i = 2 ; i < end ; i ++ ) {
107+ pages = pages . concat ( await this . doGetPages ( chapterId , page + 1 , end ) ) ;
108+ }
109+ }
110+ return pages ;
111+ }
112+
113+ async getChapterDetails ( mangaId :string , chapterId :string ) :Promise < ChapterDetails > {
114+ return createChapterDetails ( {
115+ id :chapterId ,
116+ mangaId :mangaId ,
117+ longStrip :false ,
118+ pages :await this . doGetPages ( chapterId )
119+ } ) ;
120+ }
121+
122+ async getChapters ( mangaId :string ) :Promise < Chapter [ ] > {
123+ const options :Request = createRequestObject ( {
124+ url :this . getMangaShareUrl ( mangaId ) ,
125+ method :'GET'
126+ } ) ;
127+ let response = await this . requestManager . schedule ( options , 1 ) ;
128+ let $ = this . cheerio . load ( response . data ) ;
129+ return this . parser . parseChapterList ( $ , mangaId , BASE , this . convertTime ) ;
130+ }
131+
132+ async getMangaDetails ( mangaId :string ) :Promise < Manga > {
133+ const options :Request = createRequestObject ( {
134+ url :this . getMangaShareUrl ( mangaId ) ,
135+ method :'GET'
136+ } ) ;
137+ let response = await this . requestManager . schedule ( options , 1 ) ;
138+ let $ = this . cheerio . load ( response . data ) ;
139+ return this . parser . parseManga ( $ , mangaId , BASE , this . convertTime ) ;
140+ }
141+
142+ async doSearchRequest ( url :string , page :number = 1 , end :number | null = null ) {
143+ const original_url = url ;
144+ url += `&page=${ page } .html`
145+ const options :Request = createRequestObject ( {
146+ url :url ,
147+ method :'GET'
148+ } ) ;
149+ let response = await this . requestManager . schedule ( options , 1 ) ;
150+ let $ = this . cheerio . load ( response . data ) ;
151+ if ( $ ( "div.search-nores-hint" ) . length !== 0 ) {
152+ return [ ] ;
153+ } else {
154+ let results = this . parser . parseMangaListingPage ( $ , BASE ) ;
155+ if ( ! end ) {
156+ end = Number ( $ ( "div.dis-inline-block.para-h8" ) . first ( ) . text ( ) . trim ( ) )
157+ for ( let i = 2 ; i <= end ; i ++ ) {
158+ results = results . concat ( await this . doSearchRequest ( original_url , i , end ) )
159+ }
160+ }
161+ return results ;
162+ }
163+ }
164+
165+ async searchRequest ( query :SearchRequest , metadata :any ) :Promise < PagedResults > {
166+ let url = `${ BASE } /search/?name_sel=contain`
167+ if ( query . title ) {
168+ url += `&name=${ query . title } ` ;
169+ }
170+ if ( query . author ) {
171+ url += `&author_sel=contain&author=${ query . author } ` ;
172+ }
173+ return createPagedResults ( {
174+ results :await this . doSearchRequest ( url )
175+ } ) ;
176+ }
177+
178+ async getViewMoreItems ( homepageSectionId :string , metadata :any ) :Promise < PagedResults > {
179+ const options :Request = createRequestObject ( {
180+ url :`${ BASE } /category/${ homepageSectionId } .html` ,
181+ method :'GET'
182+ } ) ;
183+ let response = await this . requestManager . schedule ( options , 1 ) ;
184+ let $ = this . cheerio . load ( response . data ) ;
185+ let results = this . parser . parseMangaListingPage ( $ , BASE ) ;
186+ return createPagedResults ( {
187+ results :results
188+ } ) ;
189+ }
190+
191+ async filterUpdatedManga ( mangaUpdatesFoundCallback :( updates :MangaUpdates ) => void , time :Date , ids :string [ ] ) :Promise < void > {
192+ mangaUpdatesFoundCallback ( createMangaUpdates ( {
193+ ids :ids
194+ } ) ) ;
195+ }
196+ }