lib = createDefaultLibrary(remoteDir);
// create cache and TMP
- File tmp = getFile(Config.CACHE_DIR, new File(configDir, "tmp"));
- if (!tmp.isAbsolute()) {
- tmp = new File(configDir, tmp.getPath());
- }
+ File tmp = getFile(Config.CACHE_DIR, configDir, "tmp");
Image.setTemporaryFilesRoot(new File(tmp.getParent(), "tmp.images"));
String ua = config.getString(Config.NETWORK_USER_AGENT, "");
cache.setTraceHandler(tracer);
// readerTmp / coverDir
- readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER, new File(configDir, "tmp-reader"));
-
- coverDir = getFile(Config.DEFAULT_COVERS_DIR, new File(configDir, "covers"));
+ readerTmp = getFile(UiConfig.CACHE_DIR_LOCAL_READER, configDir, "tmp-reader");
+ coverDir = getFile(Config.DEFAULT_COVERS_DIR, configDir, "covers");
coverDir.mkdirs();
try {
} else {
String libDir = System.getenv("BOOKS_DIR");
if (libDir == null || libDir.isEmpty()) {
- libDir = config.getString(Config.LIBRARY_DIR, "$HOME/Books");
- if (!getFile(libDir).isAbsolute()) {
- libDir = new File(configDir, libDir).getPath();
- }
+ libDir = getFile(Config.LIBRARY_DIR, configDir, "$HOME/Books").getPath();
}
try {
- lib = new LocalLibrary(getFile(libDir), config);
+ lib = new LocalLibrary(new File(libDir), config);
} catch (Exception e) {
- tracer.error(new IOException("Cannot create library for directory: " + getFile(libDir), e));
+ tracer.error(new IOException("Cannot create library for directory: " + libDir, e));
}
}
* Return a path, but support the special $HOME variable.
*
* @param id the key for the path, which may contain "$HOME"
- * @param def the default value if none
+ * @param configDir the directory to use as base if not absolute
+ * @param def the default value if none (will be configDir-rooted if needed)
* @return the path, with expanded "$HOME" if needed
*/
- protected File getFile(Config id, File def) {
- String path = config.getString(id, def.getPath());
- return getFile(path);
+ protected File getFile(Config id, String configDir, String def) {
+ String path = config.getString(id, def);
+ return getFile(path, configDir);
}
/**
* Return a path, but support the special $HOME variable.
*
* @param id the key for the path, which may contain "$HOME"
- * @param def the default value if none
+ * @param configDir the directory to use as base if not absolute
+ * @param def the default value if none (will be configDir-rooted if needed)
* @return the path, with expanded "$HOME" if needed
*/
- protected File getFile(UiConfig id, File def) {
- String path = uiconfig.getString(id, def.getPath());
- return getFile(path);
+ protected File getFile(UiConfig id, String configDir, String def) {
+ String path = uiconfig.getString(id, def);
+ return getFile(path, configDir);
}
/**
* Return a path, but support the special $HOME variable.
*
* @param path the path, which may contain "$HOME"
+ * @param configDir the directory to use as base if not absolute
* @return the path, with expanded "$HOME" if needed
*/
- protected File getFile(String path) {
+ protected File getFile(String path, String configDir) {
File file = null;
if (path != null && !path.isEmpty()) {
path = path.replace('/', File.separatorChar);
if (path.contains("$HOME")) {
path = path.replace("$HOME", getHome());
+ } else if (!path.startsWith("/")) {
+ path = new File(configDir, path).getPath();
}
file = new File(path);
@Meta(description = "The external viewer for non-images documents (or empty to use the system default program for the given file type)",//
format = Format.STRING)
NON_IMAGES_DOCUMENT_READER, //
+ @Meta(description = "The icon to use for the program",//
+ format = Format.FIXED_LIST, def = "default", list = { "default", "alternative", "magic-book", "pony-book", "pony-library" })
+ PROGRAM_ICON, //
//
// GUI settings (hidden in config)
//
writer.write(" <div class='dialogue'>— ");
break;
case IMAGE:
- // TODO
+ // TODO check if images work OK
writer.write("<a href='"
+ StringUtils.xmlEscapeQuote(para.getContent()) + "'>"
+ StringUtils.xmlEscape(para.getContent()) + "</a>");
lastWasQuote = true;
break;
case IMAGE:
- // TODO
+ // TODO what about images in LaTeX?
break;
}
}
if (type != null) {
switch (type) {
case FIMFICTION:
- // TODO
+ // TODO searchable for FIMFICTION
break;
case FANFICTION:
support = new Fanfiction(type);
break;
case MANGAHUB:
- // TODO
+ // TODO searchable for MANGAHUB
break;
case E621:
- // TODO
+ // TODO searchable for E621
break;
case YIFFSTAR:
- // TODO
+ // TODO searchable for YIFFSTAR
break;
case E_HENTAI:
- // TODO
+ // TODO searchable for E_HENTAI
break;
case MANGA_LEL:
support = new MangaLel();
sourceNode = loadDocument(source);
try {
- return doProcess(pg);
+ 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();
}
story.setChapters(new ArrayList<Chapter>());
List<Entry<String, URL>> chapters = getChapters(pgGetChapters);
pgGetChapters.done(); // 20%
-
+
if (chapters != null) {
Progress pgChaps = new Progress("Extracting chapters", 0,
chapters.size() * 300);
words += cc.getWords();
story.getChapters().add(cc);
- story.getMeta().setWords(words);
i++;
}
+
+ story.getMeta().setWords(words);
pgChaps.setName("Extracting chapters");
pgChaps.done();
* the chapter name
* @param content
* the content of the chapter
- * @return the {@link Chapter}
+ *
+ * @return the {@link Chapter}, never NULL
*
* @throws IOException
* in case of I/O error
* @param html
* TRUE if the input content is in HTML mode
*
- * @return the {@link Chapter}
+ * @return the {@link Chapter}, never NULL
*
* @throws IOException
* in case of I/O error
* @param html
* TRUE if the input content is in HTML mode
*
- * @return the processed {@link Paragraph}
+ * @return the processed {@link Paragraph}, never NULL
*/
protected Paragraph processPara(String line, boolean html) {
if (html) {
* @param pg
* the optional progress reporter
*
- * @return the {@link Paragraph}s
+ * @return the {@link Paragraph}s (can be empty but never NULL)
*
* @throws IOException
* in case of I/O error
* @param html
* TRUE if the input content is in HTML mode
*
- * @return the {@link Paragraph}
+ * @return the {@link Paragraph}, never NULL
*/
protected Paragraph makeParagraph(BasicSupport support, URL source,
String line, boolean html) {
words += cc.getWords();
story.getChapters().add(cc);
- story.getMeta().setWords(words);
} finally {
if (chapIn != null) {
chapIn.close();
i++;
}
+
+ story.getMeta().setWords(words);
pgChaps.setName("Extracting chapters");
} else {
pg.setProgress(80);
}
- return story;
+ // 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();
* @param pg
* the optional progress reporter
*
- * @return the {@link Chapter}
+ * @return the {@link Chapter}, never NULL
*
* @throws IOException
* in case of I/O error
* @param pg
* the optional progress reporter
*
- * @return the {@link Paragraph}s
+ * @return the {@link Paragraph}s (can be empty, but never NULL)
*
* @throws IOException
* in case of I/O error
}
List<Paragraph> paras = new ArrayList<Paragraph>();
-
if (content != null && !content.trim().isEmpty()) {
if (isHtml()) {
String[] tab = content.split("(<p>|</p>|<br>|<br/>)");
* @param line
* the textual content of the paragraph
*
- * @return the {@link Paragraph}
+ * @return the {@link Paragraph}, never NULL
*/
private Paragraph makeParagraph(URL source, String line) {
Image image = null;
* @param line
* the raw line
*
- * @return the processed {@link Paragraph}
+ * @return the processed {@link Paragraph}, never NULL
*/
protected Paragraph processPara(String line) {
line = ifUnhtml(line).trim();
}
if (!imagesList.isEmpty()) {
- Chapter chap = new Chapter(story.getChapters().size() + 1, null);
+ Chapter chap = new Chapter(story.getChapters().size() + 1, "");
story.getChapters().add(chap);
for (String uuid : imagesList) {
// There is no chapters on e621, just pagination...
Story story = super.process(url, pg);
- Chapter only = new Chapter(1, null);
+ Chapter only = new Chapter(1, "");
for (Chapter chap : story) {
only.getParagraphs().addAll(chap.getParagraphs());
}
} else if (langLine.equalsIgnoreCase("French")) {
lang = "fr";
} else {
- // TODO find the code?
+ // TODO find the code for other languages?
lang = langLine;
}
}
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
if (!entry.isDirectory()
&& entry.getName().startsWith(getDataPrefix())) {
String entryLName = entry.getName().toLowerCase();
+ entryLName = entryLName.substring(getDataPrefix().length());
boolean imageEntry = false;
for (String ext : bsImages.getImageExt(false)) {
}
}
- if (entry.getName().equals(getDataPrefix() + "version")) {
+ if (entryLName.equals("version")) {
// Nothing to do for now ("first"
// version is 3.0)
} else if (entryLName.endsWith(".info")) {
IOUtils.write(zipIn, tmpInfo);
} else if (imageEntry) {
// Cover
- if (getCover()) {
+ if (getCover() && cover == null) {
try {
cover = new Image(zipIn);
} catch (Exception e) {
.error(e);
}
}
- } else if (entry.getName()
- .equals(getDataPrefix() + "URL")) {
+ } else if (entryLName.equals("url")) {
String[] descArray = StringUtils
.unhtml(IOUtils.readSmallStream(zipIn)).trim()
.split("\n");
if (descArray.length > 0) {
url = descArray[0].trim();
}
- } else if (entry.getName().endsWith(".desc")) {
+ } else if (entryLName.endsWith(".desc")) {
// // For old files
// if (this.desc != null) {
// this.desc = IOUtils.readSmallStream(zipIn).trim();
// }
- } else if (entry.getName()
- .equals(getDataPrefix() + "SUMMARY")) {
+ } else if (entryLName.equals("summary")) {
String[] descArray = StringUtils
.unhtml(IOUtils.readSmallStream(zipIn)).trim()
.split("\n");
}
}
- if (requireInfo() && (!tmp.exists() || !tmpInfo.exists())) {
+ if (requireInfo() && !tmp.exists()) {
throw new IOException(
"file not supported (maybe not created with this program or corrupt)");
}
} else {
if (title == null || title.isEmpty()) {
title = getSourceFileOriginal().getName();
- if (title.toLowerCase().endsWith(".cbz")) {
- title = title.substring(0, title.length() - 4);
+ String exts[] = new String[] {".epub", ".cbz"};
+ for (String ext : exts) {
+ if (title.toLowerCase().endsWith(ext)) {
+ title = title.substring(0,
+ title.length() - ext.length());
+ }
}
title = URLDecoder.decode(title, "UTF-8").trim();
}
meta = new MetaData();
meta.setLang("en");
- meta.setTags(new ArrayList<String>());
+ meta.setTags(Arrays.asList("[no_info]"));
meta.setSource(getType().getSourceName());
meta.setUuid(url);
meta.setUrl(url);
meta.setTitle(title);
meta.setAuthor(author);
meta.setImageDocument(isImagesDocumentByDefault());
+
+ InfoReader.completeMeta(tmp, meta);
}
if (meta.getCover() == null) {
meta.setPublisher(getType().getSourceName());
meta.setUuid(source.toString());
meta.setLuid("");
- meta.setLang("en"); // TODO!
+ meta.setLang("en"); // TODO find language of book
meta.setSubject(getSubject(reset(in)));
meta.setType(getType().toString());
meta.setImageDocument(false);
meta.getUrl())) {
// TODO: not nice, would be better to do it properly...
-
String base = infoFile.getPath();
if (base.endsWith(".info")) {
base = base.substring(0,
textFile = new File(base + ".text");
}
- if (textFile.exists()) {
- final URL source = textFile.toURI().toURL();
- final MetaData[] superMetaA = new MetaData[1];
- @SuppressWarnings("unused")
- Text unused = new Text() {
- private boolean loaded = loadDocument();
-
- @Override
- public SupportType getType() {
- return SupportType.TEXT;
- }
-
- protected boolean loadDocument()
- throws IOException {
- loadDocument(source);
- superMetaA[0] = getMeta();
- return true;
- }
-
- @Override
- protected Image getCover(File sourceFile) {
- return null;
- }
- };
-
- MetaData superMeta = superMetaA[0];
- if (!hasIt(meta.getTitle())) {
- meta.setTitle(superMeta.getTitle());
- }
- if (!hasIt(meta.getAuthor())) {
- meta.setAuthor(superMeta.getAuthor());
- }
- if (!hasIt(meta.getDate())) {
- meta.setDate(superMeta.getDate());
- }
- if (!hasIt(meta.getUrl())) {
- meta.setUrl(superMeta.getUrl());
- }
- }
+ completeMeta(textFile, meta);
+ //
}
return meta;
"File given as argument does not exists: "
+ infoFile.getAbsolutePath());
}
+
+ /**
+ * Complete the given {@link MetaData} with the original text file if needed
+ * and possible.
+ *
+ * @param textFile
+ * the original text file
+ * @param meta
+ * the {@link MetaData} to complete if needed and possible
+ *
+ * @throws IOException
+ * in case of I/O errors
+ */
+ static public void completeMeta(File textFile,
+ MetaData meta) throws IOException {
+ if (textFile != null && textFile.exists()) {
+ final URL source = textFile.toURI().toURL();
+ final MetaData[] superMetaA = new MetaData[1];
+ @SuppressWarnings("unused")
+ Text unused = new Text() {
+ private boolean loaded = loadDocument();
+
+ @Override
+ public SupportType getType() {
+ return SupportType.TEXT;
+ }
+
+ protected boolean loadDocument() throws IOException {
+ loadDocument(source);
+ superMetaA[0] = getMeta();
+ return true;
+ }
+
+ @Override
+ protected Image getCover(File sourceFile) {
+ return null;
+ }
+ };
+
+ MetaData superMeta = superMetaA[0];
+ if (!hasIt(meta.getTitle())) {
+ meta.setTitle(superMeta.getTitle());
+ }
+ if (!hasIt(meta.getAuthor())) {
+ meta.setAuthor(superMeta.getAuthor());
+ }
+ if (!hasIt(meta.getDate())) {
+ meta.setDate(superMeta.getDate());
+ }
+ if (!hasIt(meta.getUrl())) {
+ meta.setUrl(superMeta.getUrl());
+ }
+ }
+ }
/**
* Check if we have non-empty values for all the given {@link String}s.
}
private String getLang() {
- @SuppressWarnings("resource")
+ @SuppressWarnings("resource") // cannot close, or we loose getInput()!
Scanner scan = new Scanner(getInput(), "UTF-8");
scan.useDelimiter("\\n");
scan.next(); // Title
}
private String getTitle() {
- @SuppressWarnings("resource")
+ @SuppressWarnings("resource") // cannot close, or we loose getInput()!
Scanner scan = new Scanner(getInput(), "UTF-8");
scan.useDelimiter("\\n");
return scan.next();
}
private String getAuthor() {
- @SuppressWarnings("resource")
+ @SuppressWarnings("resource") // cannot close, or we loose getInput()!
Scanner scan = new Scanner(getInput(), "UTF-8");
scan.useDelimiter("\\n");
scan.next();
}
private String getDate() {
- @SuppressWarnings("resource")
+ @SuppressWarnings("resource") // cannot close, or we loose getInput()!
Scanner scan = new Scanner(getInput(), "UTF-8");
scan.useDelimiter("\\n");
scan.next();
protected List<Entry<String, URL>> getChapters(Progress pg)
throws IOException {
List<Entry<String, URL>> chaps = new ArrayList<Entry<String, URL>>();
- @SuppressWarnings("resource")
+ @SuppressWarnings("resource") // cannot close, or we loose getInput()!
Scanner scan = new Scanner(getInput(), "UTF-8");
scan.useDelimiter("\\n");
- boolean prevLineEmpty = false;
+ String line = "first is not empty";
while (scan.hasNext()) {
- String line = scan.next();
+ boolean prevLineEmpty = line.trim().isEmpty();
+ line = scan.next();
if (prevLineEmpty && detectChapter(line, chaps.size() + 1) != null) {
String chapName = Integer.toString(chaps.size() + 1);
int pos = line.indexOf(':');
chapName, //
getSourceFile().toURI().toURL()));
}
-
- prevLineEmpty = line.trim().isEmpty();
}
-
+
return chaps;
}
protected String getChapterContent(URL source, int number, Progress pg)
throws IOException {
StringBuilder builder = new StringBuilder();
- @SuppressWarnings("resource")
+ @SuppressWarnings("resource") // cannot close, or we loose getInput()!
Scanner scan = new Scanner(getInput(), "UTF-8");
scan.useDelimiter("\\n");
- boolean inChap = false;
+ scan.next(); // title
+ scan.next(); // author
+ scan.next(); // date or empty
+ Boolean inChap = null;
+ String line = "";
while (scan.hasNext()) {
- String line = scan.next();
- if (!inChap && detectChapter(line, number) != null) {
+ if (number == 0 && !line.trim().isEmpty()) {
+ // We found pre-chapter content, we are checking for
+ // Chapter 0 (fake chapter) --> keep the content
+ if (inChap == null)
+ inChap = true;
+ }
+ line = scan.next();
+ if ((inChap == null || !inChap) && detectChapter(line, number) != null) {
inChap = true;
} else if (detectChapter(line, number + 1) != null) {
break;
- } else if (inChap) {
+ } else if (inChap != null && inChap) {
builder.append(line);
builder.append("\n");
}