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 javax
.imageio
.ImageIO
;
16 import be
.nikiroo
.fanfix
.Instance
;
17 import be
.nikiroo
.fanfix
.data
.MetaData
;
18 import be
.nikiroo
.utils
.IOUtils
;
19 import be
.nikiroo
.utils
.StringUtils
;
21 class MangaFox
extends BasicSupport
{
23 protected boolean isHtml() {
28 public String
getSourceName() {
33 protected MetaData
getMeta(URL source
, InputStream in
) throws IOException
{
34 MetaData meta
= new MetaData();
36 meta
.setTitle(getTitle(reset(in
)));
37 meta
.setAuthor(getAuthor(reset(in
)));
38 meta
.setDate(getDate(reset(in
)));
39 meta
.setTags(getTags(reset(in
)));
40 meta
.setSource(getSourceName());
41 meta
.setUrl(source
.toString());
42 meta
.setPublisher(getSourceName());
43 meta
.setUuid(source
.toString());
46 meta
.setSubject("manga");
47 meta
.setType(getType().toString());
48 meta
.setImageDocument(true);
49 meta
.setCover(getCover(reset(in
)));
54 private List
<String
> getTags(InputStream in
) {
55 List
<String
> tags
= new ArrayList
<String
>();
57 String line
= getLine(in
, "/genres/", 0);
59 line
= StringUtils
.unhtml(line
);
60 String
[] tab
= line
.split(",");
62 for (String tag
: tab
) {
71 private String
getTitle(InputStream in
) {
72 String line
= getLine(in
, " property=\"og:title\"", 0);
75 for (int i
= 0; i
< 3; i
++) {
76 pos
= line
.indexOf('"', pos
+ 1);
80 line
= line
.substring(pos
+ 1);
81 pos
= line
.indexOf('"');
83 return line
.substring(0, pos
);
91 private String
getAuthor(InputStream in
) {
92 List
<String
> authors
= new ArrayList
<String
>();
94 String line
= getLine(in
, "/author/", 0, false);
96 for (String ln
: StringUtils
.unhtml(line
).split(",")) {
97 if (ln
!= null && !ln
.trim().isEmpty()
98 && !authors
.contains(ln
.trim())) {
99 authors
.add(ln
.trim());
106 } catch (IOException e
) {
110 line
= getLine(in
, "/artist/", 0, false);
112 for (String ln
: StringUtils
.unhtml(line
).split(",")) {
113 if (ln
!= null && !ln
.trim().isEmpty()
114 && !authors
.contains(ln
.trim())) {
115 authors
.add(ln
.trim());
120 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();
136 private String
getDate(InputStream in
) {
137 String line
= getLine(in
, "/released/", 0);
139 line
= StringUtils
.unhtml(line
);
147 protected String
getDesc(URL source
, InputStream in
) {
148 String line
= getLine(in
, " property=\"og:description\"", 0);
151 for (int i
= 0; i
< 3; i
++) {
152 pos
= line
.indexOf('"', pos
+ 1);
156 line
= line
.substring(pos
+ 1);
157 pos
= line
.indexOf('"');
159 return line
.substring(0, pos
);
167 private BufferedImage
getCover(InputStream in
) {
168 String line
= getLine(in
, " property=\"og:image\"", 0);
172 for (int i
= 0; i
< 3; i
++) {
173 pos
= line
.indexOf('"', pos
+ 1);
177 line
= line
.substring(pos
+ 1);
178 pos
= line
.indexOf('"');
180 cover
= line
.substring(0, pos
);
188 coverIn
= openEx(cover
);
190 return IOUtils
.toImage(coverIn
);
194 } catch (IOException e
) {
202 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();
245 // to help with the retry and the originalUrl
249 final String key
= name
;
250 final URL value
= new URL(url
);
251 urls
.add(new Entry
<String
, URL
>() {
252 public URL
setValue(URL value
) {
256 public String
getKey() {
260 public URL
getValue() {
264 } catch (MalformedURLException e
) {
270 // the chapters are in reversed order
271 Collections
.reverse(urls
);
277 protected String
getChapterContent(URL source
, InputStream in
, int number
) {
278 StringBuilder builder
= new StringBuilder();
279 String base
= getCurrentReferer().toString();
280 int pos
= base
.lastIndexOf('/');
281 base
= base
.substring(0, pos
+ 1); // including the '/' at the end
283 boolean close
= false;
285 String linkNextLine
= getLine(in
, "return enlarge()", 0);
288 } catch (IOException e
) {
292 String linkImageLine
= getLine(in
, "return enlarge()", 1);
293 String linkNext
= null;
294 String linkImage
= null;
295 pos
= linkNextLine
.indexOf("href=\"");
297 linkNextLine
= linkNextLine
.substring(pos
+ "href=\"".length());
298 pos
= linkNextLine
.indexOf('\"');
300 linkNext
= linkNextLine
.substring(0, pos
);
303 pos
= linkImageLine
.indexOf("src=\"");
305 linkImageLine
= linkImageLine
306 .substring(pos
+ "src=\"".length());
307 pos
= linkImageLine
.indexOf('\"');
309 linkImage
= linkImageLine
.substring(0, pos
);
313 if (linkImage
!= null) {
315 // to help with the retry and the originalUrl, part 1
316 builder
.append(withoutQuery(linkImage
));
317 builder
.append("]\n");
320 // to help with the retry and the originalUrl, part 2
326 } catch (IOException e
) {
332 if (linkNext
!= null && !"javascript:void(0);".equals(linkNext
)) {
335 url
= new URL(base
+ linkNext
);
336 in
= openEx(base
+ linkNext
);
337 setCurrentReferer(url
);
338 } catch (IOException e
) {
339 Instance
.syserr(new IOException(
340 "Cannot get the next manga page which is: "
348 setCurrentReferer(source
);
349 return builder
.toString();
353 protected boolean supports(URL url
) {
354 return "mangafox.me".equals(url
.getHost())
355 || "www.mangafox.me".equals(url
.getHost());
359 * Refresh the {@link URL} by calling {@link MangaFox#openEx(String)}.
364 * @return TRUE if it was refreshed
366 private boolean refresh(String url
) {
370 } catch (Exception e
) {
376 * Open the URL through the cache, but: retry a second time after 100ms if
377 * it fails, remove the query part of the {@link URL} before saving it to
378 * the cache (so it can be recalled later).
383 * @return the resource
385 * @throws IOException
386 * in case of I/O error
388 private InputStream
openEx(String url
) throws IOException
{
390 return Instance
.getCache().open(new URL(url
), this, true,
392 } catch (Exception e
) {
396 } catch (InterruptedException ee
) {
399 return Instance
.getCache().open(new URL(url
), this, true,
405 * Return the same input {@link URL} but without the query part.
408 * the inpiut {@link URL} as a {@link String}
410 * @return the input {@link URL} without query
412 private URL
withoutQuery(String url
) {
415 // Remove the query from o (originalUrl), so it can be cached
418 o
= new URL(o
.getProtocol() + "://" + o
.getHost() + o
.getPath());
421 } catch (MalformedURLException e
) {