@@ -16,6 +16,11 @@ import {Alert} from 'react-native';
16
16
import { goBack } from '../../Navigation/NavigationService' ;
17
17
import APICaller from '../Controller/Interceptor' ;
18
18
import crashlytics from '@react-native-firebase/crashlytics' ;
19
+ import { ComicHostName } from '../../Utils/APIs' ;
20
+ import {
21
+ ComicBookPageClasses ,
22
+ ComicDetailPageClasses ,
23
+ } from '../../Screens/Comic/APIs/constance' ;
19
24
20
25
/**
21
26
* Action creator for handling watched data.
@@ -110,70 +115,65 @@ export const fetchComicDetails =
110
115
111
116
const response = await APICaller . get ( link ) ;
112
117
const html = response . data ;
113
- const $ = cheerio . load ( html ) ;
118
+ let $ = cheerio . load ( html ) ;
119
+
120
+ const hostkey = Object . keys ( ComicHostName ) . find ( key =>
121
+ link . includes ( key ) ,
122
+ ) ;
123
+ const config = ComicDetailPageClasses [ hostkey ] ;
124
+ if ( ! config ) throw new Error ( `No config found for source: ${ hostkey } ` ) ;
125
+
126
+ const detailsContainer = $ ( config . detailsContainer ) ;
127
+ const title = $ ( config . title ) . text ( ) . trim ( ) ;
114
128
115
- // Details Section
116
- const detailsContainer = $ ( '.list-container' ) ;
117
- const title = $ ( 'img.img-responsive' ) . attr ( 'alt' ) ?. trim ( ) ;
118
129
let imgSrc = detailsContainer
119
- . find ( '.boxed img.img-responsive' )
120
- . attr ( 'src' ) ;
130
+ . find ( config . imgSrc )
131
+ . attr ( config . getImageAttr ) ;
121
132
if ( imgSrc && imgSrc . startsWith ( '//' ) ) {
122
133
imgSrc = 'https:' + imgSrc ;
123
134
}
124
135
125
- // Build a details map from the <dl class="dl-horizontal">
126
136
const details = { } ;
127
- detailsContainer . find ( 'dl.dl-horizontal dt' ) . each ( ( i , el ) => {
137
+ detailsContainer . find ( config . detailsDL ) . each ( ( i , el ) => {
128
138
const key = $ ( el ) . text ( ) . trim ( ) . replace ( ':' , '' ) ;
129
139
const dd = $ ( el ) . next ( 'dd' ) ;
130
- if ( key === 'Tags' ) {
131
- const tags = [ ] ;
140
+
141
+ if ( key . toLowerCase ( ) === 'tags' || key . toLowerCase ( ) === 'genres' ) {
142
+ const list = [ ] ;
132
143
dd . find ( 'a' ) . each ( ( j , a ) => {
133
- tags . push ( $ ( a ) . text ( ) . trim ( ) ) ;
144
+ list . push ( $ ( a ) . text ( ) . trim ( ) ) ;
134
145
} ) ;
135
- details [ key ] = tags ;
136
- } else if ( key === 'Categories' ) {
137
- details [ key ] = dd . find ( 'a' ) . first ( ) . text ( ) . trim ( ) ;
138
- } else if ( key === 'Rating' ) {
139
- details [ key ] = dd . text ( ) . trim ( ) ;
146
+ details [ key ] = list ;
140
147
} else {
141
148
details [ key ] = dd . text ( ) . trim ( ) ;
142
149
}
143
150
} ) ;
144
151
145
- // Summary Section
146
- const summary = $ ( 'div.manga.well p' ) . text ( ) . trim ( ) ;
147
-
148
- // Chapters Section
149
- const chapters = [ ] ;
150
- $ ( 'ul.chapters li' ) . each ( ( i , el ) => {
151
- const chapterTitle = $ ( el ) . find ( 'h5.chapter-title-rtl a' ) . text ( ) . trim ( ) ;
152
- const chapterLink = $ ( el ) . find ( 'h5.chapter-title-rtl a' ) . attr ( 'href' ) ;
153
- const chapterDate = $ ( el )
154
- . find ( 'div.date-chapter-title-rtl' )
155
- . text ( )
156
- . trim ( ) ;
157
- chapters . push ( {
158
- title : chapterTitle ,
159
- link : chapterLink ,
160
- date : chapterDate ,
161
- } ) ;
162
- } ) ;
152
+ const summary = $ ( config . summary ) . text ( ) . trim ( ) ;
153
+ const chapters = await fetchChaptersWithPagination ( $ , config , link ) ;
154
+ const pagination = getChapterPagination ( $ , config ) ;
163
155
164
- // Create comic details object using the new API structure
165
156
const comicDetails = {
166
157
title,
167
158
imgSrc,
168
159
type : details [ 'Type' ] || null ,
169
160
status : details [ 'Status' ] || null ,
170
- releaseDate : details [ 'Date of release' ] || null ,
171
- categories : details [ 'Categories' ] || null ,
161
+ releaseDate :
162
+ details [ 'Release' ] ||
163
+ details [ 'Released' ] ||
164
+ details [ 'Date of release' ] ||
165
+ null ,
166
+ categories : details [ 'Category' ] || details [ 'Categories' ] || null ,
172
167
tags : details [ 'Tags' ] || [ ] ,
168
+ genres : details [ 'Genres' ] || [ ] ,
169
+ author : details [ 'Author' ] || null ,
170
+ alternativeName :
171
+ details [ 'Alternative' ] || details [ 'Alternative name' ] || null ,
173
172
views : details [ 'Views' ] || null ,
174
173
rating : details [ 'Rating' ] || null ,
175
174
summary,
176
175
chapters,
176
+ pagination,
177
177
link,
178
178
} ;
179
179
@@ -210,6 +210,54 @@ export const fetchComicDetails =
210
210
}
211
211
} ;
212
212
213
+ const fetchChaptersWithPagination = async ( $ , config , link ) => {
214
+ const chapters = [ ] ;
215
+ const visitedPages = new Set ( ) ;
216
+ let currentLink = link ;
217
+
218
+ while ( ! visitedPages . has ( currentLink ) ) {
219
+ visitedPages . add ( currentLink ) ;
220
+
221
+ $ ( config . chaptersList ) . each ( ( i , el ) => {
222
+ const chapterTitle = $ ( el ) . find ( config . chapterTitle ) . text ( ) . trim ( ) ;
223
+ const chapterLink = $ ( el ) . find ( config . chapterLink ) . attr ( 'href' ) ;
224
+ const chapterDate = $ ( el ) . find ( config . chapterDate ) . text ( ) . trim ( ) ;
225
+
226
+ if ( chapterTitle && chapterLink ) {
227
+ chapters . push ( {
228
+ title : chapterTitle ,
229
+ link : chapterLink ,
230
+ date : chapterDate ,
231
+ } ) ;
232
+ }
233
+ } ) ;
234
+
235
+ const nextPageLink = $ ( config . pagination )
236
+ . filter ( ( i , el ) => $ ( el ) . text ( ) . trim ( ) . toLowerCase ( ) === 'next' )
237
+ . attr ( 'href' ) ;
238
+
239
+ if ( ! nextPageLink ) break ;
240
+
241
+ const response = await APICaller . get ( nextPageLink ) ;
242
+ currentLink = nextPageLink ;
243
+ $ = cheerio . load ( response . data ) ;
244
+ }
245
+
246
+ return chapters ;
247
+ } ;
248
+
249
+ const getChapterPagination = ( $ , config ) => {
250
+ const pages = [ ] ;
251
+ $ ( config . pagination ) . each ( ( i , el ) => {
252
+ const text = $ ( el ) . text ( ) . trim ( ) ;
253
+ const href = $ ( el ) . attr ( 'href' ) ;
254
+ if ( text && href ) {
255
+ pages . push ( { text, link : href } ) ;
256
+ }
257
+ } ) ;
258
+ return pages ;
259
+ } ;
260
+
213
261
/**
214
262
* Fetches comic book data from a given URL and dispatches appropriate actions based on the result.
215
263
*
@@ -220,7 +268,18 @@ export const fetchComicDetails =
220
268
export const fetchComicBook =
221
269
( comicBook , setPageLink = null , isDownloadComic ) =>
222
270
async ( dispatch , getState ) => {
271
+ let newcomicBook = comicBook ;
272
+ // Dynamically get host config
273
+ const hostkey = Object . keys ( ComicHostName ) . find ( key =>
274
+ comicBook . includes ( key ) ,
275
+ ) ;
276
+
277
+ if ( hostkey == 'comichubfree' ) {
278
+ newcomicBook = `${ comicBook } /all` ;
279
+ }
280
+
223
281
if ( ! isDownloadComic ) dispatch ( fetchDataStart ( ) ) ;
282
+
224
283
try {
225
284
const Data = getState ( ) . data . dataByUrl [ comicBook ] ;
226
285
if ( Data ) {
@@ -232,40 +291,48 @@ export const fetchComicBook =
232
291
dispatch ( checkDownTime ( ) ) ;
233
292
return ;
234
293
}
235
- const response = await APICaller . get ( comicBook ) ;
294
+
295
+ const response = await APICaller . get ( newcomicBook ) ;
236
296
const html = response . data ;
237
297
const $ = cheerio . load ( html ) ;
238
298
239
- // New API: Extract chapter images using data-src attribute
240
- const imageContainer = $ ( '.imagecnt' ) ;
299
+ const config = ComicBookPageClasses [ hostkey ] ;
300
+ if ( ! config ) {
301
+ throw new Error ( `No chapter page config found for source: ${ hostkey } ` ) ;
302
+ }
303
+
304
+ const {
305
+ imageContainer,
306
+ imageSelector,
307
+ imageAttr,
308
+ titleSelector,
309
+ titleAttr,
310
+ } = config ;
311
+
312
+ const container = $ ( imageContainer ) ;
241
313
const imgSources = [ ] ;
242
- imageContainer
243
- . find ( 'img.img-responsive[data-src]' )
244
- . each ( ( index , element ) => {
245
- const src = $ ( element ) . attr ( 'data- src' ) ?. trim ( ) ;
246
- if ( src ) {
247
- imgSources . push ( src ) ;
248
- }
249
- } ) ;
314
+
315
+ container . find ( imageSelector ) . each ( ( i , el ) => {
316
+ const src = $ ( el ) . attr ( imageAttr ) ?. trim ( ) ;
317
+ if ( src ) imgSources . push ( src ) ;
318
+ } ) ;
319
+
320
+ const title =
321
+ container . find ( titleSelector ) . first ( ) . attr ( titleAttr ) ?. trim ( ) || '' ;
250
322
251
323
const data = {
252
324
images : imgSources ,
253
- // It is assumed the chapter title is embedded in the alt text of the first image.
254
- // Adjust the extraction as needed.
255
- title :
256
- imageContainer
257
- . find ( 'img.img-responsive' )
258
- . first ( )
259
- . attr ( 'alt' )
260
- ?. trim ( ) || '' ,
325
+ title,
261
326
lastReadPage : 0 ,
262
327
BookmarkPages : [ ] ,
263
- ComicDetailslink : '' ,
328
+ ComicDetailslink : '' , // set externally if needed
264
329
} ;
330
+ console . log ( 'imgSources' , data ) ;
265
331
266
332
if ( setPageLink ) {
267
333
setPageLink ( data . ComicDetailslink ) ;
268
334
}
335
+
269
336
dispatch ( fetchDataSuccess ( { url : comicBook , data} ) ) ;
270
337
if ( isDownloadComic ) return { url : comicBook , data} ;
271
338
} catch ( error ) {
@@ -467,24 +534,58 @@ export const getAdvancedSearchFilters = () => async dispatch => {
467
534
* @param {string } queryValue - The value to be appended to the search URL.
468
535
* @returns {Function } A thunk function that performs the async operation and returns the result.
469
536
*/
470
- export const searchComic = ( queryValue ) => async dispatch => {
471
- dispatch ( fetchDataStart ( ) ) ;
472
- const url = `https://readcomicsonline.ru/search?query=${ encodeURIComponent (
473
- queryValue ,
474
- ) } `;
475
- try {
476
- const response = await APICaller . get ( url ) ;
477
- dispatch ( fetchDataSuccess ( { url, data : response ?. data } ) ) ;
478
- dispatch ( StopLoading ( ) ) ;
479
- dispatch ( ClearError ( ) ) ;
480
- dispatch ( checkDownTime ( ) ) ;
481
- return response ?. data ;
482
- } catch ( error ) {
483
- crashlytics ( ) . recordError ( error ) ;
484
- console . log ( 'Error details:' , error ) ;
485
- console . error ( 'Error fetching search results:' , error ) ;
486
- dispatch ( fetchDataFailure ( error . message ) ) ;
487
- dispatch ( checkDownTime ( error ) ) ;
488
- return null ;
489
- }
490
- } ;
537
+ export const searchComic =
538
+ ( queryValue , source = 'readcomicsonline' ) =>
539
+ async dispatch => {
540
+ dispatch ( fetchDataStart ( ) ) ;
541
+
542
+ let url ;
543
+ const host =
544
+ source === 'readcomicsonline'
545
+ ? 'https://readcomicsonline.ru'
546
+ : 'https://comichubfree.com' ;
547
+
548
+ try {
549
+ if ( source === 'readcomicsonline' ) {
550
+ url = `${ host } /search?query=${ encodeURIComponent ( queryValue ) } ` ;
551
+ const response = await APICaller . get ( url ) ;
552
+ const suggestions = response ?. data ?. suggestions || [ ] ;
553
+
554
+ const formatted = suggestions . map ( item => ( {
555
+ title : item . value ,
556
+ data : item . data ,
557
+ link : `${ host } /comic/${ item . data } ` ,
558
+ } ) ) ;
559
+
560
+ dispatch ( fetchDataSuccess ( { url, data : formatted } ) ) ;
561
+ dispatch ( StopLoading ( ) ) ;
562
+ dispatch ( ClearError ( ) ) ;
563
+ dispatch ( checkDownTime ( ) ) ;
564
+ return formatted ;
565
+ } else if ( source === 'comichubfree' ) {
566
+ url = `${ host } /ajax/search?key=${ encodeURIComponent ( queryValue ) } ` ;
567
+ const response = await APICaller . get ( url ) ;
568
+ const json = response ?. data || [ ] ;
569
+
570
+ const formatted = json . map ( item => ( {
571
+ title : item . title ,
572
+ data : item . slug ,
573
+ link : `${ host } /comic/${ item . slug } ` ,
574
+ } ) ) ;
575
+
576
+ dispatch ( fetchDataSuccess ( { url, data : formatted } ) ) ;
577
+ dispatch ( StopLoading ( ) ) ;
578
+ dispatch ( ClearError ( ) ) ;
579
+ dispatch ( checkDownTime ( ) ) ;
580
+ return formatted ;
581
+ }
582
+
583
+ throw new Error ( `Unsupported source: ${ source } ` ) ;
584
+ } catch ( error ) {
585
+ crashlytics ( ) . recordError ( error ) ;
586
+ console . log ( 'Error details:' , error ) ;
587
+ dispatch ( fetchDataFailure ( error . message ) ) ;
588
+ dispatch ( checkDownTime ( error ) ) ;
589
+ return null ;
590
+ }
591
+ } ;
0 commit comments