Main.java: new actins available
[nikiroo-utils.git] / src / be / nikiroo / fanfix / supported / MangaFox.java
1 package be.nikiroo.fanfix.supported;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.Collections;
9 import java.util.List;
10 import java.util.Map.Entry;
11 import java.util.Scanner;
12
13 import be.nikiroo.fanfix.Instance;
14 import be.nikiroo.utils.StringUtils;
15
16 class MangaFox extends BasicSupport {
17 @Override
18 protected boolean isHtml() {
19 return true;
20 }
21
22 @Override
23 public String getSourceName() {
24 return "MangaFox.met";
25 }
26
27 @Override
28 protected String getSubject(URL source, InputStream in) {
29 return "manga";
30 }
31
32 @Override
33 public boolean isImageDocument(URL source, InputStream in)
34 throws IOException {
35 return true;
36 }
37
38 @Override
39 protected List<String> getTags(URL source, InputStream in) {
40 List<String> tags = new ArrayList<String>();
41
42 String line = getLine(in, "/genres/", 0);
43 if (line != null) {
44 line = StringUtils.unhtml(line);
45 String[] tab = line.split(",");
46 if (tab != null) {
47 for (String tag : tab) {
48 tags.add(tag.trim());
49 }
50 }
51 }
52
53 return tags;
54 }
55
56 @Override
57 protected String getTitle(URL source, InputStream in) {
58 String line = getLine(in, " property=\"og:title\"", 0);
59 if (line != null) {
60 int pos = -1;
61 for (int i = 0; i < 3; i++) {
62 pos = line.indexOf('"', pos + 1);
63 }
64
65 if (pos >= 0) {
66 line = line.substring(pos + 1);
67 pos = line.indexOf('"');
68 if (pos >= 0) {
69 return line.substring(0, pos);
70 }
71 }
72 }
73
74 return null;
75 }
76
77 @Override
78 protected String getAuthor(URL source, InputStream in) {
79 List<String> authors = new ArrayList<String>();
80
81 String line = getLine(in, "/author/", 0, false);
82 if (line != null) {
83 for (String ln : StringUtils.unhtml(line).split(",")) {
84 if (ln != null && !ln.trim().isEmpty()
85 && !authors.contains(ln.trim())) {
86 authors.add(ln.trim());
87 }
88 }
89 }
90
91 try {
92 in.reset();
93 } catch (IOException e) {
94 Instance.syserr(e);
95 }
96
97 line = getLine(in, "/artist/", 0, false);
98 if (line != null) {
99 for (String ln : StringUtils.unhtml(line).split(",")) {
100 if (ln != null && !ln.trim().isEmpty()
101 && !authors.contains(ln.trim())) {
102 authors.add(ln.trim());
103 }
104 }
105 }
106
107 if (authors.isEmpty()) {
108 return null;
109 } else {
110 StringBuilder builder = new StringBuilder();
111 for (String author : authors) {
112 if (builder.length() > 0) {
113 builder.append(", ");
114 }
115
116 builder.append(author);
117 }
118
119 return builder.toString();
120 }
121 }
122
123 @Override
124 protected String getDate(URL source, InputStream in) {
125 String line = getLine(in, "/released/", 0);
126 if (line != null) {
127 line = StringUtils.unhtml(line);
128 return line.trim();
129 }
130
131 return null;
132 }
133
134 @Override
135 protected String getDesc(URL source, InputStream in) {
136 String line = getLine(in, " property=\"og:description\"", 0);
137 if (line != null) {
138 int pos = -1;
139 for (int i = 0; i < 3; i++) {
140 pos = line.indexOf('"', pos + 1);
141 }
142
143 if (pos >= 0) {
144 line = line.substring(pos + 1);
145 pos = line.indexOf('"');
146 if (pos >= 0) {
147 return line.substring(0, pos);
148 }
149 }
150 }
151
152 return null;
153 }
154
155 @Override
156 protected URL getCover(URL url, InputStream in) {
157 String line = getLine(in, " property=\"og:image\"", 0);
158 String cover = null;
159 if (line != null) {
160 int pos = -1;
161 for (int i = 0; i < 3; i++) {
162 pos = line.indexOf('"', pos + 1);
163 }
164
165 if (pos >= 0) {
166 line = line.substring(pos + 1);
167 pos = line.indexOf('"');
168 if (pos >= 0) {
169 cover = line.substring(0, pos);
170 }
171 }
172 }
173
174 if (cover != null) {
175 try {
176 return new URL(cover);
177 } catch (MalformedURLException e) {
178 Instance.syserr(e);
179 }
180 }
181
182 return null;
183 }
184
185 @Override
186 protected List<Entry<String, URL>> getChapters(URL source, InputStream in) {
187 List<Entry<String, URL>> urls = new ArrayList<Entry<String, URL>>();
188
189 String volumeAt = "<h3 class=\"volume\">";
190 String linkAt = "href=\"http://mangafox.me/";
191 String endAt = "<script type=\"text/javascript\">";
192
193 boolean started = false;
194
195 @SuppressWarnings("resource")
196 Scanner scan = new Scanner(in, "UTF-8");
197 scan.useDelimiter("\\n");
198 while (scan.hasNext()) {
199 String line = scan.next();
200
201 if (started && line.contains(endAt)) {
202 break;
203 } else if (!started && line.contains(volumeAt)) {
204 started = true;
205 }
206
207 if (started && line.contains(linkAt)) {
208 // Chapter content url
209 String url = null;
210 int pos = line.indexOf("href=\"");
211 if (pos >= 0) {
212 line = line.substring(pos + "href=\"".length());
213 pos = line.indexOf('\"');
214 if (pos >= 0) {
215 url = line.substring(0, pos);
216 }
217 }
218
219 // Chapter name
220 String name = null;
221 if (scan.hasNext()) {
222 name = StringUtils.unhtml(scan.next()).trim();
223 // Remove the "new" tag if present
224 if (name.endsWith("new")) {
225 name = name.substring(0, name.length() - 3).trim();
226 }
227 }
228
229 // to help with the retry and the originalUrl
230 refresh(url);
231
232 try {
233 final String key = name;
234 final URL value = new URL(url);
235 urls.add(new Entry<String, URL>() {
236 public URL setValue(URL value) {
237 return null;
238 }
239
240 public String getKey() {
241 return key;
242 }
243
244 public URL getValue() {
245 return value;
246 }
247 });
248 } catch (MalformedURLException e) {
249 Instance.syserr(e);
250 }
251 }
252 }
253
254 // the chapters are in reversed order
255 Collections.reverse(urls);
256
257 return urls;
258 }
259
260 @Override
261 protected String getChapterContent(URL source, InputStream in, int number) {
262 StringBuilder builder = new StringBuilder();
263 String base = getCurrentReferer().toString();
264 int pos = base.lastIndexOf('/');
265 base = base.substring(0, pos + 1); // including the '/' at the end
266
267 boolean close = false;
268 while (in != null) {
269 String linkNextLine = getLine(in, "return enlarge()", 0);
270 try {
271 in.reset();
272 } catch (IOException e) {
273 Instance.syserr(e);
274 }
275
276 String linkImageLine = getLine(in, "return enlarge()", 1);
277 String linkNext = null;
278 String linkImage = null;
279 pos = linkNextLine.indexOf("href=\"");
280 if (pos >= 0) {
281 linkNextLine = linkNextLine.substring(pos + "href=\"".length());
282 pos = linkNextLine.indexOf('\"');
283 if (pos >= 0) {
284 linkNext = linkNextLine.substring(0, pos);
285 }
286 }
287 pos = linkImageLine.indexOf("src=\"");
288 if (pos >= 0) {
289 linkImageLine = linkImageLine
290 .substring(pos + "src=\"".length());
291 pos = linkImageLine.indexOf('\"');
292 if (pos >= 0) {
293 linkImage = linkImageLine.substring(0, pos);
294 }
295 }
296
297 if (linkImage != null) {
298 builder.append("[");
299 // to help with the retry and the originalUrl, part 1
300 builder.append(withoutQuery(linkImage));
301 builder.append("]\n");
302 }
303
304 // to help with the retry and the originalUrl, part 2
305 refresh(linkImage);
306
307 if (close) {
308 try {
309 in.close();
310 } catch (IOException e) {
311 Instance.syserr(e);
312 }
313 }
314
315 in = null;
316 if (linkNext != null && !"javascript:void(0);".equals(linkNext)) {
317 URL url;
318 try {
319 url = new URL(base + linkNext);
320 in = openEx(base + linkNext);
321 setCurrentReferer(url);
322 } catch (IOException e) {
323 Instance.syserr(new IOException(
324 "Cannot get the next manga page which is: "
325 + linkNext, e));
326 }
327 }
328
329 close = true;
330 }
331
332 setCurrentReferer(source);
333 return builder.toString();
334 }
335
336 @Override
337 protected boolean supports(URL url) {
338 return "mangafox.me".equals(url.getHost())
339 || "www.mangafox.me".equals(url.getHost());
340 }
341
342 /**
343 * Refresh the {@link URL} by calling {@link MangaFox#openEx(String)}.
344 *
345 * @param url
346 * the URL to refresh
347 *
348 * @return TRUE if it was refreshed
349 */
350 private boolean refresh(String url) {
351 try {
352 openEx(url).close();
353 return true;
354 } catch (Exception e) {
355 return false;
356 }
357 }
358
359 /**
360 * Open the URL through the cache, but: retry a second time after 100ms if
361 * it fails, remove the query part of the {@link URL} before saving it to
362 * the cache (so it can be recalled later).
363 *
364 * @param url
365 * the {@link URL}
366 *
367 * @return the resource
368 *
369 * @throws IOException
370 * in case of I/O error
371 */
372 private InputStream openEx(String url) throws IOException {
373 try {
374 return Instance.getCache().open(new URL(url), this, true,
375 withoutQuery(url));
376 } catch (Exception e) {
377 // second chance
378 try {
379 Thread.sleep(100);
380 } catch (InterruptedException ee) {
381 }
382
383 return Instance.getCache().open(new URL(url), this, true,
384 withoutQuery(url));
385 }
386 }
387
388 /**
389 * Return the same input {@link URL} but without the query part.
390 *
391 * @param url
392 * the inpiut {@link URL} as a {@link String}
393 *
394 * @return the input {@link URL} without query
395 */
396 private URL withoutQuery(String url) {
397 URL o = null;
398 try {
399 // Remove the query from o (originalUrl), so it can be cached
400 // correctly
401 o = new URL(url);
402 o = new URL(o.getProtocol() + "://" + o.getHost() + o.getPath());
403
404 return o;
405 } catch (MalformedURLException e) {
406 return null;
407 }
408 }
409 }