1+ var currentPage = 0 ;
2+ var digits = 0 ;
3+ var imgURLs ;
4+
5+ const ROOT_URL = "https://catmanga.org/" ;
6+
7+ // Helper function. Builds the API URL since there are no ES6 template strings.
8+ function buildApiEndpoint ( buildID , mangaID , chapterNum ) {
9+ return ROOT_URL + "_next/data/" + buildID
10+ + "/series/" + mangaID + "/" + chapterNum + ".json" ;
11+ }
12+
13+ function listChapters ( query ) {
14+ // Get API data (stored in a <script> tag in the index html)
15+ // We can't use the API directly, since that means already
16+ // knowing the correct buildID.
17+ //
18+ // URL in format https://catmanga.org/_next/data/{BUILD-ID}/{ENDPOINT}.json
19+
20+ var indexHTML = mango . get ( ROOT_URL ) . body
21+ if ( ! indexHTML ) {
22+ mango . raise ( "Failed to get index." )
23+ }
24+
25+ var APINode = mango . css ( indexHTML , "script#__NEXT_DATA__" ) [ 0 ] ;
26+
27+ if ( ! APINode ) {
28+ mango . raise ( "Failed to get series data." )
29+ }
30+
31+ var indexJSONString = mango . text ( APINode ) ;
32+
33+ if ( ! indexJSONString ) {
34+ mango . raise ( "An error occured when searching." ) ;
35+ }
36+
37+ var indexJSON = JSON . parse ( indexJSONString ) ;
38+ var allSeries = indexJSON [ "props" ] [ "pageProps" ] [ "series" ] ;
39+
40+ // Search all manga on site to find something that matches query.
41+ // We have to do it manually since Catmanga has no searching.
42+ var manga ;
43+ allSeries . forEach ( function ( element ) {
44+ if ( query . toLowerCase ( ) == element [ "title" ] . toLowerCase ( ) ||
45+ query . toLowerCase ( ) == element [ "series_id" ] . toLowerCase ( ) ) {
46+ manga = element ;
47+ } else {
48+ element [ "alt_titles" ] . forEach ( function ( title ) {
49+ if ( title . toLowerCase ( ) == query . toLowerCase ( ) ) {
50+ manga = element ;
51+ }
52+ } ) ;
53+ }
54+ } ) ;
55+
56+ if ( ! manga ) {
57+ mango . raise ( "Failed to find manga with title: " + query ) ;
58+ }
59+
60+ var mangaTitle = manga [ "title" ] ;
61+
62+ if ( ! mangaTitle ) {
63+ mango . raise ( "Failed to get title of manga." ) ;
64+ }
65+
66+ var chapters = [ ] ;
67+ manga [ "chapters" ] . forEach ( function ( chapter ) {
68+ var seriesID = manga [ "series_id" ] ;
69+ var chapterNum = chapter [ "number" ] . toString ( ) . replace ( / \. / , "_" ) ;
70+ var chapterGroups = chapter [ "groups" ] . join ( ", " )
71+
72+ var slimObj = { } ;
73+ slimObj [ "id" ] = seriesID + "ch" + chapterNum
74+ slimObj [ "title" ] = "Chapter " + chapter [ "number" ] ;
75+ slimObj [ "groups" ] = chapterGroups ;
76+
77+ chapters . push ( slimObj ) ;
78+ } ) ;
79+
80+ return JSON . stringify ( {
81+ chapters : chapters . reverse ( ) , // Catmanga sorts chapters oldest -> newest
82+ title : mangaTitle
83+ } ) ;
84+ }
85+
86+ function selectChapter ( id ) {
87+ // Get buildID for chapter
88+ var mangaIDMatch = / ( .* ?) c h ( ( \d _ ? ) * ) $ / . exec ( id ) ;
89+ var mangaID = mangaIDMatch [ 1 ] ;
90+ var mangaChapterNumber = mangaIDMatch [ 2 ] . replace ( / \_ / , "." ) ; // Convert '_' back to '.
91+
92+ var chapterReaderURL = ROOT_URL + "series/" + mangaID + "/" + mangaChapterNumber ;
93+ var chapterHTML = mango . get ( chapterReaderURL ) . body ;
94+
95+ if ( ! chapterHTML ) {
96+ mango . raise ( "Failed to load chapter HTML." ) ;
97+ }
98+
99+ var APINode = mango . css ( chapterHTML , "script#__NEXT_DATA__" ) [ 0 ] ;
100+
101+ if ( ! APINode ) {
102+ mango . raise ( "Failed to get chapter buildID." )
103+ }
104+
105+ var buildIDJSONString = mango . text ( APINode ) ;
106+ var buildIDJSON = JSON . parse ( buildIDJSONString ) ;
107+
108+ var buildID = buildIDJSON [ "buildId" ] ;
109+
110+ // Get manga images from API
111+ var mangaURL = buildApiEndpoint ( buildID , mangaID , mangaChapterNumber ) ;
112+ var mangaJSONString = mango . get ( mangaURL ) . body ;
113+
114+ if ( ! mangaJSONString ) {
115+ mango . raise ( "Failed to load chapter." ) ;
116+ }
117+
118+ var mangaJSON = JSON . parse ( mangaJSONString ) ;
119+
120+ var chapterTitle = "Chapter " + mangaJSON [ "pageProps" ] [ "chapter" ] [ "number" ] ;
121+
122+ if ( ! chapterTitle ) {
123+ mango . raise ( "Failed to get chapter title." ) ;
124+ }
125+
126+ imgURLs = mangaJSON [ "pageProps" ] [ "pages" ] ;
127+ currentPage = 0 ;
128+ digits = Math . floor ( Math . log10 ( imgURLs . length ) ) + 1 ;
129+
130+ return JSON . stringify ( {
131+ title : chapterTitle ,
132+ pages : imgURLs . length
133+ } ) ;
134+ }
135+
136+ function nextPage ( ) {
137+ if ( currentPage >= imgURLs . length ) {
138+ return JSON . stringify ( { } ) ;
139+ }
140+
141+ var url = imgURLs [ currentPage ]
142+ var filename = pad ( currentPage , digits ) + '.' + / \. ( \w + ) $ / . exec ( url ) [ 0 ] ;
143+
144+ currentPage += 1 ;
145+ return JSON . stringify ( {
146+ url : url ,
147+ filename : filename ,
148+ headers : {
149+ 'referer' : "https://catmanga.org"
150+ }
151+ } ) ;
152+ }
153+
154+ // https://stackoverflow.com/a/10073788
155+ function pad ( n , width , z ) {
156+ z = z || '0' ;
157+ n = n + '' ;
158+ return n . length >= width ? n : new Array ( width - n . length + 1 ) . join ( z ) + n ;
159+ }
0 commit comments