X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2Fsupported%2FBasicSupport.java;h=f16cdc7b6453ac00753bb479850ab7eb2edcafc5;hb=16a81ef7656c5c692fb831927e75edde25dd77a0;hp=97338ba4b1d8fca449c16b5799e5d4d8a23b13ed;hpb=ed08c17162aa8cbdb0cbe6a6045815b987236b9f;p=nikiroo-utils.git diff --git a/src/be/nikiroo/fanfix/supported/BasicSupport.java b/src/be/nikiroo/fanfix/supported/BasicSupport.java index 97338ba..f16cdc7 100644 --- a/src/be/nikiroo/fanfix/supported/BasicSupport.java +++ b/src/be/nikiroo/fanfix/supported/BasicSupport.java @@ -1,6 +1,5 @@ package be.nikiroo.fanfix.supported; -import java.awt.image.BufferedImage; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; @@ -25,7 +24,7 @@ import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Paragraph; import be.nikiroo.fanfix.data.Paragraph.ParagraphType; import be.nikiroo.fanfix.data.Story; -import be.nikiroo.utils.IOUtils; +import be.nikiroo.utils.Image; import be.nikiroo.utils.Progress; import be.nikiroo.utils.StringUtils; @@ -62,6 +61,8 @@ public abstract class BasicSupport { E621, /** Furry website with stories */ YIFFSTAR, + /** Comics and images groups, mostly but not only NSFW */ + E_HENTAI, /** CBZ files */ CBZ, /** HTML files */ @@ -104,7 +105,8 @@ public abstract class BasicSupport { } /** - * Call {@link SupportType#valueOf(String.toUpperCase())}. + * Call {@link SupportType#valueOf(String)} after conversion to upper + * case. * * @param typeName * the possible type name @@ -117,8 +119,8 @@ public abstract class BasicSupport { } /** - * Call {@link SupportType#valueOf(String.toUpperCase())} but return - * NULL for NULL instead of raising exception. + * Call {@link SupportType#valueOf(String)} after conversion to upper + * case but return NULL for NULL instead of raising exception. * * @param typeName * the possible type name @@ -134,8 +136,9 @@ public abstract class BasicSupport { } /** - * Call {@link SupportType#valueOf(String.toUpperCase())} but return - * NULL in case of error instead of raising an exception. + * Call {@link SupportType#valueOf(String)} after conversion to upper + * case but return NULL in case of error instead of raising an + * exception. * * @param typeName * the possible type name @@ -156,13 +159,13 @@ public abstract class BasicSupport { private URL currentReferer; // with only one 'r', as in 'HTTP'... // quote chars - private char openQuote = Instance.getTrans().getChar( + private char openQuote = Instance.getTrans().getCharacter( StringId.OPEN_SINGLE_QUOTE); - private char closeQuote = Instance.getTrans().getChar( + private char closeQuote = Instance.getTrans().getCharacter( StringId.CLOSE_SINGLE_QUOTE); - private char openDoubleQuote = Instance.getTrans().getChar( + private char openDoubleQuote = Instance.getTrans().getCharacter( StringId.OPEN_DOUBLE_QUOTE); - private char closeDoubleQuote = Instance.getTrans().getChar( + private char closeDoubleQuote = Instance.getTrans().getCharacter( StringId.CLOSE_DOUBLE_QUOTE); /** @@ -190,6 +193,19 @@ public abstract class BasicSupport { */ protected abstract boolean isHtml(); + /** + * Return the {@link MetaData} of this story. + * + * @param source + * the source of the story + * @param in + * the input (the main resource) + * + * @return the associated {@link MetaData}, never NULL + * + * @throws IOException + * in case of I/O error + */ protected abstract MetaData getMeta(URL source, InputStream in) throws IOException; @@ -254,8 +270,8 @@ public abstract class BasicSupport { * @throws IOException * in case of I/O error */ + @SuppressWarnings("unused") public void login() throws IOException { - } /** @@ -266,14 +282,20 @@ public abstract class BasicSupport { * it. * * @return the cookies - * - * @throws IOException - * in case of I/O error */ - public Map getCookies() throws IOException { + public Map getCookies() { return new HashMap(); } + /** + * OAuth authorisation (aka, "bearer XXXXXXX"). + * + * @return the OAuth string + */ + public String getOAuth() { + return null; + } + /** * Return the canonical form of the main {@link URL}. * @@ -285,6 +307,7 @@ public abstract class BasicSupport { * @throws IOException * in case of I/O error */ + @SuppressWarnings("unused") public URL getCanonicalUrl(URL source) throws IOException { return source; } @@ -311,13 +334,14 @@ public abstract class BasicSupport { * * @param url * the story resource - * * @param close * close "this" and "in" when done + * @param getDesc + * retrieve the description of the story, or not * @param pg * the optional progress reporter * - * @return the {@link Story} + * @return the {@link Story}, never NULL * * @throws IOException * in case of I/O error @@ -337,11 +361,7 @@ public abstract class BasicSupport { setCurrentReferer(url); - in = openInput(url); - if (in == null) { - return null; - } - + in = openInput(url); // NULL allowed here try { preprocess(url, getInput()); pg.setProgress(30); @@ -356,7 +376,7 @@ public abstract class BasicSupport { pg.setProgress(50); - if (meta != null && meta.getCover() == null) { + if (meta.getCover() == null) { meta.setCover(getDefaultCover(meta.getSubject())); } @@ -377,7 +397,7 @@ public abstract class BasicSupport { try { close(); } catch (IOException e) { - Instance.syserr(e); + Instance.getTraceHandler().error(e); } if (in != null) { @@ -398,7 +418,7 @@ public abstract class BasicSupport { * @param pg * the optional progress reporter * - * @return the {@link Story} + * @return the {@link Story}, never NULL * * @throws IOException * in case of I/O error @@ -420,11 +440,6 @@ public abstract class BasicSupport { pgMeta.setProgress(pgMeta.getMax()); // 10% } - if (story == null) { - pg.setProgress(90); - return null; - } - pg.setName("Retrieving " + story.getMeta().getTitle()); setCurrentReferer(url); @@ -447,9 +462,12 @@ public abstract class BasicSupport { int i = 1; for (Entry chap : chapters) { pgChaps.setName("Extracting chapter " + i); - setCurrentReferer(chap.getValue()); - InputStream chapIn = Instance.getCache().open( - chap.getValue(), this, true); + InputStream chapIn = null; + if (chap.getValue() != null) { + setCurrentReferer(chap.getValue()); + chapIn = Instance.getCache().open(chap.getValue(), + this, true); + } pgChaps.setProgress(i * 100); try { Progress pgGetChapterContent = new Progress(); @@ -472,11 +490,11 @@ public abstract class BasicSupport { words += cc.getWords(); story.getChapters().add(cc); - if (story.getMeta() != null) { - story.getMeta().setWords(words); - } + story.getMeta().setWords(words); } finally { - chapIn.close(); + if (chapIn != null) { + chapIn.close(); + } } i++; @@ -493,7 +511,7 @@ public abstract class BasicSupport { try { close(); } catch (IOException e) { - Instance.syserr(e); + Instance.getTraceHandler().error(e); } if (in != null) { @@ -558,6 +576,7 @@ public abstract class BasicSupport { * @throws IOException * on I/O error */ + @SuppressWarnings("unused") protected void preprocess(URL source, InputStream in) throws IOException { } @@ -567,6 +586,7 @@ public abstract class BasicSupport { * @throws IOException * on I/O error */ + @SuppressWarnings("unused") protected void close() throws IOException { } @@ -574,6 +594,8 @@ public abstract class BasicSupport { * Create a {@link Chapter} object from the given information, formatting * the content as it should be. * + * @param source + * the source of the story * @param number * the chapter number * @param name @@ -591,7 +613,8 @@ public abstract class BasicSupport { protected Chapter makeChapter(URL source, int number, String name, String content, Progress pg) throws IOException { // Chapter name: process it correctly, then remove the possible - // redundant "Chapter x: " in front of it + // redundant "Chapter x: " in front of it, or "-" (as in + // "Chapter 5: - Fun!" after the ": " was automatically added) String chapterName = processPara(name).getContent().trim(); for (String lang : Instance.getConfig().getString(Config.CHAPTER) .split(",")) { @@ -609,7 +632,7 @@ public abstract class BasicSupport { Integer.toString(number).length()).trim(); } - if (chapterName.startsWith(":")) { + while (chapterName.startsWith(":") || chapterName.startsWith("-")) { chapterName = chapterName.substring(1).trim(); } // @@ -726,17 +749,17 @@ public abstract class BasicSupport { * @return the {@link Paragraph} */ private Paragraph makeParagraph(URL source, String line) { - URL image = null; + Image image = null; if (line.startsWith("[") && line.endsWith("]")) { - image = getImageUrl(this, source, - line.substring(1, line.length() - 1).trim()); + image = getImage(this, source, line.substring(1, line.length() - 1) + .trim()); } if (image != null) { return new Paragraph(image); - } else { - return processPara(line); } + + return processPara(line); } /** @@ -793,7 +816,7 @@ public abstract class BasicSupport { * * @return the cover if any, or NULL */ - static BufferedImage getDefaultCover(String subject) { + static Image getDefaultCover(String subject) { if (subject != null && !subject.isEmpty() && Instance.getCoverDir() != null) { try { @@ -819,9 +842,9 @@ public abstract class BasicSupport { static String[] getImageExt(boolean emptyAllowed) { if (emptyAllowed) { return new String[] { "", ".png", ".jpg", ".jpeg", ".gif", ".bmp" }; - } else { - return new String[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp" }; } + + return new String[] { ".png", ".jpg", ".jpeg", ".gif", ".bmp" }; } /** @@ -836,13 +859,18 @@ public abstract class BasicSupport { * @return the image if found, or NULL * */ - static BufferedImage getImage(BasicSupport support, URL source, String line) { + static Image getImage(BasicSupport support, URL source, String line) { URL url = getImageUrl(support, source, line); if (url != null) { + if ("file".equals(url.getProtocol())) { + if (new File(url.getPath()).isDirectory()) { + return null; + } + } InputStream in = null; try { in = Instance.getCache().open(url, getSupport(url), true); - return IOUtils.toImage(in); + return new Image(in); } catch (IOException e) { } finally { if (in != null) { @@ -874,19 +902,38 @@ public abstract class BasicSupport { if (line != null) { // try for files - String path = null; if (source != null) { - path = new File(source.getFile()).getParent(); try { - String basePath = new File(new File(path), line.trim()) - .getAbsolutePath(); + + String relPath = null; + String absPath = null; + try { + String path = new File(source.getFile()).getParent(); + relPath = new File(new File(path), line.trim()) + .getAbsolutePath(); + } catch (Exception e) { + // Cannot be converted to path (one possibility to take + // into account: absolute path on Windows) + } + try { + absPath = new File(line.trim()).getAbsolutePath(); + } catch (Exception e) { + // Cannot be converted to path (at all) + } + for (String ext : getImageExt(true)) { - if (new File(basePath + ext).exists()) { - url = new File(basePath + ext).toURI().toURL(); + File absFile = new File(absPath + ext); + File relFile = new File(relPath + ext); + if (absPath != null && absFile.exists() + && absFile.isFile()) { + url = absFile.toURI().toURL(); + } else if (relPath != null && relFile.exists() + && relFile.isFile()) { + url = relFile.toURI().toURL(); } } } catch (Exception e) { - // Nothing to do here + // Should not happen since we control the correct arguments } } @@ -894,7 +941,8 @@ public abstract class BasicSupport { // try for URLs try { for (String ext : getImageExt(true)) { - if (Instance.getCache().check(new URL(line + ext))) { + if (Instance.getCache() + .check(new URL(line + ext), true)) { url = new URL(line + ext); break; } @@ -934,6 +982,9 @@ public abstract class BasicSupport { /** * Open the input file that will be used through the support. + *

+ * Can return NULL, in which case you are supposed to work without an + * {@link InputStream}. * * @param source * the source {@link URL} @@ -947,22 +998,6 @@ public abstract class BasicSupport { return Instance.getCache().open(source, this, false); } - /** - * Reset the given {@link InputStream} and return it. - * - * @param in - * the {@link InputStream} to reset - * - * @return the same {@link InputStream} after reset - */ - protected InputStream reset(InputStream in) { - try { - in.reset(); - } catch (IOException e) { - } - return in; - } - /** * Reset then return {@link BasicSupport#in}. * @@ -1124,9 +1159,9 @@ public abstract class BasicSupport { if (prev == car) { builder.append(closeDoubleQuote); continue; - } else { - builder.append(closeQuote); } + + builder.append(closeQuote); } } @@ -1362,7 +1397,12 @@ public abstract class BasicSupport { case INFO_TEXT: return new InfoText().setType(type); case FIMFICTION: - return new Fimfiction().setType(type); + try { + // Can fail if no client key or NO in options + return new FimfictionApi().setType(type); + } catch (IOException e) { + return new Fimfiction().setType(type); + } case FANFICTION: return new Fanfiction().setType(type); case TEXT: @@ -1373,6 +1413,8 @@ public abstract class BasicSupport { return new E621().setType(type); case YIFFSTAR: return new YiffStar().setType(type); + case E_HENTAI: + return new EHentai().setType(type); case CBZ: return new Cbz().setType(type); case HTML: @@ -1382,6 +1424,25 @@ public abstract class BasicSupport { return null; } + /** + * Reset the given {@link InputStream} and return it. + * + * @param in + * the {@link InputStream} to reset + * + * @return the same {@link InputStream} after reset + */ + static protected InputStream reset(InputStream in) { + try { + if (in != null) { + in.reset(); + } + } catch (IOException e) { + } + + return in; + } + /** * Return the first line from the given input which correspond to the given * selectors. @@ -1398,7 +1459,8 @@ public abstract class BasicSupport { * * @return the line */ - static String getLine(InputStream in, String needle, int relativeLine) { + static protected String getLine(InputStream in, String needle, + int relativeLine) { return getLine(in, needle, relativeLine, true); } @@ -1421,15 +1483,11 @@ public abstract class BasicSupport { * * @return the line */ - static String getLine(InputStream in, String needle, int relativeLine, - boolean first) { + static protected String getLine(InputStream in, String needle, + int relativeLine, boolean first) { String rep = null; - try { - in.reset(); - } catch (IOException e) { - Instance.syserr(e); - } + reset(in); List lines = new ArrayList(); @SuppressWarnings("resource") @@ -1463,4 +1521,133 @@ public abstract class BasicSupport { return rep; } + + /** + * Return the text between the key and the endKey (and optional subKey can + * be passed, in this case we will look for the key first, then take the + * text between the subKey and the endKey). + *

+ * Will only match the first line with the given key if more than one are + * possible. Which also means that if the subKey or endKey is not found on + * that line, NULL will be returned. + * + * @param in + * the input + * @param key + * the key to match (also supports "^" at start to say + * "only if it starts with" the key) + * @param subKey + * the sub key or NULL if none + * @param endKey + * the end key or NULL for "up to the end" + * @return the text or NULL if not found + */ + static protected String getKeyLine(InputStream in, String key, + String subKey, String endKey) { + return getKeyText(getLine(in, key, 0), key, subKey, endKey); + } + + /** + * Return the text between the key and the endKey (and optional subKey can + * be passed, in this case we will look for the key first, then take the + * text between the subKey and the endKey). + * + * @param in + * the input + * @param key + * the key to match (also supports "^" at start to say + * "only if it starts with" the key) + * @param subKey + * the sub key or NULL if none + * @param endKey + * the end key or NULL for "up to the end" + * @return the text or NULL if not found + */ + static protected String getKeyText(String in, String key, String subKey, + String endKey) { + String result = null; + + String line = in; + if (line != null && line.contains(key)) { + line = line.substring(line.indexOf(key) + key.length()); + if (subKey == null || subKey.isEmpty() || line.contains(subKey)) { + if (subKey != null) { + line = line.substring(line.indexOf(subKey) + + subKey.length()); + } + if (endKey == null || line.contains(endKey)) { + if (endKey != null) { + line = line.substring(0, line.indexOf(endKey)); + result = line; + } + } + } + } + + return result; + } + + /** + * Return the text between the key and the endKey (optional subKeys can be + * passed, in this case we will look for the subKeys first, then take the + * text between the key and the endKey). + * + * @param in + * the input + * @param key + * the key to match + * @param endKey + * the end key or NULL for "up to the end" + * @param afters + * the sub-keys to find before checking for key/endKey + * + * @return the text or NULL if not found + */ + static protected String getKeyTextAfter(String in, String key, + String endKey, String... afters) { + + if (in != null && !in.isEmpty()) { + int pos = indexOfAfter(in, 0, afters); + if (pos < 0) { + return null; + } + + in = in.substring(pos); + } + + return getKeyText(in, key, null, endKey); + } + + /** + * Return the first index after all the given "afters" have been found in + * the {@link String}, or -1 if it was not possible. + * + * @param in + * the input + * @param startAt + * start at this position in the string + * @param afters + * the sub-keys to find before checking for key/endKey + * + * @return the text or NULL if not found + */ + static protected int indexOfAfter(String in, int startAt, String... afters) { + int pos = -1; + if (in != null && !in.isEmpty()) { + pos = startAt; + if (afters != null) { + for (int i = 0; pos >= 0 && i < afters.length; i++) { + String subKey = afters[i]; + if (!subKey.isEmpty()) { + pos = in.indexOf(subKey, pos); + if (pos >= 0) { + pos += subKey.length(); + } + } + } + } + } + + return pos; + } }