Commit | Line | Data |
---|---|---|
08fe2e33 NR |
1 | package be.nikiroo.fanfix.supported; |
2 | ||
08fe2e33 NR |
3 | import java.io.IOException; |
4 | import java.io.InputStream; | |
5cf61f35 | 5 | import java.net.MalformedURLException; |
08fe2e33 | 6 | import java.net.URL; |
08fe2e33 | 7 | import java.util.ArrayList; |
793f1071 | 8 | import java.util.Date; |
08fe2e33 NR |
9 | import java.util.HashMap; |
10 | import java.util.List; | |
11 | import java.util.Map; | |
5cf61f35 | 12 | import java.util.Scanner; |
08fe2e33 | 13 | import java.util.Map.Entry; |
0ffa4754 | 14 | |
8831d290 | 15 | import org.json.JSONException; |
5cf61f35 | 16 | import org.json.JSONObject; |
0ffa4754 NR |
17 | import org.jsoup.helper.DataUtil; |
18 | import org.jsoup.nodes.Document; | |
19 | import org.jsoup.nodes.Element; | |
20 | import org.jsoup.nodes.Node; | |
08fe2e33 NR |
21 | |
22 | import be.nikiroo.fanfix.Instance; | |
08fe2e33 NR |
23 | import be.nikiroo.fanfix.bundles.StringId; |
24 | import be.nikiroo.fanfix.data.Chapter; | |
25 | import be.nikiroo.fanfix.data.MetaData; | |
9252c65e | 26 | import be.nikiroo.fanfix.data.Story; |
3b2b638f | 27 | import be.nikiroo.utils.Progress; |
08fe2e33 NR |
28 | import be.nikiroo.utils.StringUtils; |
29 | ||
30 | /** | |
31 | * This class is the base class used by the other support classes. It can be | |
32 | * used outside of this package, and have static method that you can use to get | |
33 | * access to the correct support class. | |
34 | * <p> | |
35 | * It will be used with 'resources' (usually web pages or files). | |
36 | * | |
37 | * @author niki | |
38 | */ | |
39 | public abstract class BasicSupport { | |
0ffa4754 NR |
40 | private Document sourceNode; |
41 | private URL source; | |
08fe2e33 | 42 | private SupportType type; |
22848428 | 43 | private URL currentReferer; // with only one 'r', as in 'HTTP'... |
8d59ce07 NR |
44 | |
45 | static protected BasicSupportHelper bsHelper = new BasicSupportHelper(); | |
46 | static protected BasicSupportImages bsImages = new BasicSupportImages(); | |
47 | static protected BasicSupportPara bsPara = new BasicSupportPara(new BasicSupportHelper(), new BasicSupportImages()); | |
08fe2e33 | 48 | |
08fe2e33 NR |
49 | /** |
50 | * Check if the given resource is supported by this {@link BasicSupport}. | |
51 | * | |
52 | * @param url | |
53 | * the resource to check for | |
54 | * | |
55 | * @return TRUE if it is | |
56 | */ | |
57 | protected abstract boolean supports(URL url); | |
58 | ||
59 | /** | |
60 | * Return TRUE if the support will return HTML encoded content values for | |
61 | * the chapters content. | |
62 | * | |
63 | * @return TRUE for HTML | |
64 | */ | |
65 | protected abstract boolean isHtml(); | |
66 | ||
0efd25e3 NR |
67 | /** |
68 | * Return the {@link MetaData} of this story. | |
69 | * | |
776ad3c6 | 70 | * @return the associated {@link MetaData}, never NULL |
0efd25e3 NR |
71 | * |
72 | * @throws IOException | |
73 | * in case of I/O error | |
74 | */ | |
0ffa4754 | 75 | protected abstract MetaData getMeta() throws IOException; |
08fe2e33 NR |
76 | |
77 | /** | |
78 | * Return the story description. | |
79 | * | |
08fe2e33 NR |
80 | * @return the description |
81 | * | |
82 | * @throws IOException | |
83 | * in case of I/O error | |
84 | */ | |
0ffa4754 | 85 | protected abstract String getDesc() throws IOException; |
08fe2e33 | 86 | |
08fe2e33 | 87 | /** |
826e4569 | 88 | * Return the list of chapters (name and resource). |
0ffa4754 NR |
89 | * <p> |
90 | * Can be NULL if this {@link BasicSupport} do no use chapters. | |
08fe2e33 | 91 | * |
ed08c171 NR |
92 | * @param pg |
93 | * the optional progress reporter | |
08fe2e33 | 94 | * |
0ffa4754 | 95 | * @return the chapters or NULL |
08fe2e33 NR |
96 | * |
97 | * @throws IOException | |
98 | * in case of I/O error | |
99 | */ | |
0ffa4754 NR |
100 | protected abstract List<Entry<String, URL>> getChapters(Progress pg) |
101 | throws IOException; | |
08fe2e33 NR |
102 | |
103 | /** | |
104 | * Return the content of the chapter (possibly HTML encoded, if | |
105 | * {@link BasicSupport#isHtml()} is TRUE). | |
106 | * | |
0ffa4754 NR |
107 | * @param chapUrl |
108 | * the chapter {@link URL} | |
08fe2e33 NR |
109 | * @param number |
110 | * the chapter number | |
ed08c171 NR |
111 | * @param pg |
112 | * the optional progress reporter | |
08fe2e33 NR |
113 | * |
114 | * @return the content | |
115 | * | |
116 | * @throws IOException | |
117 | * in case of I/O error | |
118 | */ | |
0ffa4754 NR |
119 | protected abstract String getChapterContent(URL chapUrl, int number, |
120 | Progress pg) throws IOException; | |
6e06d2cc | 121 | |
08fe2e33 NR |
122 | /** |
123 | * Return the list of cookies (values included) that must be used to | |
124 | * correctly fetch the resources. | |
125 | * <p> | |
126 | * You are expected to call the super method implementation if you override | |
127 | * it. | |
128 | * | |
129 | * @return the cookies | |
130 | */ | |
315f14ae | 131 | public Map<String, String> getCookies() { |
08fe2e33 NR |
132 | return new HashMap<String, String>(); |
133 | } | |
134 | ||
315f14ae NR |
135 | /** |
136 | * OAuth authorisation (aka, "bearer XXXXXXX"). | |
137 | * | |
138 | * @return the OAuth string | |
139 | */ | |
140 | public String getOAuth() { | |
141 | return null; | |
142 | } | |
143 | ||
a4143cd7 NR |
144 | /** |
145 | * Return the canonical form of the main {@link URL}. | |
146 | * | |
147 | * @param source | |
0ffa4754 NR |
148 | * the source {@link URL}, which can be NULL |
149 | * | |
150 | * @return the canonical form of this {@link URL} or NULL if the source was | |
151 | * NULL | |
152 | */ | |
153 | protected URL getCanonicalUrl(URL source) { | |
154 | return source; | |
155 | } | |
156 | ||
157 | /** | |
158 | * The main {@link Node} for this {@link Story}. | |
159 | * | |
160 | * @return the node | |
161 | */ | |
162 | protected Element getSourceNode() { | |
163 | return sourceNode; | |
164 | } | |
165 | ||
166 | /** | |
167 | * The main {@link URL} for this {@link Story}. | |
168 | * | |
169 | * @return the URL | |
170 | */ | |
171 | protected URL getSource() { | |
172 | return source; | |
173 | } | |
174 | ||
175 | /** | |
176 | * The current referer {@link URL} (only one 'r', as in 'HTML'...), i.e., | |
177 | * the current {@link URL} we work on. | |
178 | * | |
179 | * @return the referer | |
180 | */ | |
181 | public URL getCurrentReferer() { | |
182 | return currentReferer; | |
183 | } | |
184 | ||
185 | /** | |
186 | * The current referer {@link URL} (only one 'r', as in 'HTML'...), i.e., | |
187 | * the current {@link URL} we work on. | |
188 | * | |
189 | * @param currentReferer | |
190 | * the new referer | |
191 | */ | |
192 | protected void setCurrentReferer(URL currentReferer) { | |
193 | this.currentReferer = currentReferer; | |
194 | } | |
195 | ||
196 | /** | |
197 | * The support type. | |
198 | * | |
199 | * @return the type | |
200 | */ | |
201 | public SupportType getType() { | |
202 | return type; | |
203 | } | |
204 | ||
205 | /** | |
206 | * The support type. | |
207 | * | |
208 | * @param type | |
209 | * the new type | |
210 | */ | |
211 | protected void setType(SupportType type) { | |
212 | this.type = type; | |
213 | } | |
214 | ||
215 | /** | |
216 | * Open an input link that will be used for the support. | |
217 | * <p> | |
7445f856 NR |
218 | * Can return NULL, in which case you are supposed to work without a source |
219 | * node. | |
0ffa4754 NR |
220 | * |
221 | * @param source | |
a4143cd7 NR |
222 | * the source {@link URL} |
223 | * | |
0ffa4754 NR |
224 | * @return the {@link InputStream} |
225 | * | |
226 | * @throws IOException | |
227 | * in case of I/O error | |
228 | */ | |
229 | protected Document loadDocument(URL source) throws IOException { | |
230 | String url = getCanonicalUrl(source).toString(); | |
d66deb8d | 231 | return DataUtil.load(Instance.getInstance().getCache().open(source, this, false), "UTF-8", url.toString()); |
0ffa4754 NR |
232 | } |
233 | ||
234 | /** | |
235 | * Log into the support (can be a no-op depending upon the support). | |
a4143cd7 NR |
236 | * |
237 | * @throws IOException | |
238 | * in case of I/O error | |
239 | */ | |
0ffa4754 NR |
240 | protected void login() throws IOException { |
241 | } | |
242 | ||
0ffa4754 NR |
243 | /** |
244 | * Now that we have processed the {@link Story}, close the resources if any. | |
245 | */ | |
246 | protected void close() { | |
247 | setCurrentReferer(null); | |
a4143cd7 NR |
248 | } |
249 | ||
08fe2e33 NR |
250 | /** |
251 | * Process the given story resource into a partially filled {@link Story} | |
252 | * object containing the name and metadata. | |
253 | * | |
0efd25e3 NR |
254 | * @param getDesc |
255 | * retrieve the description of the story, or not | |
ed08c171 NR |
256 | * @param pg |
257 | * the optional progress reporter | |
08fe2e33 | 258 | * |
776ad3c6 | 259 | * @return the {@link Story}, never NULL |
08fe2e33 NR |
260 | * |
261 | * @throws IOException | |
262 | * in case of I/O error | |
263 | */ | |
0ffa4754 NR |
264 | protected Story processMeta(boolean getDesc, Progress pg) |
265 | throws IOException { | |
ed08c171 NR |
266 | if (pg == null) { |
267 | pg = new Progress(); | |
268 | } else { | |
269 | pg.setMinMax(0, 100); | |
270 | } | |
271 | ||
0ffa4754 | 272 | pg.setProgress(30); |
ed08c171 | 273 | |
0ffa4754 | 274 | Story story = new Story(); |
cfdaf605 | 275 | |
0ffa4754 | 276 | MetaData meta = getMeta(); |
cfdaf605 NR |
277 | meta.setType(getType().toString()); |
278 | meta.setSource(getType().getSourceName()); | |
ee8686f0 NR |
279 | if (meta.getPublisher() == null) { |
280 | meta.setPublisher(getType().getSourceName()); | |
281 | } | |
282 | ||
bff19b54 NR |
283 | if (meta.getCreationDate() == null |
284 | || meta.getCreationDate().trim().isEmpty()) { | |
285 | meta.setCreationDate(bsHelper | |
286 | .formatDate(StringUtils.fromTime(new Date().getTime()))); | |
0ffa4754 NR |
287 | } |
288 | story.setMeta(meta); | |
920af1c7 | 289 | pg.put("meta", meta); |
ed08c171 | 290 | |
0ffa4754 | 291 | pg.setProgress(50); |
08fe2e33 | 292 | |
0ffa4754 | 293 | if (meta.getCover() == null) { |
8d59ce07 | 294 | meta.setCover(bsHelper.getDefaultCover(meta.getSubject())); |
0ffa4754 | 295 | } |
08fe2e33 | 296 | |
0ffa4754 | 297 | pg.setProgress(60); |
a4143cd7 | 298 | |
0ffa4754 | 299 | if (getDesc) { |
d66deb8d NR |
300 | String descChapterName = Instance.getInstance().getTrans().getString(StringId.DESCRIPTION); |
301 | story.getMeta().setResume(bsPara.makeChapter(this, source, 0, descChapterName, // | |
302 | getDesc(), isHtml(), null)); | |
08fe2e33 | 303 | } |
0ffa4754 | 304 | |
fdc55375 | 305 | pg.done(); |
0ffa4754 | 306 | return story; |
08fe2e33 NR |
307 | } |
308 | ||
5cf61f35 NR |
309 | /** |
310 | * Utility method to convert the given URL into a JSON object. | |
311 | * <p> | |
312 | * Note that this method expects small JSON files (everything is copied into | |
313 | * memory at least twice). | |
314 | * | |
315 | * @param url | |
316 | * the URL to parse | |
317 | * @param stable | |
318 | * TRUE for more stable resources, FALSE when they often change | |
319 | * | |
320 | * @return the JSON object | |
321 | * | |
322 | * @throws IOException | |
323 | * in case of I/O error | |
324 | */ | |
325 | protected JSONObject getJson(String url, boolean stable) | |
326 | throws IOException { | |
327 | try { | |
328 | return getJson(new URL(url), stable); | |
329 | } catch (MalformedURLException e) { | |
330 | throw new IOException("Malformed URL: " + url, e); | |
331 | } | |
332 | } | |
333 | ||
334 | /** | |
335 | * Utility method to convert the given URL into a JSON object. | |
336 | * <p> | |
337 | * Note that this method expects small JSON files (everything is copied into | |
338 | * memory at least twice). | |
339 | * | |
340 | * @param url | |
341 | * the URL to parse | |
342 | * @param stable | |
343 | * TRUE for more stable resources, FALSE when they often change | |
344 | * | |
345 | * @return the JSON object | |
346 | * | |
347 | * @throws IOException | |
348 | * in case of I/O error | |
349 | */ | |
350 | protected JSONObject getJson(URL url, boolean stable) throws IOException { | |
351 | InputStream in = Instance.getInstance().getCache().open(url, null, | |
352 | stable); | |
353 | try { | |
354 | Scanner scan = new Scanner(in); | |
355 | scan.useDelimiter("\0"); | |
356 | try { | |
357 | return new JSONObject(scan.next()); | |
8831d290 NR |
358 | } catch (JSONException e) { |
359 | throw new IOException(e); | |
5cf61f35 NR |
360 | } finally { |
361 | scan.close(); | |
362 | } | |
363 | } finally { | |
364 | in.close(); | |
365 | } | |
366 | } | |
367 | ||
9005532f | 368 | /** |
826e4569 NR |
369 | * Process the given story resource into a fully filled {@link Story} |
370 | * object. | |
9005532f NR |
371 | * |
372 | * @param pg | |
373 | * the optional progress reporter | |
374 | * | |
375 | * @return the {@link Story}, never NULL | |
376 | * | |
377 | * @throws IOException | |
378 | * in case of I/O error | |
379 | */ | |
6569afb4 | 380 | // TODO: ADD final when BasicSupport_Deprecated is gone |
9005532f NR |
381 | public Story process(Progress pg) throws IOException { |
382 | setCurrentReferer(source); | |
383 | login(); | |
384 | sourceNode = loadDocument(source); | |
385 | ||
386 | try { | |
75a6a3ea NR |
387 | Story story = doProcess(pg); |
388 | ||
389 | // Check for "no chapters" stories | |
390 | if (story.getChapters().isEmpty() | |
391 | && story.getMeta().getResume() != null | |
392 | && !story.getMeta().getResume().getParagraphs().isEmpty()) { | |
393 | Chapter resume = story.getMeta().getResume(); | |
394 | resume.setName(""); | |
395 | resume.setNumber(1); | |
396 | story.getChapters().add(resume); | |
5d190880 | 397 | story.getMeta().setWords(resume.getWords()); |
75a6a3ea NR |
398 | |
399 | String descChapterName = Instance.getInstance().getTrans() | |
400 | .getString(StringId.DESCRIPTION); | |
401 | resume = new Chapter(0, descChapterName); | |
402 | story.getMeta().setResume(resume); | |
403 | } | |
404 | ||
405 | return story; | |
9005532f NR |
406 | } finally { |
407 | close(); | |
408 | } | |
409 | } | |
410 | ||
08fe2e33 | 411 | /** |
826e4569 NR |
412 | * Actual processing step, without the calls to other methods. |
413 | * <p> | |
414 | * Will convert the story resource into a fully filled {@link Story} object. | |
08fe2e33 | 415 | * |
92fb0719 NR |
416 | * @param pg |
417 | * the optional progress reporter | |
08fe2e33 | 418 | * |
776ad3c6 | 419 | * @return the {@link Story}, never NULL |
08fe2e33 NR |
420 | * |
421 | * @throws IOException | |
422 | * in case of I/O error | |
423 | */ | |
826e4569 | 424 | protected Story doProcess(Progress pg) throws IOException { |
92fb0719 NR |
425 | if (pg == null) { |
426 | pg = new Progress(); | |
427 | } else { | |
428 | pg.setMinMax(0, 100); | |
429 | } | |
3b039231 NR |
430 | |
431 | pg.setName("Initialising"); | |
92fb0719 | 432 | |
92fb0719 | 433 | pg.setProgress(1); |
9005532f NR |
434 | Progress pgMeta = new Progress(); |
435 | pg.addProgress(pgMeta, 10); | |
436 | Story story = processMeta(true, pgMeta); | |
68328e17 | 437 | pgMeta.done(); // 10% |
920af1c7 | 438 | pg.put("meta", story.getMeta()); |
ed08c171 | 439 | |
9005532f NR |
440 | Progress pgGetChapters = new Progress(); |
441 | pg.addProgress(pgGetChapters, 10); | |
442 | story.setChapters(new ArrayList<Chapter>()); | |
443 | List<Entry<String, URL>> chapters = getChapters(pgGetChapters); | |
68328e17 | 444 | pgGetChapters.done(); // 20% |
5d190880 | 445 | |
9005532f NR |
446 | if (chapters != null) { |
447 | Progress pgChaps = new Progress("Extracting chapters", 0, | |
448 | chapters.size() * 300); | |
449 | pg.addProgress(pgChaps, 80); | |
450 | ||
451 | long words = 0; | |
452 | int i = 1; | |
453 | for (Entry<String, URL> chap : chapters) { | |
454 | pgChaps.setName("Extracting chapter " + i); | |
455 | URL chapUrl = chap.getValue(); | |
456 | String chapName = chap.getKey(); | |
457 | if (chapUrl != null) { | |
458 | setCurrentReferer(chapUrl); | |
459 | } | |
460 | ||
461 | pgChaps.setProgress(i * 100); | |
462 | Progress pgGetChapterContent = new Progress(); | |
463 | Progress pgMakeChapter = new Progress(); | |
464 | pgChaps.addProgress(pgGetChapterContent, 100); | |
465 | pgChaps.addProgress(pgMakeChapter, 100); | |
466 | ||
467 | String content = getChapterContent(chapUrl, i, | |
468 | pgGetChapterContent); | |
68328e17 | 469 | pgGetChapterContent.done(); |
8d59ce07 | 470 | Chapter cc = bsPara.makeChapter(this, chapUrl, i, |
9005532f | 471 | chapName, content, isHtml(), pgMakeChapter); |
68328e17 | 472 | pgMakeChapter.done(); |
ed08c171 | 473 | |
9005532f NR |
474 | words += cc.getWords(); |
475 | story.getChapters().add(cc); | |
9005532f NR |
476 | |
477 | i++; | |
08fe2e33 | 478 | } |
5d190880 NR |
479 | |
480 | story.getMeta().setWords(words); | |
08fe2e33 | 481 | |
9005532f | 482 | pgChaps.setName("Extracting chapters"); |
fdc55375 | 483 | pgChaps.done(); |
08fe2e33 | 484 | } |
9005532f | 485 | |
68328e17 NR |
486 | pg.done(); |
487 | ||
9005532f | 488 | return story; |
08fe2e33 NR |
489 | } |
490 | ||
99d71bd7 NR |
491 | /** |
492 | * Create a chapter from the given data. | |
493 | * | |
494 | * @param source | |
495 | * the source URL for this content, which can be used to try and | |
496 | * find images if images are present in the format [image-url] | |
497 | * @param number | |
498 | * the chapter number (0 = description) | |
499 | * @param name | |
500 | * the chapter name | |
501 | * @param content | |
502 | * the content of the chapter | |
75a6a3ea NR |
503 | * |
504 | * @return the {@link Chapter}, never NULL | |
99d71bd7 NR |
505 | * |
506 | * @throws IOException | |
507 | * in case of I/O error | |
508 | */ | |
509 | public Chapter makeChapter(URL source, int number, String name, | |
510 | String content) throws IOException { | |
8d59ce07 | 511 | return bsPara.makeChapter(this, source, number, name, |
99d71bd7 NR |
512 | content, isHtml(), null); |
513 | } | |
514 | ||
08fe2e33 | 515 | /** |
0ffa4754 NR |
516 | * Return a {@link BasicSupport} implementation supporting the given |
517 | * resource if possible. | |
08fe2e33 | 518 | * |
0ffa4754 NR |
519 | * @param url |
520 | * the story resource | |
08fe2e33 | 521 | * |
0ffa4754 | 522 | * @return an implementation that supports it, or NULL |
08fe2e33 | 523 | */ |
0ffa4754 NR |
524 | public static BasicSupport getSupport(URL url) { |
525 | if (url == null) { | |
526 | return null; | |
527 | } | |
08fe2e33 | 528 | |
0ffa4754 NR |
529 | // TEXT and INFO_TEXT always support files (not URLs though) |
530 | for (SupportType type : SupportType.values()) { | |
531 | if (type != SupportType.TEXT && type != SupportType.INFO_TEXT) { | |
532 | BasicSupport support = getSupport(type, url); | |
533 | if (support != null && support.supports(url)) { | |
534 | return support; | |
535 | } | |
536 | } | |
537 | } | |
08fe2e33 | 538 | |
0ffa4754 NR |
539 | for (SupportType type : new SupportType[] { SupportType.INFO_TEXT, |
540 | SupportType.TEXT }) { | |
541 | BasicSupport support = getSupport(type, url); | |
542 | if (support != null && support.supports(url)) { | |
543 | return support; | |
544 | } | |
545 | } | |
546 | ||
547 | return null; | |
08fe2e33 NR |
548 | } |
549 | ||
550 | /** | |
0ffa4754 | 551 | * Return a {@link BasicSupport} implementation supporting the given type. |
08fe2e33 | 552 | * |
0ffa4754 | 553 | * @param type |
99d71bd7 | 554 | * the type, must not be NULL |
0ffa4754 NR |
555 | * @param url |
556 | * the {@link URL} to support (can be NULL to get an | |
727108fe NR |
557 | * "abstract support"; if not NULL, will be used as the source |
558 | * URL) | |
08fe2e33 | 559 | * |
0ffa4754 | 560 | * @return an implementation that supports it, or NULL |
08fe2e33 | 561 | */ |
0ffa4754 NR |
562 | public static BasicSupport getSupport(SupportType type, URL url) { |
563 | BasicSupport support = null; | |
08fe2e33 | 564 | |
08fe2e33 NR |
565 | switch (type) { |
566 | case EPUB: | |
0ffa4754 NR |
567 | support = new Epub(); |
568 | break; | |
08fe2e33 | 569 | case INFO_TEXT: |
0ffa4754 NR |
570 | support = new InfoText(); |
571 | break; | |
08fe2e33 | 572 | case FIMFICTION: |
315f14ae NR |
573 | try { |
574 | // Can fail if no client key or NO in options | |
0ffa4754 | 575 | support = new FimfictionApi(); |
315f14ae | 576 | } catch (IOException e) { |
0ffa4754 | 577 | support = new Fimfiction(); |
315f14ae | 578 | } |
0ffa4754 | 579 | break; |
08fe2e33 | 580 | case FANFICTION: |
0ffa4754 NR |
581 | support = new Fanfiction(); |
582 | break; | |
08fe2e33 | 583 | case TEXT: |
0ffa4754 NR |
584 | support = new Text(); |
585 | break; | |
413bcc29 NR |
586 | case MANGAHUB: |
587 | support = new MangaHub(); | |
0ffa4754 | 588 | break; |
08fe2e33 | 589 | case E621: |
0ffa4754 NR |
590 | support = new E621(); |
591 | break; | |
a4143cd7 | 592 | case YIFFSTAR: |
0ffa4754 NR |
593 | support = new YiffStar(); |
594 | break; | |
f0608ab1 | 595 | case E_HENTAI: |
0ffa4754 NR |
596 | support = new EHentai(); |
597 | break; | |
af1f506f NR |
598 | case MANGA_LEL: |
599 | support = new MangaLel(); | |
600 | break; | |
08fe2e33 | 601 | case CBZ: |
0ffa4754 NR |
602 | support = new Cbz(); |
603 | break; | |
373da363 | 604 | case HTML: |
0ffa4754 NR |
605 | support = new Html(); |
606 | break; | |
68686a37 NR |
607 | } |
608 | ||
0ffa4754 NR |
609 | if (support != null) { |
610 | support.setType(type); | |
611 | support.source = support.getCanonicalUrl(url); | |
315f14ae NR |
612 | } |
613 | ||
0ffa4754 | 614 | return support; |
315f14ae | 615 | } |
08fe2e33 | 616 | } |