MANGAFOX,
/** Furry website with comics support */
E621,
+ /** Furry website with stories */
+ YIFFSTAR,
/** CBZ files */
CBZ,
/** HTML files */
private InputStream in;
private SupportType type;
- private URL currentReferer; // with on 'r', as in 'HTTP'...
+ private URL currentReferer; // with only one 'r', as in 'HTTP'...
// quote chars
private char openQuote = Instance.getTrans().getChar(
protected abstract String getChapterContent(URL source, InputStream in,
int number) throws IOException;
+ /**
+ * Log into the support (can be a no-op depending upon the support).
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public void login() throws IOException {
+
+ }
+
/**
* Return the list of cookies (values included) that must be used to
* correctly fetch the resources.
* it.
*
* @return the cookies
+ *
+ * @throws IOException
+ * in case of I/O error
*/
- public Map<String, String> getCookies() {
+ public Map<String, String> getCookies() throws IOException {
return new HashMap<String, String>();
}
+ /**
+ * Return the canonical form of the main {@link URL}.
+ *
+ * @param source
+ * the source {@link URL}
+ *
+ * @return the canonical form of this {@link URL}
+ *
+ * @throws IOException
+ * in case of I/O error
+ */
+ public URL getCanonicalUrl(URL source) throws IOException {
+ return source;
+ }
+
/**
* Process the given story resource into a partially filled {@link Story}
* object containing the name and metadata, except for the description.
*/
protected Story processMeta(URL url, boolean close, boolean getDesc)
throws IOException {
+ login();
+
+ url = getCanonicalUrl(url);
+
+ setCurrentReferer(url);
+
in = openInput(url);
if (in == null) {
return null;
in.close();
}
}
+
+ setCurrentReferer(null);
}
}
pg.setMinMax(0, 100);
}
- setCurrentReferer(url);
-
+ url = getCanonicalUrl(url);
pg.setProgress(1);
try {
Story story = processMeta(url, false, true);
return null;
}
+ setCurrentReferer(url);
+
story.setChapters(new ArrayList<Chapter>());
List<Entry<String, URL>> chapters = getChapters(url, getInput());
in.close();
}
- currentReferer = null;
+ setCurrentReferer(null);
}
}
/**
- * The support type.$
+ * The support type.
*
* @return the type
*/
/**
* Return the list of supported image extensions.
*
+ * @param emptyAllowed
+ * TRUE to allow an empty extension on first place, which can be
+ * used when you may already have an extension in your input but
+ * are not sure about it
+ *
* @return the extensions
*/
static String[] getImageExt(boolean emptyAllowed) {
}
}
+ /**
+ * Check if the given resource can be a local image or a remote image, then
+ * refresh the cache with it if it is.
+ *
+ * @param source
+ * the story source
+ * @param line
+ * the resource to check
+ *
+ * @return the image if found, or NULL
+ *
+ */
static BufferedImage getImage(BasicSupport support, URL source, String line) {
URL url = getImageUrl(support, source, line);
if (url != null) {
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();
* paragraphs (quotes or not)).
*
* @param para
- * the paragraph to requotify (not necessaraly a quote)
+ * the paragraph to requotify (not necessarily a quote)
*
* @return the correctly (or so we hope) quotified paragraphs
*/
*
* @return the processed {@link Paragraph}
*/
- private Paragraph processPara(String line) {
+ protected Paragraph processPara(String line) {
line = ifUnhtml(line).trim();
boolean space = true;
if (tentativeCloseQuote) {
tentativeCloseQuote = false;
- if ((car >= 'a' && car <= 'z') || (car >= 'A' && car <= 'Z')
- || (car >= '0' && car <= '9')) {
+ if (Character.isLetterOrDigit(car)) {
builder.append("'");
} else {
- builder.append(closeQuote);
+ // handle double-single quotes as double quotes
+ if (prev == car) {
+ builder.append(closeDoubleQuote);
+ continue;
+ } else {
+ builder.append(closeQuote);
+ }
}
}
case '\'':
if (space || (brk && quote)) {
quote = true;
- builder.append(openQuote);
- } else if (prev == ' ') {
- builder.append(openQuote);
+ // handle double-single quotes as double quotes
+ if (prev == car) {
+ builder.deleteCharAt(builder.length() - 1);
+ builder.append(openDoubleQuote);
+ } else {
+ builder.append(openQuote);
+ }
+ } else if (prev == ' ' || prev == car) {
+ // handle double-single quotes as double quotes
+ if (prev == car) {
+ builder.deleteCharAt(builder.length() - 1);
+ builder.append(openDoubleQuote);
+ } else {
+ builder.append(openQuote);
+ }
} else {
// it is a quote ("I'm off") or a 'quote' ("This
// 'good' restaurant"...)
quote = true;
builder.append(openQuote);
} else {
- builder.append(openQuote);
+ // handle double-single quotes as double quotes
+ if (prev == car) {
+ builder.deleteCharAt(builder.length() - 1);
+ builder.append(openDoubleQuote);
+ } else {
+ builder.append(openQuote);
+ }
}
space = false;
brk = false;
case '」':
space = false;
brk = false;
- builder.append(closeQuote);
+ // handle double-single quotes as double quotes
+ if (prev == car) {
+ builder.deleteCharAt(builder.length() - 1);
+ builder.append(closeDoubleQuote);
+ } else {
+ builder.append(closeQuote);
+ }
break;
case '«':
}
/**
- * Remove the HTML from the inpit <b>if</b> {@link BasicSupport#isHtml()} is
+ * Remove the HTML from the input <b>if</b> {@link BasicSupport#isHtml()} is
* true.
*
* @param input
return new MangaFox().setType(type);
case E621:
return new E621().setType(type);
+ case YIFFSTAR:
+ return new YiffStar().setType(type);
case CBZ:
return new Cbz().setType(type);
case HTML: