11import {
2+ SourceManga ,
3+ Chapter ,
4+ ChapterDetails ,
5+ HomeSection ,
6+ SearchRequest ,
7+ PagedResults ,
8+ TagSection ,
9+ Request ,
10+ Response ,
11+ MangaProviding ,
12+ ChapterProviding ,
13+ SearchResultsProviding ,
14+ HomePageSectionsProviding ,
15+ HomeSectionType ,
16+ SourceIntents ,
217 ContentRating ,
318 SourceInfo ,
4- BadgeColor ,
5- SourceIntents
19+ BadgeColor
620} from '@paperback/types'
721
822import {
9- MangaReader
10- } from '../templates/mangareader/base'
23+ parseMangaDetails ,
24+ parseChapters ,
25+ parseChapterDetails ,
26+ parseMangaResults ,
27+ parseSearchTags
28+ } from './PhenixScansParser'
1129
30+ import * as cheerio from 'cheerio'
1231
13- const DOMAIN : string = 'https://phenixscans.fr'
32+ const DOMAIN : string = 'https://phenix-scans.com'
33+ export const API_DOMAIN : string = 'https://api.phenix-scans.com'
1434
1535export const PhenixScansInfo : SourceInfo = {
16- version : "1.1 " ,
36+ version : "2.0 " ,
1737 language : "FR" ,
1838 name : 'PhenixScans' ,
1939 icon : 'icon.png' ,
@@ -28,10 +48,180 @@ export const PhenixScansInfo: SourceInfo = {
2848 type : BadgeColor . GREY
2949 } ,
3050 ] ,
31- intents : SourceIntents . MANGA_CHAPTERS | SourceIntents . HOMEPAGE_SECTIONS | SourceIntents . CLOUDFLARE_BYPASS_REQUIRED
51+ intents : SourceIntents . MANGA_CHAPTERS | SourceIntents . HOMEPAGE_SECTIONS
3252}
3353
34- export class PhenixScans extends MangaReader {
35- base_url = DOMAIN
36- lang_code = PhenixScansInfo . language !
37- }
54+ export class PhenixScans implements MangaProviding , ChapterProviding , SearchResultsProviding , HomePageSectionsProviding {
55+
56+ requestManager = App . createRequestManager ( {
57+ requestsPerSecond : 10 ,
58+ requestTimeout : 20000 ,
59+ interceptor : {
60+ interceptRequest : async ( request : Request ) : Promise < Request > => {
61+ request . headers = {
62+ ...( request . headers ?? { } ) ,
63+ ...{
64+ 'referer' : `${ DOMAIN } /`
65+ }
66+ }
67+ return request
68+ } ,
69+ interceptResponse : async ( response : Response ) : Promise < Response > => {
70+ return response
71+ }
72+ }
73+ } )
74+
75+
76+ /////////////////////////////////
77+ ///// MANGA PROVIDING /////
78+ /////////////////////////////////
79+
80+
81+ getMangaShareUrl ( mangaId : string ) : string { return `${ DOMAIN } /manga/${ mangaId } ` }
82+
83+ async getMangaDetails ( mangaId : string ) : Promise < SourceManga > {
84+ const request = App . createRequest ( {
85+ url : `${ API_DOMAIN } /front/manga/${ mangaId } ` ,
86+ method : 'GET'
87+ } )
88+
89+ const response = await this . requestManager . schedule ( request , 1 )
90+ const json = JSON . parse ( response . data as string )
91+ return parseMangaDetails ( json , mangaId )
92+ }
93+
94+
95+ ///////////////////////////////////
96+ ///// CHAPTER PROVIDING /////
97+ ///////////////////////////////////
98+
99+
100+ async getChapters ( mangaId : string ) : Promise < Chapter [ ] > {
101+ const request = App . createRequest ( {
102+ url : `${ API_DOMAIN } /front/manga/${ mangaId } ` ,
103+ method : 'GET'
104+ } )
105+
106+ const response = await this . requestManager . schedule ( request , 1 )
107+ const json = JSON . parse ( response . data as string )
108+ return parseChapters ( json , mangaId )
109+ }
110+
111+ async getChapterDetails ( mangaId : string , chapterId : string ) : Promise < ChapterDetails > {
112+ const request = App . createRequest ( {
113+ url : `${ API_DOMAIN } /front/manga/${ mangaId } /chapter/${ chapterId } ` ,
114+ method : 'GET'
115+ } )
116+
117+ const response = await this . requestManager . schedule ( request , 1 )
118+ const json = JSON . parse ( response . data as string )
119+ return parseChapterDetails ( json , mangaId , chapterId )
120+ }
121+
122+
123+ /////////////////////////////////////////////
124+ ///// HOMEPAGE SECTIONS PROVIDING /////
125+ /////////////////////////////////////////////
126+
127+
128+ async getHomePageSections ( sectionCallback : ( section : HomeSection ) => void ) : Promise < void > {
129+ const sections = [
130+ App . createHomeSection ( { id : 'updatedAt' , title : "Dernières Sorties" , type : HomeSectionType . singleRowNormal , containsMoreItems : true } ) ,
131+ App . createHomeSection ( { id : 'rating' , title : "Populaire" , type : HomeSectionType . singleRowNormal , containsMoreItems : true } )
132+ ]
133+
134+ for ( const section of sections ) {
135+ const request = App . createRequest ( {
136+ url : `${ API_DOMAIN } /front/manga?sort=${ section . id } ` ,
137+ method : 'GET'
138+ } )
139+
140+ const response = await this . requestManager . schedule ( request , 1 )
141+ const json = JSON . parse ( response . data as string )
142+
143+ section . items = parseMangaResults ( json )
144+ sectionCallback ( section )
145+ }
146+ }
147+
148+ async getViewMoreItems ( homepageSectionId : string , metadata : any ) : Promise < PagedResults > {
149+ const page : number = metadata ?. page ?? 1
150+
151+ const request = App . createRequest ( {
152+ url : `${ API_DOMAIN } /front/manga?sort=${ homepageSectionId } &page=${ page } &limit=18` ,
153+ method : 'GET'
154+ } )
155+
156+ const response = await this . requestManager . schedule ( request , 1 )
157+ const json = JSON . parse ( response . data as string )
158+ const results = parseMangaResults ( json )
159+
160+ return App . createPagedResults ( {
161+ results,
162+ metadata : json . pagination . hasNextPage ? { page : page + 1 } : undefined
163+ } )
164+ }
165+
166+
167+ //////////////////////////////////////////
168+ ///// SEARCH RESULTS PROVIDING /////
169+ //////////////////////////////////////////
170+
171+
172+ async getSearchTags ?( ) : Promise < TagSection [ ] > {
173+ const request_genres = App . createRequest ( {
174+ url : `${ API_DOMAIN } /front/manga` ,
175+ method : 'GET'
176+ } )
177+ const request_filters = App . createRequest ( {
178+ url : `${ DOMAIN } /manga` ,
179+ method : 'GET'
180+ } )
181+
182+ const response_genres = await this . requestManager . schedule ( request_genres , 1 )
183+ const json = JSON . parse ( response_genres . data as string )
184+
185+ const response_filters = await this . requestManager . schedule ( request_filters , 1 )
186+ const $ = cheerio . load ( response_filters . data as string )
187+
188+ return parseSearchTags ( json , $ )
189+ }
190+
191+ async getSearchResults ( query : SearchRequest , metadata : any ) : Promise < PagedResults > {
192+ const page : number = metadata ?. page ?? 1
193+ const search = query . title ?. replace ( / / g, '+' ) . replace ( / [ ’ ' ´ ] / g, '%27' ) ?? ''
194+
195+ let url = ""
196+ if ( search ) {
197+ url = `${ API_DOMAIN } /front/manga/search?query=${ search } `
198+ } else {
199+ url = `${ API_DOMAIN } /front/manga?page=${ page } &limit=18`
200+
201+ if ( query . includedTags && query . includedTags ?. length != 0 ) {
202+ url += `&genre=${ query . includedTags . filter ( tag => tag . id . startsWith ( "genre=" ) ) . map ( tag => tag . id . replace ( "genre=" , "" ) ) . join ( "%2C" ) } `
203+ url += query . includedTags . find ( tag => tag . id . startsWith ( "&type=" ) ) ?. id ?? ""
204+ url += query . includedTags . find ( tag => tag . id . startsWith ( "&status=" ) ) ?. id ?? ""
205+ url += query . includedTags . find ( tag => tag . id . startsWith ( "&sort=" ) ) ?. id ?? ""
206+ }
207+ }
208+
209+ const request = App . createRequest ( {
210+ url,
211+ method : 'GET'
212+ } )
213+
214+ const response = await this . requestManager . schedule ( request , 1 )
215+ const json = JSON . parse ( response . data as string )
216+
217+ const results = parseMangaResults ( json )
218+ metadata = json . pagination . hasNextPage ? { page : page + 1 } : undefined
219+
220+ return App . createPagedResults ( {
221+ results,
222+ metadata
223+ } )
224+ }
225+
226+ }
227+
0 commit comments