1 package be
.nikiroo
.fanfix
.supported
;
3 import java
.awt
.image
.BufferedImage
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStream
;
6 import java
.net
.MalformedURLException
;
8 import java
.util
.ArrayList
;
9 import java
.util
.Collections
;
10 import java
.util
.List
;
11 import java
.util
.Map
.Entry
;
12 import java
.util
.Scanner
;
14 import be
.nikiroo
.fanfix
.Instance
;
15 import be
.nikiroo
.fanfix
.data
.MetaData
;
16 import be
.nikiroo
.utils
.ImageUtils
;
17 import be
.nikiroo
.utils
.Progress
;
18 import be
.nikiroo
.utils
.StringUtils
;
20 class MangaFox
extends BasicSupport
{
22 protected boolean isHtml() {
27 public String
getSourceName() {
32 protected MetaData
getMeta(URL source
, InputStream in
) throws IOException
{
33 MetaData meta
= new MetaData();
35 meta
.setTitle(getTitle(reset(in
)));
36 meta
.setAuthor(getAuthor(reset(in
)));
37 meta
.setDate(getDate(reset(in
)));
38 meta
.setTags(getTags(reset(in
)));
39 meta
.setSource(getSourceName());
40 meta
.setUrl(source
.toString());
41 meta
.setPublisher(getSourceName());
42 meta
.setUuid(source
.toString());
45 meta
.setSubject("manga");
46 meta
.setType(getType().toString());
47 meta
.setImageDocument(true);
48 meta
.setCover(getCover(reset(in
)));
53 private List
<String
> getTags(InputStream in
) {
54 List
<String
> tags
= new ArrayList
<String
>();
56 String line
= getLine(in
, "/genres/", 0);
58 line
= StringUtils
.unhtml(line
);
59 String
[] tab
= line
.split(",");
61 for (String tag
: tab
) {
70 private String
getTitle(InputStream in
) {
71 String line
= getLine(in
, " property=\"og:title\"", 0);
74 for (int i
= 0; i
< 3; i
++) {
75 pos
= line
.indexOf('"', pos
+ 1);
79 line
= line
.substring(pos
+ 1);
80 pos
= line
.indexOf('"');
82 return line
.substring(0, pos
);
90 private String
getAuthor(InputStream in
) {
91 List
<String
> authors
= new ArrayList
<String
>();
93 String line
= getLine(in
, "/author/", 0, false);
95 for (String ln
: StringUtils
.unhtml(line
).split(",")) {
96 if (ln
!= null && !ln
.trim().isEmpty()
97 && !authors
.contains(ln
.trim())) {
98 authors
.add(ln
.trim());
105 } catch (IOException e
) {
109 line
= getLine(in
, "/artist/", 0, false);
111 for (String ln
: StringUtils
.unhtml(line
).split(",")) {
112 if (ln
!= null && !ln
.trim().isEmpty()
113 && !authors
.contains(ln
.trim())) {
114 authors
.add(ln
.trim());
119 if (authors
.isEmpty()) {
123 StringBuilder builder
= new StringBuilder();
124 for (String author
: authors
) {
125 if (builder
.length() > 0) {
126 builder
.append(", ");
129 builder
.append(author
);
132 return builder
.toString();
135 private String
getDate(InputStream in
) {
136 String line
= getLine(in
, "/released/", 0);
138 line
= StringUtils
.unhtml(line
);
146 protected String
getDesc(URL source
, InputStream in
) {
147 String line
= getLine(in
, " property=\"og:description\"", 0);
150 for (int i
= 0; i
< 3; i
++) {
151 pos
= line
.indexOf('"', pos
+ 1);
155 line
= line
.substring(pos
+ 1);
156 pos
= line
.indexOf('"');
158 return line
.substring(0, pos
);
166 private BufferedImage
getCover(InputStream in
) {
167 String line
= getLine(in
, " property=\"og:image\"", 0);
171 for (int i
= 0; i
< 3; i
++) {
172 pos
= line
.indexOf('"', pos
+ 1);
176 line
= line
.substring(pos
+ 1);
177 pos
= line
.indexOf('"');
179 cover
= line
.substring(0, pos
);
187 coverIn
= openEx(cover
);
189 return ImageUtils
.fromStream(coverIn
);
193 } catch (IOException e
) {
201 protected List
<Entry
<String
, URL
>> getChapters(URL source
, InputStream in
,
203 List
<Entry
<String
, URL
>> urls
= new ArrayList
<Entry
<String
, URL
>>();
205 String volumeAt
= "<h3 class=\"volume\">";
206 String linkAt
= "href=\"http://mangafox.me/";
207 String endAt
= "<script type=\"text/javascript\">";
209 boolean started
= false;
211 @SuppressWarnings("resource")
212 Scanner scan
= new Scanner(in
, "UTF-8");
213 scan
.useDelimiter("\\n");
214 while (scan
.hasNext()) {
215 String line
= scan
.next();
217 if (started
&& line
.contains(endAt
)) {
219 } else if (!started
&& line
.contains(volumeAt
)) {
223 if (started
&& line
.contains(linkAt
)) {
224 // Chapter content url
226 int pos
= line
.indexOf("href=\"");
228 line
= line
.substring(pos
+ "href=\"".length());
229 pos
= line
.indexOf('\"');
231 url
= line
.substring(0, pos
);
237 if (scan
.hasNext()) {
238 name
= StringUtils
.unhtml(scan
.next()).trim();
239 // Remove the "new" tag if present
240 if (name
.endsWith("new")) {
241 name
= name
.substring(0, name
.length() - 3).trim();
246 final String key
= name
;
247 final URL value
= new URL(url
);
248 urls
.add(new Entry
<String
, URL
>() {
250 public URL
setValue(URL value
) {
255 public String
getKey() {
260 public URL
getValue() {
264 } catch (MalformedURLException e
) {
271 pg
= new Progress(0, urls
.size());
273 pg
.setMinMax(0, urls
.size());
277 for (Entry
<String
, URL
> entry
: urls
) {
278 // to help with the retry and the originalUrl
279 refresh(entry
.getValue().toString());
283 // the chapters are in reversed order
284 Collections
.reverse(urls
);
290 protected String
getChapterContent(URL source
, InputStream in
, int number
,
295 // Since we have no idea how many images we have, we cycle from 0
296 // to max, then again, then again...
300 StringBuilder builder
= new StringBuilder();
301 String base
= getCurrentReferer().toString();
302 int pos
= base
.lastIndexOf('/');
303 base
= base
.substring(0, pos
+ 1); // including the '/' at the end
306 boolean close
= false;
308 String linkNextLine
= getLine(in
, "return enlarge()", 0);
311 } catch (IOException e
) {
315 String linkImageLine
= getLine(in
, "return enlarge()", 1);
316 String linkNext
= null;
317 String linkImage
= null;
318 pos
= linkNextLine
.indexOf("href=\"");
320 linkNextLine
= linkNextLine
.substring(pos
+ "href=\"".length());
321 pos
= linkNextLine
.indexOf('\"');
323 linkNext
= linkNextLine
.substring(0, pos
);
326 pos
= linkImageLine
.indexOf("src=\"");
328 linkImageLine
= linkImageLine
329 .substring(pos
+ "src=\"".length());
330 pos
= linkImageLine
.indexOf('\"');
332 linkImage
= linkImageLine
.substring(0, pos
);
336 if (linkImage
!= null) {
338 // to help with the retry and the originalUrl, part 1
339 builder
.append(withoutQuery(linkImage
));
340 builder
.append("]<br/>");
343 // to help with the retry and the originalUrl, part 2
345 pg
.setProgress((i
++) % pg
.getMax());
350 } catch (IOException e
) {
356 if (linkNext
!= null && !"javascript:void(0);".equals(linkNext
)) {
359 url
= new URL(base
+ linkNext
);
360 in
= openEx(base
+ linkNext
);
361 setCurrentReferer(url
);
362 pg
.setProgress((i
++) % pg
.getMax());
363 } catch (IOException e
) {
364 Instance
.syserr(new IOException(
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
) {