1 package be
.nikiroo
.fanfix
.supported
;
3 import java
.io
.IOException
;
4 import java
.io
.InputStream
;
5 import java
.net
.MalformedURLException
;
7 import java
.util
.ArrayList
;
8 import java
.util
.Collections
;
10 import java
.util
.Map
.Entry
;
11 import java
.util
.Scanner
;
13 import be
.nikiroo
.fanfix
.Instance
;
14 import be
.nikiroo
.fanfix
.data
.MetaData
;
15 import be
.nikiroo
.utils
.Image
;
16 import be
.nikiroo
.utils
.Progress
;
17 import be
.nikiroo
.utils
.StringUtils
;
19 class MangaFox
extends BasicSupport
{
21 protected boolean isHtml() {
26 public String
getSourceName() {
31 protected MetaData
getMeta(URL source
, InputStream in
) throws IOException
{
32 MetaData meta
= new MetaData();
34 meta
.setTitle(getTitle(reset(in
)));
35 meta
.setAuthor(getAuthor(reset(in
)));
36 meta
.setDate(getDate(reset(in
)));
37 meta
.setTags(getTags(reset(in
)));
38 meta
.setSource(getSourceName());
39 meta
.setUrl(source
.toString());
40 meta
.setPublisher(getSourceName());
41 meta
.setUuid(source
.toString());
44 meta
.setSubject("manga");
45 meta
.setType(getType().toString());
46 meta
.setImageDocument(true);
47 meta
.setCover(getCover(reset(in
)));
52 private List
<String
> getTags(InputStream in
) {
53 List
<String
> tags
= new ArrayList
<String
>();
55 String line
= getLine(in
, "/genres/", 0);
57 line
= StringUtils
.unhtml(line
);
58 String
[] tab
= line
.split(",");
60 for (String tag
: tab
) {
69 private String
getTitle(InputStream in
) {
70 String line
= getLine(in
, " property=\"og:title\"", 0);
73 for (int i
= 0; i
< 3; i
++) {
74 pos
= line
.indexOf('"', pos
+ 1);
78 line
= line
.substring(pos
+ 1);
79 pos
= line
.indexOf('"');
81 return line
.substring(0, pos
);
89 private String
getAuthor(InputStream in
) {
90 List
<String
> authors
= new ArrayList
<String
>();
92 String line
= getLine(in
, "/author/", 0, false);
94 for (String ln
: StringUtils
.unhtml(line
).split(",")) {
95 if (ln
!= null && !ln
.trim().isEmpty()
96 && !authors
.contains(ln
.trim())) {
97 authors
.add(ln
.trim());
104 } catch (IOException e
) {
105 Instance
.getTraceHandler().error(e
);
108 line
= getLine(in
, "/artist/", 0, false);
110 for (String ln
: StringUtils
.unhtml(line
).split(",")) {
111 if (ln
!= null && !ln
.trim().isEmpty()
112 && !authors
.contains(ln
.trim())) {
113 authors
.add(ln
.trim());
118 if (authors
.isEmpty()) {
122 StringBuilder builder
= new StringBuilder();
123 for (String author
: authors
) {
124 if (builder
.length() > 0) {
125 builder
.append(", ");
128 builder
.append(author
);
131 return builder
.toString();
134 private String
getDate(InputStream in
) {
135 String line
= getLine(in
, "/released/", 0);
137 line
= StringUtils
.unhtml(line
);
145 protected String
getDesc(URL source
, InputStream in
) {
146 String line
= getLine(in
, " property=\"og:description\"", 0);
149 for (int i
= 0; i
< 3; i
++) {
150 pos
= line
.indexOf('"', pos
+ 1);
154 line
= line
.substring(pos
+ 1);
155 pos
= line
.indexOf('"');
157 return line
.substring(0, pos
);
165 private Image
getCover(InputStream in
) {
166 String line
= getLine(in
, " property=\"og:image\"", 0);
170 for (int i
= 0; i
< 3; i
++) {
171 pos
= line
.indexOf('"', pos
+ 1);
175 line
= line
.substring(pos
+ 1);
176 pos
= line
.indexOf('"');
178 cover
= line
.substring(0, pos
);
186 coverIn
= openEx(cover
);
188 return new Image(coverIn
);
192 } catch (IOException e
) {
200 protected List
<Entry
<String
, URL
>> getChapters(URL source
, InputStream in
,
202 List
<Entry
<String
, URL
>> urls
= new ArrayList
<Entry
<String
, URL
>>();
204 String volumeAt
= "<h3 class=\"volume\">";
205 String linkAt
= "href=\"http://mangafox.me/";
206 String endAt
= "<script type=\"text/javascript\">";
208 boolean started
= false;
210 @SuppressWarnings("resource")
211 Scanner scan
= new Scanner(in
, "UTF-8");
212 scan
.useDelimiter("\\n");
213 while (scan
.hasNext()) {
214 String line
= scan
.next();
216 if (started
&& line
.contains(endAt
)) {
218 } else if (!started
&& line
.contains(volumeAt
)) {
222 if (started
&& line
.contains(linkAt
)) {
223 // Chapter content url
225 int pos
= line
.indexOf("href=\"");
227 line
= line
.substring(pos
+ "href=\"".length());
228 pos
= line
.indexOf('\"');
230 url
= line
.substring(0, pos
);
236 if (scan
.hasNext()) {
237 name
= StringUtils
.unhtml(scan
.next()).trim();
238 // Remove the "new" tag if present
239 if (name
.endsWith("new")) {
240 name
= name
.substring(0, name
.length() - 3).trim();
245 final String key
= name
;
246 final URL value
= new URL(url
);
247 urls
.add(new Entry
<String
, URL
>() {
249 public URL
setValue(URL value
) {
254 public String
getKey() {
259 public URL
getValue() {
263 } catch (MalformedURLException e
) {
264 Instance
.getTraceHandler().error(e
);
270 pg
= new Progress(0, urls
.size());
272 pg
.setMinMax(0, urls
.size());
276 for (Entry
<String
, URL
> entry
: urls
) {
277 // to help with the retry and the originalUrl
278 refresh(entry
.getValue().toString());
282 // the chapters are in reversed order
283 Collections
.reverse(urls
);
289 protected String
getChapterContent(URL source
, InputStream in
, int number
,
294 // Since we have no idea how many images we have, we cycle from 0
295 // to max, then again, then again...
299 StringBuilder builder
= new StringBuilder();
300 String base
= getCurrentReferer().toString();
301 int pos
= base
.lastIndexOf('/');
302 base
= base
.substring(0, pos
+ 1); // including the '/' at the end
305 boolean close
= false;
307 String linkNextLine
= getLine(in
, "return enlarge()", 0);
310 } catch (IOException e
) {
311 Instance
.getTraceHandler().error(e
);
314 String linkImageLine
= getLine(in
, "return enlarge()", 1);
315 String linkNext
= null;
316 String linkImage
= null;
317 pos
= linkNextLine
.indexOf("href=\"");
319 linkNextLine
= linkNextLine
.substring(pos
+ "href=\"".length());
320 pos
= linkNextLine
.indexOf('\"');
322 linkNext
= linkNextLine
.substring(0, pos
);
325 pos
= linkImageLine
.indexOf("src=\"");
327 linkImageLine
= linkImageLine
328 .substring(pos
+ "src=\"".length());
329 pos
= linkImageLine
.indexOf('\"');
331 linkImage
= linkImageLine
.substring(0, pos
);
335 if (linkImage
!= null) {
337 // to help with the retry and the originalUrl, part 1
338 builder
.append(withoutQuery(linkImage
));
339 builder
.append("]<br/>");
342 // to help with the retry and the originalUrl, part 2
344 pg
.setProgress((i
++) % pg
.getMax());
349 } catch (IOException e
) {
350 Instance
.getTraceHandler().error(e
);
355 if (linkNext
!= null && !"javascript:void(0);".equals(linkNext
)) {
358 url
= new URL(base
+ linkNext
);
359 in
= openEx(base
+ linkNext
);
360 setCurrentReferer(url
);
361 pg
.setProgress((i
++) % pg
.getMax());
362 } catch (IOException e
) {
363 Instance
.getTraceHandler().error(
365 "Cannot get the next manga page which is: "
373 setCurrentReferer(source
);
374 return builder
.toString();
378 protected boolean supports(URL url
) {
379 return "mangafox.me".equals(url
.getHost())
380 || "www.mangafox.me".equals(url
.getHost());
384 * Refresh the {@link URL} by calling {@link MangaFox#openEx(String)}.
389 * @return TRUE if it was refreshed
391 private boolean refresh(String url
) {
395 } catch (Exception e
) {
401 * Open the URL through the cache, but: retry a second time after 100ms if
402 * it fails, remove the query part of the {@link URL} before saving it to
403 * the cache (so it can be recalled later).
408 * @return the resource
410 * @throws IOException
411 * in case of I/O error
413 private InputStream
openEx(String url
) throws IOException
{
415 return Instance
.getCache().open(new URL(url
), this, true,
417 } catch (Exception e
) {
421 } catch (InterruptedException ee
) {
424 return Instance
.getCache().open(new URL(url
), this, true,
430 * Return the same input {@link URL} but without the query part.
433 * the inpiut {@link URL} as a {@link String}
435 * @return the input {@link URL} without query
437 private URL
withoutQuery(String url
) {
440 // Remove the query from o (originalUrl), so it can be cached
443 o
= new URL(o
.getProtocol() + "://" + o
.getHost() + o
.getPath());
446 } catch (MalformedURLException e
) {