Merge branch 'subtree'
authorNiki Roo <niki@nikiroo.be>
Tue, 5 May 2020 15:13:15 +0000 (17:13 +0200)
committerNiki Roo <niki@nikiroo.be>
Tue, 5 May 2020 15:13:15 +0000 (17:13 +0200)
14 files changed:
src/be/nikiroo/fanfix/Instance.java
src/be/nikiroo/fanfix/bundles/UiConfig.java
src/be/nikiroo/fanfix/output/Html.java
src/be/nikiroo/fanfix/output/LaTeX.java
src/be/nikiroo/fanfix/searchable/BasicSearchable.java
src/be/nikiroo/fanfix/supported/BasicSupport.java
src/be/nikiroo/fanfix/supported/BasicSupportPara.java
src/be/nikiroo/fanfix/supported/BasicSupport_Deprecated.java
src/be/nikiroo/fanfix/supported/Cbz.java
src/be/nikiroo/fanfix/supported/EHentai.java
src/be/nikiroo/fanfix/supported/Epub.java
src/be/nikiroo/fanfix/supported/Fanfiction.java
src/be/nikiroo/fanfix/supported/InfoReader.java
src/be/nikiroo/fanfix/supported/Text.java

index d0d1c84ab7643b65b34a91859a1b75ca59533091..5c00a0756e0aa2f484e2003135b9123d396257f0 100644 (file)
@@ -147,10 +147,7 @@ public class Instance {
                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, "");
@@ -166,9 +163,8 @@ public class Instance {
                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 {
@@ -493,15 +489,12 @@ public class Instance {
                } 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));
                        }
                }
 
@@ -512,38 +505,43 @@ public class Instance {
         * 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);
index 0f3142d3f5552833c162c846122061b9a347e9da..2122ccf8b48164ca04562227cc1c6d32a8388e4f 100644 (file)
@@ -31,6 +31,9 @@ public enum UiConfig {
        @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)
        //
index da79466a40d9cc2fcf80872d77ef6e588398e732..f81ea1dc5f643d20de832dcd96b48ec4070172ab 100644 (file)
@@ -216,7 +216,7 @@ class Html extends BasicOutput {
                        writer.write("                  <div class='dialogue'>&mdash; ");
                        break;
                case IMAGE:
-                       // TODO
+                       // TODO check if images work OK
                        writer.write("<a href='"
                                        + StringUtils.xmlEscapeQuote(para.getContent()) + "'>"
                                        + StringUtils.xmlEscape(para.getContent()) + "</a>");
index a15e67c900c7fe59dbbde4aa901c7bc246255e61..a406fc35fd425635baad02e6335de0cbaf0a9f61 100644 (file)
@@ -149,7 +149,7 @@ class LaTeX extends BasicOutput {
                        lastWasQuote = true;
                        break;
                case IMAGE:
-                       // TODO
+                       // TODO what about images in LaTeX?
                        break;
                }
        }
index b943abd25401f426bad456140eea004be06437fb..cb0b1712ccb3fc7762354f799a04f65b45d89de8 100644 (file)
@@ -241,22 +241,22 @@ public abstract class BasicSearchable {
                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();
index 0a5ec3686e1be43c52a328d1a1be86e805ad21fe..f1635589bfd70b0dca80b5972dcfd241bda895f8 100644 (file)
@@ -374,7 +374,25 @@ public abstract class BasicSupport {
                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();
                }
@@ -414,7 +432,7 @@ public abstract class BasicSupport {
                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);
@@ -445,10 +463,11 @@ public abstract class BasicSupport {
 
                                words += cc.getWords();
                                story.getChapters().add(cc);
-                               story.getMeta().setWords(words);
 
                                i++;
                        }
+                       
+                       story.getMeta().setWords(words);
 
                        pgChaps.setName("Extracting chapters");
                        pgChaps.done();
@@ -471,7 +490,8 @@ public abstract class BasicSupport {
         *            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
index 58c363af59b77e1b4f4d1c323fefe2af350ad31b..1dbedc9cc326b0bdcb18e11753c8d78ccc611e22 100644 (file)
@@ -60,7 +60,7 @@ public class BasicSupportPara {
         * @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
@@ -202,7 +202,7 @@ public class BasicSupportPara {
         * @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) {
@@ -423,7 +423,7 @@ public class BasicSupportPara {
         * @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
@@ -514,7 +514,7 @@ public class BasicSupportPara {
         * @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) {
index bc3738a211bc22b92ac8811e85a549dd17777618..a50ee3cf48a962a38b5ebe52b33184c956169ffd 100644 (file)
@@ -317,7 +317,6 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
 
                                                words += cc.getWords();
                                                story.getChapters().add(cc);
-                                               story.getMeta().setWords(words);
                                        } finally {
                                                if (chapIn != null) {
                                                        chapIn.close();
@@ -326,14 +325,31 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
 
                                        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();
 
@@ -373,7 +389,7 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
         * @param pg
         *            the optional progress reporter
         * 
-        * @return the {@link Chapter}
+        * @return the {@link Chapter}, never NULL
         * 
         * @throws IOException
         *             in case of I/O error
@@ -429,7 +445,7 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
         * @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
@@ -447,7 +463,6 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
                }
 
                List<Paragraph> paras = new ArrayList<Paragraph>();
-
                if (content != null && !content.trim().isEmpty()) {
                        if (isHtml()) {
                                String[] tab = content.split("(<p>|</p>|<br>|<br/>)");
@@ -512,7 +527,7 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
         * @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;
@@ -862,7 +877,7 @@ public abstract class BasicSupport_Deprecated extends BasicSupport {
         * @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();
index a6188ec55085467b1306f5a9ac91e0083bdf014d..7fe496d97ea8acb9e8869bb41c37d6723e19a636 100644 (file)
@@ -168,7 +168,7 @@ class Cbz extends Epub {
                        }
 
                        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) {
index 03c1557432194187cb54e2b43e9f4239d42c1668..3c734329e3bac03e456665958b6699cc623b3ff8 100644 (file)
@@ -54,7 +54,7 @@ class EHentai extends BasicSupport_Deprecated {
                // 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());
                }
@@ -118,7 +118,7 @@ class EHentai extends BasicSupport_Deprecated {
                        } else if (langLine.equalsIgnoreCase("French")) {
                                lang = "fr";
                        } else {
-                               // TODO find the code?
+                               // TODO find the code for other languages?
                                lang = langLine;
                        }
                }
index 90a9f458e4fd3ce9c0f8ad331bc407a27dc760ca..965a27affda88bfe8919e744b80962f58c3aa465 100644 (file)
@@ -7,6 +7,8 @@ import java.net.URISyntaxException;
 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;
 
@@ -107,6 +109,7 @@ class Epub extends InfoText {
                                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)) {
@@ -115,7 +118,7 @@ class Epub extends InfoText {
                                                }
                                        }
 
-                                       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")) {
@@ -123,7 +126,7 @@ class Epub extends InfoText {
                                                IOUtils.write(zipIn, tmpInfo);
                                        } else if (imageEntry) {
                                                // Cover
-                                               if (getCover()) {
+                                               if (getCover() && cover == null) {
                                                        try {
                                                                cover = new Image(zipIn);
                                                        } catch (Exception e) {
@@ -131,21 +134,19 @@ class Epub extends InfoText {
                                                                                .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");
@@ -172,7 +173,7 @@ class Epub extends InfoText {
                                }
                        }
 
-                       if (requireInfo() && (!tmp.exists() || !tmpInfo.exists())) {
+                       if (requireInfo() && !tmp.exists()) {
                                throw new IOException(
                                                "file not supported (maybe not created with this program or corrupt)");
                        }
@@ -187,21 +188,27 @@ class Epub extends InfoText {
                        } 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) {
index 282192e065bb82fd238c06b863d0e9a3647f4917..16b44f806de8b1df604a0f5e0637a017f39d8ce2 100644 (file)
@@ -45,7 +45,7 @@ class Fanfiction extends BasicSupport_Deprecated {
                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);
index 206464f45a0a2e7c989e6fa6719afa22ca61c9cb..d5eeeb1d9190a022db4bf360cb243710decc493e 100644 (file)
@@ -48,7 +48,6 @@ public class InfoReader {
                                                meta.getUrl())) {
 
                                        // TODO: not nice, would be better to do it properly...
-
                                        String base = infoFile.getPath();
                                        if (base.endsWith(".info")) {
                                                base = base.substring(0,
@@ -62,45 +61,8 @@ public class InfoReader {
                                                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;
@@ -113,6 +75,60 @@ public class InfoReader {
                                "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.
index ade797fbf71ae3182a05ced4a6f0fdbb74b1f118..232eab6ec4f7736b6b470011f51d09548fe733e8 100644 (file)
@@ -102,7 +102,7 @@ class Text extends BasicSupport {
        }
 
        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
@@ -128,14 +128,14 @@ class Text extends BasicSupport {
        }
 
        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();
@@ -151,7 +151,7 @@ class Text extends BasicSupport {
        }
 
        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();
@@ -215,12 +215,13 @@ class Text extends BasicSupport {
        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(':');
@@ -232,10 +233,8 @@ class Text extends BasicSupport {
                                                chapName, //
                                                getSourceFile().toURI().toURL()));
                        }
-
-                       prevLineEmpty = line.trim().isEmpty();
                }
-
+               
                return chaps;
        }
 
@@ -243,17 +242,27 @@ class Text extends BasicSupport {
        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");
                        }