X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Fsupported%2FBasicSupport.java;h=ff9ecaf9be3cc80666d964ee48da375d1307bae6;hp=4314b99ce3da1589eef307e7d76b851adeadc943;hb=ee8686f095023b8cde2fc33488a58c291acfc50a;hpb=0ffa47548f474c1330d8d723300d9aa7a4894736 diff --git a/src/be/nikiroo/fanfix/supported/BasicSupport.java b/src/be/nikiroo/fanfix/supported/BasicSupport.java index 4314b99..ff9ecaf 100644 --- a/src/be/nikiroo/fanfix/supported/BasicSupport.java +++ b/src/be/nikiroo/fanfix/supported/BasicSupport.java @@ -2,14 +2,18 @@ package be.nikiroo.fanfix.supported; import java.io.IOException; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Scanner; import java.util.Map.Entry; +import org.json.JSONException; +import org.json.JSONObject; import org.jsoup.helper.DataUtil; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -37,13 +41,10 @@ public abstract class BasicSupport { private URL source; private SupportType type; private URL currentReferer; // with only one 'r', as in 'HTTP'... - - /** - * The name of this support class. - * - * @return the name - */ - protected abstract String getSourceName(); + + static protected BasicSupportHelper bsHelper = new BasicSupportHelper(); + static protected BasicSupportImages bsImages = new BasicSupportImages(); + static protected BasicSupportPara bsPara = new BasicSupportPara(new BasicSupportHelper(), new BasicSupportImages()); /** * Check if the given resource is supported by this {@link BasicSupport}. @@ -84,7 +85,7 @@ public abstract class BasicSupport { protected abstract String getDesc() throws IOException; /** - * Return the list of chapters (name and resource). * + * Return the list of chapters (name and resource). *

* Can be NULL if this {@link BasicSupport} do no use chapters. * @@ -214,8 +215,8 @@ public abstract class BasicSupport { /** * Open an input link that will be used for the support. *

- * Can return NULL, in which case you are supposed to work without an - * {@link InputStream}. + * Can return NULL, in which case you are supposed to work without a source + * node. * * @param source * the source {@link URL} @@ -227,8 +228,7 @@ public abstract class BasicSupport { */ protected Document loadDocument(URL source) throws IOException { String url = getCanonicalUrl(source).toString(); - return DataUtil.load(Instance.getCache().open(source, this, false), - "UTF-8", url.toString()); + return DataUtil.load(Instance.getInstance().getCache().open(source, this, false), "UTF-8", url.toString()); } /** @@ -237,20 +237,9 @@ public abstract class BasicSupport { * @throws IOException * in case of I/O error */ - @SuppressWarnings("unused") protected void login() throws IOException { } - /** - * Prepare the support if needed before processing. - * - * @throws IOException - * on I/O error - */ - @SuppressWarnings("unused") - protected void preprocess() throws IOException { - } - /** * Now that we have processed the {@link Story}, close the resources if any. */ @@ -258,28 +247,6 @@ public abstract class BasicSupport { setCurrentReferer(null); } - /** - * Process the given story resource into a partially filled {@link Story} - * object containing the name and metadata, except for the description. - * - * @return the {@link Story} - * - * @throws IOException - * in case of I/O error - */ - public Story processMeta() throws IOException { - Story story = null; - - preprocess(); - try { - story = processMeta(false, null); - } finally { - close(); - } - - return story; - } - /** * Process the given story resource into a partially filled {@link Story} * object containing the name and metadata. @@ -305,33 +272,99 @@ public abstract class BasicSupport { pg.setProgress(30); Story story = new Story(); + MetaData meta = getMeta(); - if (meta.getCreationDate() == null || meta.getCreationDate().isEmpty()) { - meta.setCreationDate(StringUtils.fromTime(new Date().getTime())); + meta.setType(getType().toString()); + meta.setSource(getType().getSourceName()); + if (meta.getPublisher() == null) { + meta.setPublisher(getType().getSourceName()); + } + + if (meta.getCreationDate() == null + || meta.getCreationDate().trim().isEmpty()) { + meta.setCreationDate(bsHelper + .formatDate(StringUtils.fromTime(new Date().getTime()))); } story.setMeta(meta); + pg.put("meta", meta); pg.setProgress(50); if (meta.getCover() == null) { - meta.setCover(BasicSupportHelper.getDefaultCover(meta.getSubject())); + meta.setCover(bsHelper.getDefaultCover(meta.getSubject())); } pg.setProgress(60); if (getDesc) { - String descChapterName = Instance.getTrans().getString( - StringId.DESCRIPTION); - story.getMeta().setResume( - BasicSupportPara.makeChapter(this, source, 0, - descChapterName, // - getDesc(), isHtml(), null)); + String descChapterName = Instance.getInstance().getTrans().getString(StringId.DESCRIPTION); + story.getMeta().setResume(bsPara.makeChapter(this, source, 0, descChapterName, // + getDesc(), isHtml(), null)); } - pg.setProgress(100); + pg.done(); return story; } + /** + * Utility method to convert the given URL into a JSON object. + *

+ * Note that this method expects small JSON files (everything is copied into + * memory at least twice). + * + * @param url + * the URL to parse + * @param stable + * TRUE for more stable resources, FALSE when they often change + * + * @return the JSON object + * + * @throws IOException + * in case of I/O error + */ + protected JSONObject getJson(String url, boolean stable) + throws IOException { + try { + return getJson(new URL(url), stable); + } catch (MalformedURLException e) { + throw new IOException("Malformed URL: " + url, e); + } + } + + /** + * Utility method to convert the given URL into a JSON object. + *

+ * Note that this method expects small JSON files (everything is copied into + * memory at least twice). + * + * @param url + * the URL to parse + * @param stable + * TRUE for more stable resources, FALSE when they often change + * + * @return the JSON object + * + * @throws IOException + * in case of I/O error + */ + protected JSONObject getJson(URL url, boolean stable) throws IOException { + InputStream in = Instance.getInstance().getCache().open(url, null, + stable); + try { + Scanner scan = new Scanner(in); + scan.useDelimiter("\0"); + try { + return new JSONObject(scan.next()); + } catch (JSONException e) { + throw new IOException(e); + } finally { + scan.close(); + } + } finally { + in.close(); + } + } + /** * Process the given story resource into a fully filled {@link Story} * object. @@ -344,87 +377,139 @@ public abstract class BasicSupport { * @throws IOException * in case of I/O error */ + // TODO: ADD final when BasicSupport_Deprecated is gone public Story process(Progress pg) throws IOException { + setCurrentReferer(source); + login(); + sourceNode = loadDocument(source); + + try { + Story story = doProcess(pg); + + // Check for "no chapters" stories + if (story.getChapters().isEmpty() + && story.getMeta().getResume() != null + && !story.getMeta().getResume().getParagraphs().isEmpty()) { + Chapter resume = story.getMeta().getResume(); + resume.setName(""); + resume.setNumber(1); + story.getChapters().add(resume); + story.getMeta().setWords(resume.getWords()); + + String descChapterName = Instance.getInstance().getTrans() + .getString(StringId.DESCRIPTION); + resume = new Chapter(0, descChapterName); + story.getMeta().setResume(resume); + } + + return story; + } finally { + close(); + } + } + + /** + * Actual processing step, without the calls to other methods. + *

+ * Will convert the story resource into a fully filled {@link Story} object. + * + * @param pg + * the optional progress reporter + * + * @return the {@link Story}, never NULL + * + * @throws IOException + * in case of I/O error + */ + protected Story doProcess(Progress pg) throws IOException { if (pg == null) { pg = new Progress(); } else { pg.setMinMax(0, 100); } - - setCurrentReferer(source); - login(); - sourceNode = loadDocument(source); + + pg.setName("Initialising"); pg.setProgress(1); - try { - Progress pgMeta = new Progress(); - pg.addProgress(pgMeta, 10); - preprocess(); - Story story = processMeta(true, pgMeta); - if (!pgMeta.isDone()) { - pgMeta.setProgress(pgMeta.getMax()); // 10% - } + Progress pgMeta = new Progress(); + pg.addProgress(pgMeta, 10); + Story story = processMeta(true, pgMeta); + pgMeta.done(); // 10% + pg.put("meta", story.getMeta()); + + Progress pgGetChapters = new Progress(); + pg.addProgress(pgGetChapters, 10); + story.setChapters(new ArrayList()); + List> chapters = getChapters(pgGetChapters); + pgGetChapters.done(); // 20% + + if (chapters != null) { + Progress pgChaps = new Progress("Extracting chapters", 0, + chapters.size() * 300); + pg.addProgress(pgChaps, 80); + + long words = 0; + int i = 1; + for (Entry chap : chapters) { + pgChaps.setName("Extracting chapter " + i); + URL chapUrl = chap.getValue(); + String chapName = chap.getKey(); + if (chapUrl != null) { + setCurrentReferer(chapUrl); + } - pg.setName("Retrieving " + story.getMeta().getTitle()); + pgChaps.setProgress(i * 100); + Progress pgGetChapterContent = new Progress(); + Progress pgMakeChapter = new Progress(); + pgChaps.addProgress(pgGetChapterContent, 100); + pgChaps.addProgress(pgMakeChapter, 100); - Progress pgGetChapters = new Progress(); - pg.addProgress(pgGetChapters, 10); - story.setChapters(new ArrayList()); - List> chapters = getChapters(pgGetChapters); - if (!pgGetChapters.isDone()) { - pgGetChapters.setProgress(pgGetChapters.getMax()); // 20% - } + String content = getChapterContent(chapUrl, i, + pgGetChapterContent); + pgGetChapterContent.done(); + Chapter cc = bsPara.makeChapter(this, chapUrl, i, + chapName, content, isHtml(), pgMakeChapter); + pgMakeChapter.done(); - if (chapters != null) { - Progress pgChaps = new Progress("Extracting chapters", 0, - chapters.size() * 300); - pg.addProgress(pgChaps, 80); - - long words = 0; - int i = 1; - for (Entry chap : chapters) { - pgChaps.setName("Extracting chapter " + i); - URL chapUrl = chap.getValue(); - String chapName = chap.getKey(); - if (chapUrl != null) { - setCurrentReferer(chapUrl); - } - - pgChaps.setProgress(i * 100); - Progress pgGetChapterContent = new Progress(); - Progress pgMakeChapter = new Progress(); - pgChaps.addProgress(pgGetChapterContent, 100); - pgChaps.addProgress(pgMakeChapter, 100); - - String content = getChapterContent(chapUrl, i, - pgGetChapterContent); - if (!pgGetChapterContent.isDone()) { - pgGetChapterContent.setProgress(pgGetChapterContent - .getMax()); - } - - Chapter cc = BasicSupportPara.makeChapter(this, chapUrl, i, - chapName, content, isHtml(), pgMakeChapter); - if (!pgMakeChapter.isDone()) { - pgMakeChapter.setProgress(pgMakeChapter.getMax()); - } - - words += cc.getWords(); - story.getChapters().add(cc); - story.getMeta().setWords(words); - - i++; - } + words += cc.getWords(); + story.getChapters().add(cc); - pgChaps.setName("Extracting chapters"); - } else { - pg.setProgress(80); + i++; } + + story.getMeta().setWords(words); - return story; - } finally { - close(); + pgChaps.setName("Extracting chapters"); + pgChaps.done(); } + + pg.done(); + + return story; + } + + /** + * Create a chapter from the given data. + * + * @param source + * the source URL for this content, which can be used to try and + * find images if images are present in the format [image-url] + * @param number + * the chapter number (0 = description) + * @param name + * the chapter name + * @param content + * the content of the chapter + * + * @return the {@link Chapter}, never NULL + * + * @throws IOException + * in case of I/O error + */ + public Chapter makeChapter(URL source, int number, String name, + String content) throws IOException { + return bsPara.makeChapter(this, source, number, name, + content, isHtml(), null); } /** @@ -466,10 +551,11 @@ public abstract class BasicSupport { * Return a {@link BasicSupport} implementation supporting the given type. * * @param type - * the type + * the type, must not be NULL * @param url * the {@link URL} to support (can be NULL to get an - * "abstract support") + * "abstract support"; if not NULL, will be used as the source + * URL) * * @return an implementation that supports it, or NULL */ @@ -497,8 +583,8 @@ public abstract class BasicSupport { case TEXT: support = new Text(); break; - case MANGAFOX: - support = new MangaFox(); + case MANGAHUB: + support = new MangaHub(); break; case E621: support = new E621(); @@ -509,6 +595,9 @@ public abstract class BasicSupport { case E_HENTAI: support = new EHentai(); break; + case MANGA_LEL: + support = new MangaLel(); + break; case CBZ: support = new Cbz(); break;