1
+ import {
2
+ Chapter ,
3
+ ChapterDetails ,
4
+ HomeSection ,
5
+ Manga ,
6
+ MangaUpdates ,
7
+ PagedResults ,
8
+ Request , RequestHeaders , RequestManager ,
9
+ SearchRequest ,
10
+ Source ,
11
+ SourceInfo ,
12
+ TagSection ,
13
+ } from "paperback-extensions-common"
14
+ import { SenMangaParser } from "./SenMangaParser" ;
15
+
16
+ const BASE = "https://raw.senmanga.com"
17
+
18
+ export const SenMangaInfo : SourceInfo = {
19
+ icon : "icon.png" ,
20
+ version : "1.0.0" ,
21
+ name : "SenManga" ,
22
+ author : "PythonCoderAS" ,
23
+ authorWebsite : "https://github.com/PythonCoderAS" ,
24
+ description : "Extension that pulls manga from SenManga" ,
25
+ language : "jp" ,
26
+ hentaiSource : false ,
27
+ websiteBaseURL : BASE
28
+ }
29
+
30
+ export class SenManga extends Source {
31
+
32
+ private readonly parser : SenMangaParser = new SenMangaParser ( ) ;
33
+
34
+ private readonly header : RequestHeaders = {
35
+ "user-agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
36
+ }
37
+
38
+ readonly requestManager : RequestManager = createRequestManager ( {
39
+ requestTimeout : 15000 ,
40
+ requestsPerSecond : 4
41
+ } ) ;
42
+
43
+ globalRequestHeaders ( ) : RequestHeaders {
44
+ return this . header ;
45
+ }
46
+
47
+ getMangaShareUrl ( mangaId : string ) : string {
48
+ return `${ BASE } /${ mangaId } ` ;
49
+ }
50
+
51
+ async getTags ( ) : Promise < TagSection [ ] > {
52
+ const options : Request = createRequestObject ( {
53
+ url : `${ BASE } ` ,
54
+ method : 'GET' ,
55
+ headers : this . header
56
+ } ) ;
57
+ let response = await this . requestManager . schedule ( options , 1 ) ;
58
+ let $ = this . cheerio . load ( response . data ) ;
59
+ return this . parser . parseGlobalTagList ( $ ) ;
60
+ }
61
+
62
+ async getHomePageSections ( sectionCallback : ( section : HomeSection ) => void ) : Promise < void > {
63
+ const options : Request = createRequestObject ( {
64
+ url : `${ BASE } ` ,
65
+ method : 'GET' ,
66
+ headers : this . header
67
+ } ) ;
68
+ let response = await this . requestManager . schedule ( options , 1 ) ;
69
+ let $ = this . cheerio . load ( response . data ) ;
70
+ sectionCallback ( createHomeSection ( {
71
+ id : "last_update" ,
72
+ items : this . parser . parseLatestUpdates ( $ , BASE ) ,
73
+ title : "Latest Updates" ,
74
+ view_more : true
75
+ } ) ) ;
76
+ sectionCallback ( createHomeSection ( {
77
+ id : "popular" ,
78
+ items : this . parser . parseMostPopular ( $ , BASE ) ,
79
+ title : "Popular Manga" ,
80
+ view_more : true
81
+ } ) ) ;
82
+ sectionCallback ( createHomeSection ( {
83
+ id : "new_series" ,
84
+ items : this . parser . parseNewSeries ( $ , BASE ) ,
85
+ title : "New Series" ,
86
+ view_more : true
87
+ } ) ) ;
88
+ }
89
+
90
+ private async getPagedResults ( url : string , metadata : { page ?: number | null , [ key : string ] : any } ) {
91
+ if ( typeof metadata !== "object" ) {
92
+ metadata = { page : metadata }
93
+ }
94
+ let page = 1 ;
95
+ if ( metadata . page ) {
96
+ page = metadata . page ;
97
+ }
98
+ if ( page === null ) {
99
+ return createPagedResults ( { results : [ ] } ) ;
100
+ }
101
+ let pageAdder = `?page=${ page } ` ;
102
+ if ( url . includes ( "?" ) ) {
103
+ pageAdder = `&page=${ page } ` ;
104
+ }
105
+ const options : Request = createRequestObject ( {
106
+ url : url + pageAdder ,
107
+ method : 'GET' ,
108
+ headers : this . header
109
+ } ) ;
110
+ let response = await this . requestManager . schedule ( options , 1 ) ;
111
+ let $ = this . cheerio . load ( response . data ) ;
112
+ const data = this . parser . parseDirectory ( $ , BASE ) ;
113
+ let newPage : number | null = page + 1 ;
114
+ if ( data . max >= newPage ) {
115
+ newPage = null ;
116
+ }
117
+ metadata . page = newPage ;
118
+ return createPagedResults ( {
119
+ results : data . data
120
+ } ) ;
121
+ }
122
+
123
+ async getWebsiteMangaDirectory ( metadata : { page ?: number | null , [ key : string ] : any } ) : Promise < PagedResults > {
124
+ return await this . getPagedResults ( `${ BASE } /directory` , metadata )
125
+ }
126
+
127
+ async getChapterDetails ( mangaId : string , chapterId : string ) : Promise < ChapterDetails > {
128
+ const options : Request = createRequestObject ( {
129
+ url : this . getMangaShareUrl ( mangaId ) + "/" + chapterId ,
130
+ method : 'GET' ,
131
+ headers : this . header ,
132
+ cookies : [
133
+ createCookie ( {
134
+ name : "viewer" ,
135
+ value : "1" ,
136
+ domain : BASE ,
137
+ path : "/" ,
138
+ created : new Date ( ) ,
139
+ expires : new Date ( 2147483647 )
140
+ } )
141
+ ]
142
+ } ) ;
143
+ let response = await this . requestManager . schedule ( options , 1 ) ;
144
+ return createChapterDetails ( {
145
+ id : chapterId ,
146
+ mangaId : mangaId ,
147
+ longStrip : false ,
148
+ pages : await this . parser . parsePages ( response . data )
149
+ } ) ;
150
+ }
151
+
152
+ async getChapters ( mangaId : string ) : Promise < Chapter [ ] > {
153
+ const options : Request = createRequestObject ( {
154
+ url : this . getMangaShareUrl ( mangaId ) ,
155
+ method : 'GET' ,
156
+ headers : this . header
157
+ } ) ;
158
+ let response = await this . requestManager . schedule ( options , 1 ) ;
159
+ let $ = this . cheerio . load ( response . data ) ;
160
+ return this . parser . parseChapterList ( $ , mangaId , BASE ) ;
161
+ }
162
+
163
+ async getMangaDetails ( mangaId : string ) : Promise < Manga > {
164
+ const options : Request = createRequestObject ( {
165
+ url : this . getMangaShareUrl ( mangaId ) ,
166
+ method : 'GET' ,
167
+ headers : this . header
168
+ } ) ;
169
+ let response = await this . requestManager . schedule ( options , 1 ) ;
170
+ let $ = this . cheerio . load ( response . data ) ;
171
+ return this . parser . parseManga ( $ , mangaId ) ;
172
+ }
173
+
174
+ async searchRequest ( query : SearchRequest , metadata : any ) : Promise < PagedResults > {
175
+ return await this . getPagedResults ( `${ BASE } /search?s=${ query . title } ` , metadata ) ;
176
+ }
177
+
178
+ async getViewMoreItems ( homepageSectionId : string , metadata : any ) : Promise < PagedResults > {
179
+ return await this . getPagedResults ( `${ BASE } /directory/${ homepageSectionId } ` , metadata ) ;
180
+ }
181
+
182
+ async filterUpdatedManga ( mangaUpdatesFoundCallback : ( updates : MangaUpdates ) => void , time : Date , ids : string [ ] ) : Promise < void > {
183
+ const options : Request = createRequestObject ( {
184
+ url : `${ BASE } ` ,
185
+ method : 'GET' ,
186
+ headers : this . header
187
+ } ) ;
188
+ let response = await this . requestManager . schedule ( options , 1 ) ;
189
+ let $ = this . cheerio . load ( response . data ) ;
190
+ const idList : string [ ] = [ ] ;
191
+ let tiles = this . parser . parseLatestUpdates ( $ , BASE , true ) ;
192
+ for ( let i = 0 ; i < tiles . length ; i ++ ) {
193
+ const tile = tiles [ i ] ;
194
+ const parsedTime = this . parser . parseDateTime ( tile . primaryText ?. text || "" )
195
+ if ( parsedTime && parsedTime > time && ids . includes ( tile . id ) ) {
196
+ idList . push ( tile . id ) ;
197
+ }
198
+ }
199
+ mangaUpdatesFoundCallback ( createMangaUpdates ( {
200
+ ids : idList
201
+ } ) ) ;
202
+ }
203
+ }
0 commit comments