From e992c260c059c53c4aabc980db85efd58f190205 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 17 May 2020 22:02:52 +0200 Subject: [PATCH] update from master --- data/MetaData.java | 18 + library/BasicLibrary.java | 4 + library/LocalLibrary.java | 12 + library/WebLibraryServerHtml.java | 494 +++++++++--------- library/web/index.post.html | 2 - library/web/index.pre.html | 6 +- library/web/package-info.java | 1 + library/web/style.css | 4 +- .../templates/WebLibraryServerTemplates.java | 4 + library/web/templates/bookline.html | 1 + library/web/templates/browser.html | 18 + library/web/templates/browser.option.html | 1 + library/web/templates/browser.select.html | 3 + library/web/templates/index.banner.html | 5 + library/web/templates/index.post.html | 2 + library/web/templates/package-info.java | 1 + library/web/templates/viewer.desc.html | 9 + library/web/templates/viewer.descline.html | 1 + library/web/templates/viewer.image.html | 6 + library/web/templates/viewer.link.html | 1 + library/web/templates/viewer.navbar.html | 11 + .../templates/viewer.optionbar.button.html | 1 + library/web/templates/viewer.optionbar.html | 2 + library/web/templates/viewer.text.html | 4 + output/BasicOutput.java | 6 - output/InfoCover.java | 97 +++- reader/TextOutput.java | 14 + supported/BasicSupportPara.java | 13 +- supported/InfoReader.java | 39 +- supported/Text.java | 17 +- 30 files changed, 495 insertions(+), 302 deletions(-) delete mode 100644 library/web/index.post.html create mode 100644 library/web/package-info.java create mode 100644 library/web/templates/WebLibraryServerTemplates.java create mode 100644 library/web/templates/bookline.html create mode 100644 library/web/templates/browser.html create mode 100644 library/web/templates/browser.option.html create mode 100644 library/web/templates/browser.select.html create mode 100644 library/web/templates/index.banner.html create mode 100644 library/web/templates/index.post.html create mode 100644 library/web/templates/package-info.java create mode 100644 library/web/templates/viewer.desc.html create mode 100644 library/web/templates/viewer.descline.html create mode 100644 library/web/templates/viewer.image.html create mode 100644 library/web/templates/viewer.link.html create mode 100644 library/web/templates/viewer.navbar.html create mode 100644 library/web/templates/viewer.optionbar.button.html create mode 100644 library/web/templates/viewer.optionbar.html create mode 100644 library/web/templates/viewer.text.html diff --git a/data/MetaData.java b/data/MetaData.java index bcebf75..2e34ef9 100644 --- a/data/MetaData.java +++ b/data/MetaData.java @@ -9,6 +9,12 @@ import be.nikiroo.utils.StringUtils; /** * The meta data associated to a {@link Story} object. + *

+ * Note that some earlier version of the program did not save the resume as an + * external file; for those stories, the resume is not fetched until the story + * is. + *

+ * The cover is never fetched until the story is. * * @author niki */ @@ -120,6 +126,10 @@ public class MetaData implements Cloneable, Comparable, Serializable { * The story resume (a.k.a. description). *

* This can be NULL if we don't have a resume for this {@link Story}. + *

+ * Note that some earlier version of the program did not save the resume as + * an external file; for those stories, the resume is not fetched until the + * story is. * * @return the resume */ @@ -129,6 +139,10 @@ public class MetaData implements Cloneable, Comparable, Serializable { /** * The story resume (a.k.a. description). + *

+ * Note that some earlier version of the program did not save the resume as + * an external file; for those stories, the resume is not fetched until the + * story is. * * @param resume * the resume to set @@ -139,6 +153,8 @@ public class MetaData implements Cloneable, Comparable, Serializable { /** * The cover image of the story if any (can be NULL). + *

+ * The cover is not fetched until the story is. * * @return the cover */ @@ -148,6 +164,8 @@ public class MetaData implements Cloneable, Comparable, Serializable { /** * The cover image of the story if any (can be NULL). + *

+ * The cover is not fetched until the story is. * * @param cover * the cover to set diff --git a/library/BasicLibrary.java b/library/BasicLibrary.java index 8b72f19..f77d0ed 100644 --- a/library/BasicLibrary.java +++ b/library/BasicLibrary.java @@ -475,6 +475,8 @@ abstract public class BasicLibrary { /** * Retrieve a specific {@link Story}. + *

+ * Note that it will update both the cover and the resume in meta. * * @param luid * the Library UID of the story @@ -513,6 +515,8 @@ abstract public class BasicLibrary { /** * Retrieve a specific {@link Story}. + *

+ * Note that it will update both the cover and the resume in meta. * * @param luid * the LUID of the story diff --git a/library/LocalLibrary.java b/library/LocalLibrary.java index f655d4d..25f2ec9 100644 --- a/library/LocalLibrary.java +++ b/library/LocalLibrary.java @@ -625,6 +625,18 @@ public class LocalLibrary extends BasicLibrary { files.add(coverFile); } + String summaryExt = ".summary"; + File summaryFile = new File(path + summaryExt); + if (!summaryFile.exists()) { + summaryFile = new File( + path.substring(0, path.length() - fileExt.length()) + + summaryExt); + } + + if (summaryFile.exists()) { + files.add(summaryFile); + } + return files; } diff --git a/library/WebLibraryServerHtml.java b/library/WebLibraryServerHtml.java index 8895fb8..69d8671 100644 --- a/library/WebLibraryServerHtml.java +++ b/library/WebLibraryServerHtml.java @@ -22,6 +22,7 @@ import be.nikiroo.fanfix.data.Paragraph.ParagraphType; import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.library.WebLibraryServer.WLoginResult; import be.nikiroo.fanfix.library.web.WebLibraryServerIndex; +import be.nikiroo.fanfix.library.web.templates.WebLibraryServerTemplates; import be.nikiroo.fanfix.reader.TextOutput; import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.NanoHTTPD; @@ -173,13 +174,13 @@ abstract class WebLibraryServerHtml implements Runnable { } Response rep = null; - if (!login.isSuccess() - && WebLibraryUrls.isSupportedUrl(uri, true)) { - rep = loginPage(login, uri); - } + try { + if (!login.isSuccess() + && WebLibraryUrls.isSupportedUrl(uri, true)) { + rep = loginPage(login, uri); + } - if (rep == null) { - try { + if (rep == null) { if (WebLibraryUrls.isSupportedUrl(uri, false)) { if (WebLibraryUrls.INDEX_URL.equals(uri)) { rep = root(session, cookies, login); @@ -253,13 +254,12 @@ abstract class WebLibraryServerHtml implements Runnable { NanoHTTPD.MIME_PLAINTEXT, "Not Found"); } } - } catch (Exception e) { - Instance.getInstance().getTraceHandler().error( - new IOException("Cannot process web request", - e)); - rep = newFixedLengthResponse(Status.INTERNAL_ERROR, - NanoHTTPD.MIME_PLAINTEXT, "An error occured"); } + } catch (Exception e) { + Instance.getInstance().getTraceHandler().error( + new IOException("Cannot process web request", e)); + rep = newFixedLengthResponse(Status.INTERNAL_ERROR, + NanoHTTPD.MIME_PLAINTEXT, "An error occured"); } return rep; @@ -309,31 +309,34 @@ abstract class WebLibraryServerHtml implements Runnable { this.tracer = tracer; } - private Response loginPage(WLoginResult login, String uri) { + private Response loginPage(WLoginResult login, String uri) + throws IOException { StringBuilder builder = new StringBuilder(); - appendPreHtml(builder, true); + builder.append(getTemplateIndexPreBanner(true)); if (login.isBadLogin()) { - builder.append("

Bad login or password
"); + builder.append( + "\t\t
Bad login or password
"); } else if (login.isBadCookie()) { - builder.append("
Your session timed out
"); + builder.append( + "\t\t
Your session timed out
"); } if (WebLibraryUrls.LOGOUT_URL.equals(uri)) { uri = WebLibraryUrls.INDEX_URL; } + builder.append("\t\t
\n"); builder.append( - "\n"); - builder.append( - "

You must be logged into the system to see the stories.

"); - builder.append("\t\n"); - builder.append("\t\n"); - builder.append("\t\n"); - builder.append("
\n"); + "\t\t\t

You must be logged into the system to see the stories.

"); + builder.append("\t\t\t\n"); + builder.append("\t\t\t\n"); + builder.append("\t\t\t\n"); + builder.append("\t\t\n"); - appendPostHtml(builder); + builder.append(getTemplate("index.post")); return NanoHTTPD.newFixedLengthResponse(Status.FORBIDDEN, NanoHTTPD.MIME_HTML, builder.toString()); @@ -345,7 +348,7 @@ abstract class WebLibraryServerHtml implements Runnable { MetaResultList result = new MetaResultList(metas(login)); StringBuilder builder = new StringBuilder(); - appendPreHtml(builder, true); + builder.append(getTemplateIndexPreBanner(true)); Map params = session.getParms(); @@ -369,45 +372,56 @@ abstract class WebLibraryServerHtml implements Runnable { // TODO: javascript in realtime, using visible=false + hide [submit] - builder.append("
\n"); - builder.append("\n"); + String sel = "selected='selected'"; + builder.append(getTemplate("browser") // + .replace("${sourcesSelected}", sourcesSel ? sel : "") // + .replace("${authorsSelected}", authorsSel ? sel : "") // + .replace("${tagsSelected}", tagsSel ? sel : "") // + .replace("${filter}", filter) // + .replace("${selects}", selects.toString()) // + ); - // TODO: javascript in realtime, using visible=false + hide [submit] - builder.append("
\n"); - builder.append("\tFilter: \n"); - builder.append( - "\t\n"); - builder.append("\t\n"); - builder.append("\t"); - builder.append( - "\t\n"); - builder.append("
\n"); - builder.append("
\n"); - - builder.append("\t
"); + builder.append("\t\t
\n"); for (MetaData meta : result.getMetas()) { if (!filter.isEmpty() && !meta.getTitle().toLowerCase() .contains(filter.toLowerCase())) { @@ -478,38 +487,33 @@ abstract class WebLibraryServerHtml implements Runnable { continue; } - builder.append("\n"); + + builder.append(getTemplate("bookline") // + .replace("${href}", + WebLibraryUrls.getViewUrl(meta.getLuid(), null, + null)) // + .replace("${luid}", meta.getLuid()) // + .replace("${title}", meta.getTitle()) // + .replace("${author}", author) // + .replace("${cachedClass}", cachedClass) // + .replace("${cached}", cached) // + ); } - builder.append("
"); + builder.append("\t\t
\n"); + + builder.append(getTemplate("index.post")); - appendPostHtml(builder); return NanoHTTPD.newFixedLengthResponse(builder.toString()); } @@ -563,9 +567,6 @@ abstract class WebLibraryServerHtml implements Runnable { NanoHTTPD.MIME_PLAINTEXT, "Story not found"); } - StringBuilder builder = new StringBuilder(); - appendPreHtml(builder, false); - // For images documents, always go to the images if not chap 0 desc if (story.getMeta().isImageDocument()) { if (chapter > 0 && paragraph <= 0) @@ -586,7 +587,7 @@ abstract class WebLibraryServerHtml implements Runnable { String first, previous, next, last; - StringBuilder content = new StringBuilder(); + String viewer = ""; String disabledLeft = ""; String disabledRight = ""; @@ -604,35 +605,37 @@ abstract class WebLibraryServerHtml implements Runnable { last = WebLibraryUrls.getViewUrl(luid, story.getChapters().size(), null); - StringBuilder desc = new StringBuilder(); - + String desc = ""; if (chapter <= 0) { - desc.append("

"); - desc.append(story.getMeta().getTitle()); - desc.append("

\n"); - desc.append("
\n"); - desc.append("\t\n"); - desc.append("\t\t\n"); - desc.append("\t\n"); - desc.append("\t\n"); + StringBuilder desclines = new StringBuilder(); Map details = BasicLibrary .getMetaDesc(story.getMeta()); for (String key : details.keySet()) { - appendTableRow(desc, 2, key, details.get(key)); + desclines.append(getTemplate("viewer.descline") // + .replace("${key}", key) // + .replace("${value}", details.get(key)) // + ); } - desc.append("\t
\n"); - desc.append("
\n"); - desc.append("

Description

\n"); + + desc = getTemplate("viewer.desc") // + .replace("${title}", story.getMeta().getTitle()) // + .replace("${href}", next) // + .replace("${cover}", + WebLibraryUrls.getStoryUrlCover(luid)) // + .replace("${details}", desclines.toString()) // + ; } - content.append("
\n"); - content.append(desc); - String description = new TextOutput(false).convert(chap, - chapter > 0); - content.append(chap.getParagraphs().size() <= 0 - ? "No content provided." - : description); - content.append("
\n"); + viewer = getTemplate("viewer.text") // + .replace("${desc}", desc) // + ; + if (chap.getParagraphs().size() <= 0) { + viewer = viewer.replace("${content}", + "No content provided."); + } else { + viewer = viewer.replace("${content}", + new TextOutput(false).convert(chap, chapter > 0)); + } if (chapter <= 0) disabledLeft = " disabled='disbaled'"; @@ -689,44 +692,39 @@ abstract class WebLibraryServerHtml implements Runnable { } } - String javascript = "document.getElementById(\"previous\").click(); return false;"; - content.append(String.format("" // - + "" - + "" - + "", // - javascript, // - next, // - zoomStyle, // - WebLibraryUrls.getStoryUrl(luid, chapter, - paragraph))); + viewer = getTemplate("viewer.image") // + .replace("${href}", next) // + .replace("${zoomStyle}", zoomStyle) // + .replace("${src}", WebLibraryUrls.getStoryUrl(luid, + chapter, paragraph)) // + ; } else { - content.append(String.format("" // - + "
%s
", // - para.getContent())); + viewer = getTemplate("viewer.text") // + .replace("${desc}", "") // + .replace("${content}", + new TextOutput(false).convert(para)) // + ; } } - builder.append(String.format("" // - + "\n", // - disabledRight, next, // - disabledRight, last // - )); - - builder.append(content); + // Buttons on the optionbar - builder.append("
\n"); - builder.append(" BACK\n"); - if (paragraph > 0) { - builder.append(String.format("" // - + "\tREAL\n"// - + "\tWIDTH\n"// - + "\tHEIGHT\n"// - + "
\n", // - disabledZoomReal, - uri + "?optionName=zoom&optionValue=real", // - disabledZoomWidth, - uri + "?optionName=zoom&optionValue=width", // - disabledZoomHeight, - uri + "?optionName=zoom&optionValue=height" // - )); - } + // Full content + + StringBuilder builder = new StringBuilder(); + + builder.append(getTemplateIndexPreBanner(false)); + + builder.append(getTemplate("viewer.navbar") // + .replace("${disabledFirst}", disabledLeft) // + .replace("${disabledPrevious}", disabledLeft) // + .replace("${disabledNext}", disabledRight) // + .replace("${disabledLast}", disabledRight) // + .replace("${hrefFirst}", first) // + .replace("${hrefPrevious}", previous) // + .replace("${hrefNext}", next) // + .replace("${hrefLast}", last) // + .replace("${current}", + "" + (paragraph > 0 ? paragraph : chapter)) // + .replace("${links}", links.toString()) // + ); + + builder.append(viewer); + + builder.append(getTemplate("viewer.optionbar") // + .replace("${classSize}", (paragraph > 0 ? "s4" : "s1")) // + .replace("${buttons}", buttons.toString()) // + ); + + builder.append(getTemplate("index.post")); - appendPostHtml(builder); return NanoHTTPD.newFixedLengthResponse(Status.OK, NanoHTTPD.MIME_HTML, builder.toString()); } catch (IOException e) { @@ -799,22 +825,8 @@ abstract class WebLibraryServerHtml implements Runnable { return NanoHTTPD.newChunkedResponse(Status.OK, mimeType, in); } - private String getContentOf(String file) { - InputStream in = IOUtils.openResource(WebLibraryServerIndex.class, - file); - if (in != null) { - try { - return IOUtils.readSmallStream(in); - } catch (IOException e) { - Instance.getInstance().getTraceHandler().error( - new IOException("Cannot get file: index.pre.html", e)); - } - } - - return ""; - } - - private void appendPreHtml(StringBuilder builder, boolean banner) { + private String getTemplateIndexPreBanner(boolean banner) + throws IOException { String favicon = "favicon.ico"; String icon = Instance.getInstance().getUiConfig() .getString(UiConfig.PROGRAM_ICON); @@ -822,70 +834,44 @@ abstract class WebLibraryServerHtml implements Runnable { favicon = "icon_" + icon.replace("-", "_") + ".png"; } - builder.append( - getContentOf("index.pre.html").replace("favicon.ico", favicon)); + String html = getTemplate("index.pre") // + .replace("${title}", "Fanfix") // + .replace("${favicon}", favicon) // + ; if (banner) { - builder.append("\n"); + html += getTemplate("index.banner") // + .replace("${favicon}", favicon) // + .replace("${version}", + Version.getCurrentVersion().toString()) // + ; } - } - private void appendPostHtml(StringBuilder builder) { - builder.append(getContentOf("index.post.html")); + return html; } - private void appendOption(StringBuilder builder, int depth, String name, - String value, String selected) { - for (int i = 0; i < depth; i++) { - builder.append("\t"); - } - builder.append("\n"); - } - - private void appendTableRow(StringBuilder builder, int depth, - String... tds) { - for (int i = 0; i < depth; i++) { - builder.append("\t"); + selectedAttribute = " selected='selected'"; } - int col = 1; - builder.append(""); - for (String td : tds) { - builder.append(""); - builder.append(td); - builder.append(""); - } - builder.append("\n"); + return getTemplate("browser.option" // + .replace("${value}", value) // + .replace("${selected}", selectedAttribute) // + .replace("${name}", name) // + ); } - private void appendItemA(StringBuilder builder, int depth, String link, - String name, boolean selected) { - for (int i = 0; i < depth; i++) { - builder.append("\t"); - } - - builder.append(""); - builder.append(name); - builder.append("\n"); } } diff --git a/library/web/index.post.html b/library/web/index.post.html deleted file mode 100644 index d4e0905..0000000 --- a/library/web/index.post.html +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/library/web/index.pre.html b/library/web/index.pre.html index 18c1508..1e626ab 100644 --- a/library/web/index.pre.html +++ b/library/web/index.pre.html @@ -40,9 +40,9 @@ --> - Fanfix + ${title} - + -
+
diff --git a/library/web/package-info.java b/library/web/package-info.java new file mode 100644 index 0000000..69bff54 --- /dev/null +++ b/library/web/package-info.java @@ -0,0 +1 @@ +package be.nikiroo.fanfix.library.web; \ No newline at end of file diff --git a/library/web/style.css b/library/web/style.css index 4196aeb..b12a24f 100644 --- a/library/web/style.css +++ b/library/web/style.css @@ -310,13 +310,13 @@ a.viewer.link:hover { display: block; } -.desc .details .col1 { +.desc .details .col.key { font-weight: bold; padding-left: 5px; padding-right: 5px; } -.desc .details .col2 { +.desc .details .col.value { color: #AAA391; } diff --git a/library/web/templates/WebLibraryServerTemplates.java b/library/web/templates/WebLibraryServerTemplates.java new file mode 100644 index 0000000..482a1b8 --- /dev/null +++ b/library/web/templates/WebLibraryServerTemplates.java @@ -0,0 +1,4 @@ +package be.nikiroo.fanfix.library.web.templates; + +public class WebLibraryServerTemplates { +} diff --git a/library/web/templates/bookline.html b/library/web/templates/bookline.html new file mode 100644 index 0000000..9b1a6b7 --- /dev/null +++ b/library/web/templates/bookline.html @@ -0,0 +1 @@ + diff --git a/library/web/templates/browser.html b/library/web/templates/browser.html new file mode 100644 index 0000000..f3f3047 --- /dev/null +++ b/library/web/templates/browser.html @@ -0,0 +1,18 @@ +
+ +
+ Filter: + + + + +
+
diff --git a/library/web/templates/browser.option.html b/library/web/templates/browser.option.html new file mode 100644 index 0000000..49f7b5b --- /dev/null +++ b/library/web/templates/browser.option.html @@ -0,0 +1 @@ + diff --git a/library/web/templates/browser.select.html b/library/web/templates/browser.select.html new file mode 100644 index 0000000..447d845 --- /dev/null +++ b/library/web/templates/browser.select.html @@ -0,0 +1,3 @@ + diff --git a/library/web/templates/index.banner.html b/library/web/templates/index.banner.html new file mode 100644 index 0000000..c2cd1e7 --- /dev/null +++ b/library/web/templates/index.banner.html @@ -0,0 +1,5 @@ + diff --git a/library/web/templates/index.post.html b/library/web/templates/index.post.html new file mode 100644 index 0000000..52ba19e --- /dev/null +++ b/library/web/templates/index.post.html @@ -0,0 +1,2 @@ +
+ \ No newline at end of file diff --git a/library/web/templates/package-info.java b/library/web/templates/package-info.java new file mode 100644 index 0000000..5d4f3b2 --- /dev/null +++ b/library/web/templates/package-info.java @@ -0,0 +1 @@ +package be.nikiroo.fanfix.library.web.templates; \ No newline at end of file diff --git a/library/web/templates/viewer.desc.html b/library/web/templates/viewer.desc.html new file mode 100644 index 0000000..21cddc4 --- /dev/null +++ b/library/web/templates/viewer.desc.html @@ -0,0 +1,9 @@ +

${title}

+
+ + + + +${details}
+
+

Description

diff --git a/library/web/templates/viewer.descline.html b/library/web/templates/viewer.descline.html new file mode 100644 index 0000000..9d61987 --- /dev/null +++ b/library/web/templates/viewer.descline.html @@ -0,0 +1 @@ + ${key}${value} diff --git a/library/web/templates/viewer.image.html b/library/web/templates/viewer.image.html new file mode 100644 index 0000000..2416516 --- /dev/null +++ b/library/web/templates/viewer.image.html @@ -0,0 +1,6 @@ + + + diff --git a/library/web/templates/viewer.link.html b/library/web/templates/viewer.link.html new file mode 100644 index 0000000..5812c80 --- /dev/null +++ b/library/web/templates/viewer.link.html @@ -0,0 +1 @@ + ${name} diff --git a/library/web/templates/viewer.navbar.html b/library/web/templates/viewer.navbar.html new file mode 100644 index 0000000..59f35be --- /dev/null +++ b/library/web/templates/viewer.navbar.html @@ -0,0 +1,11 @@ + diff --git a/library/web/templates/viewer.optionbar.button.html b/library/web/templates/viewer.optionbar.button.html new file mode 100644 index 0000000..b85f9a9 --- /dev/null +++ b/library/web/templates/viewer.optionbar.button.html @@ -0,0 +1 @@ + ${value} diff --git a/library/web/templates/viewer.optionbar.html b/library/web/templates/viewer.optionbar.html new file mode 100644 index 0000000..1d1eaec --- /dev/null +++ b/library/web/templates/viewer.optionbar.html @@ -0,0 +1,2 @@ +
+${buttons}
diff --git a/library/web/templates/viewer.text.html b/library/web/templates/viewer.text.html new file mode 100644 index 0000000..4562ea4 --- /dev/null +++ b/library/web/templates/viewer.text.html @@ -0,0 +1,4 @@ +
+${desc} + ${content} +
diff --git a/output/BasicOutput.java b/output/BasicOutput.java index 41634fa..62a008c 100644 --- a/output/BasicOutput.java +++ b/output/BasicOutput.java @@ -299,27 +299,21 @@ public abstract class BasicOutput { return ""; } - @SuppressWarnings("unused") protected void writeStoryHeader(Story story) throws IOException { } - @SuppressWarnings("unused") protected void writeChapterHeader(Chapter chap) throws IOException { } - @SuppressWarnings("unused") protected void writeParagraphHeader(Paragraph para) throws IOException { } - @SuppressWarnings("unused") protected void writeStoryFooter(Story story) throws IOException { } - @SuppressWarnings("unused") protected void writeChapterFooter(Chapter chap) throws IOException { } - @SuppressWarnings("unused") protected void writeParagraphFooter(Paragraph para) throws IOException { } diff --git a/output/InfoCover.java b/output/InfoCover.java index d8ca49a..fe530a8 100644 --- a/output/InfoCover.java +++ b/output/InfoCover.java @@ -5,22 +5,45 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; +import java.util.Arrays; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.bundles.Config; +import be.nikiroo.fanfix.data.Chapter; import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.fanfix.data.Story; +/** + * Helper class to write info, cover and summary (resume) files. + * + * @author niki + */ public class InfoCover { + /** + * Write both the .info and the .summary files by taking + * the information from the {@link MetaData}. + * + * @param targetDir + * the directory where to write the 2 files + * @param targetName + * the target name (no extension) to use (so you will get + * targetName.info and targetName.summary) + * @param meta + * the {@link MetaData} to get the data out of + * + * @throws IOException + * in case of I/O error + */ public static void writeInfo(File targetDir, String targetName, MetaData meta) throws IOException { File info = new File(targetDir, targetName + ".info"); - BufferedWriter infoWriter = null; - try { - infoWriter = new BufferedWriter(new OutputStreamWriter( - new FileOutputStream(info), "UTF-8")); + if (meta != null) { + BufferedWriter infoWriter = null; + try { + infoWriter = new BufferedWriter(new OutputStreamWriter( + new FileOutputStream(info), "UTF-8")); - if (meta != null) { String tags = ""; if (meta.getTags() != null) { for (String tag : meta.getTags()) { @@ -47,7 +70,8 @@ public class InfoCover { writeMeta(infoWriter, "TYPE", meta.getType()); if (meta.getCover() != null) { String format = Instance.getInstance().getConfig() - .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase(); + .getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER) + .toLowerCase(); writeMeta(infoWriter, "COVER", targetName + "." + format); } else { writeMeta(infoWriter, "COVER", ""); @@ -59,14 +83,69 @@ public class InfoCover { writeMeta(infoWriter, "CREATION_DATE", meta.getCreationDate()); writeMeta(infoWriter, "FAKE_COVER", Boolean.toString(meta.isFakeCover())); + } finally { + if (infoWriter != null) { + infoWriter.close(); + } } - } finally { - if (infoWriter != null) { - infoWriter.close(); + + if (meta.getResume() != null) { + Story fakeStory = new Story(); + fakeStory.setMeta(meta); + fakeStory.setChapters(Arrays.asList(meta.getResume())); + + Text summaryText = new Text() { + @Override + protected boolean isWriteCover() { + return false; + } + + @Override + protected boolean isWriteInfo() { + return false; // infinite loop if not! + } + + @Override + public String getDefaultExtension(boolean readerTarget) { + return ".summary"; + } + + @Override + protected void writeStoryHeader(Story story) + throws IOException { + } + + @Override + protected void writeStoryFooter(Story story) + throws IOException { + } + + @Override + protected void writeChapterHeader(Chapter chap) + throws IOException { + } + + @Override + protected void writeChapterFooter(Chapter chap) + throws IOException { + } + }; + + summaryText.process(fakeStory, targetDir, targetName); } } } + /** + * Write the cover file. + * + * @param targetDir + * the target directory + * @param targetName + * the target name for the cover (the extension will be added) + * @param meta + * the meta to get the information out of + */ public static void writeCover(File targetDir, String targetName, MetaData meta) { if (meta != null && meta.getCover() != null) { diff --git a/reader/TextOutput.java b/reader/TextOutput.java index 60b3a7f..732fced 100644 --- a/reader/TextOutput.java +++ b/reader/TextOutput.java @@ -145,4 +145,18 @@ public class TextOutput { } return builder.toString(); } + + /** + * Convert the paragraph into HTML3 code. + * + * @param para + * the {@link Paragraph} to convert + * + * @return HTML3 code tested with Java Swing + */ + public String convert(Paragraph para) { + Chapter fakeChapter = new Chapter(0, ""); + fakeChapter.setParagraphs(Arrays.asList(para)); + return convert(fakeChapter, false); + } } diff --git a/supported/BasicSupportPara.java b/supported/BasicSupportPara.java index 1dbedc9..e550d82 100644 --- a/supported/BasicSupportPara.java +++ b/supported/BasicSupportPara.java @@ -35,6 +35,17 @@ public class BasicSupportPara { BasicSupportHelper bsHelper; BasicSupportImages bsImages; + /** + * Create a new {@link BasicSupportPara}. + *

+ * Note that you need an instance of both {@link BasicSupportHelper} and + * {@link BasicSupportImages} for it to work. + * + * @param bsHelper + * the required {@link BasicSupportHelper} + * @param bsImages + * the required {@link BasicSupportImages} + */ public BasicSupportPara(BasicSupportHelper bsHelper, BasicSupportImages bsImages) { this.bsHelper = bsHelper; this.bsImages = bsImages; @@ -45,7 +56,7 @@ public class BasicSupportPara { * the content as it should be. * * @param support - * the linked {@link BasicSupport} + * the linked {@link BasicSupport} (can be NULL) * @param source * the source of the story (for image lookup in the same path if * the source is a file, can be NULL) diff --git a/supported/InfoReader.java b/supported/InfoReader.java index d5eeeb1..22afc92 100644 --- a/supported/InfoReader.java +++ b/supported/InfoReader.java @@ -11,27 +11,30 @@ import java.util.Scanner; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.bundles.Config; +import be.nikiroo.fanfix.data.Chapter; import be.nikiroo.fanfix.data.MetaData; +import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.Image; import be.nikiroo.utils.streams.MarkableFileInputStream; -// not complete: no "description" tag public class InfoReader { static protected BasicSupportHelper bsHelper = new BasicSupportHelper(); - // static protected BasicSupportImages bsImages = new BasicSupportImages(); - // static protected BasicSupportPara bsPara = new BasicSupportPara(new - // BasicSupportHelper(), new BasicSupportImages()); + static protected BasicSupportImages bsImages = new BasicSupportImages(); + static protected BasicSupportPara bsPara = new BasicSupportPara( + new BasicSupportHelper(), new BasicSupportImages()); public static MetaData readMeta(File infoFile, boolean withCover) throws IOException { if (infoFile == null) { throw new IOException("File is null"); } + + MetaData meta = null; if (infoFile.exists()) { InputStream in = new MarkableFileInputStream(infoFile); try { - MetaData meta = createMeta(infoFile.toURI().toURL(), in, + meta = createMeta(infoFile.toURI().toURL(), in, withCover); // Some old .info files were using UUID for URL... @@ -46,8 +49,6 @@ public class InfoReader { // formats have a copy of the original text file) if (!hasIt(meta.getTitle(), meta.getAuthor(), meta.getDate(), 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,15 +63,34 @@ public class InfoReader { } completeMeta(textFile, meta); - // } - return meta; + } finally { in.close(); } } + if (meta != null) { + try { + File summaryFile = new File(infoFile.getAbsolutePath() + .replaceFirst("\\.info$", ".summary")); + InputStream in = new MarkableFileInputStream(summaryFile); + try { + String content = IOUtils.readSmallStream(in); + Chapter desc = bsPara.makeChapter(null, null, 0, + "Description", content, false, null); + meta.setResume(desc); + } finally { + in.close(); + } + } catch (IOException e) { + // ignore absent or bad summary + } + + return meta; + } + throw new FileNotFoundException( "File given as argument does not exists: " + infoFile.getAbsolutePath()); @@ -90,6 +110,7 @@ public class InfoReader { */ static public void completeMeta(File textFile, MetaData meta) throws IOException { + // TODO: not nice, would be better to do it properly... if (textFile != null && textFile.exists()) { final URL source = textFile.toURI().toURL(); final MetaData[] superMetaA = new MetaData[1]; diff --git a/supported/Text.java b/supported/Text.java index 232eab6..71e30c3 100644 --- a/supported/Text.java +++ b/supported/Text.java @@ -15,9 +15,7 @@ import org.jsoup.nodes.Document; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.bundles.Config; -import be.nikiroo.fanfix.data.Chapter; import be.nikiroo.fanfix.data.MetaData; -import be.nikiroo.fanfix.data.Paragraph; import be.nikiroo.utils.Image; import be.nikiroo.utils.ImageUtils; import be.nikiroo.utils.Progress; @@ -172,20 +170,7 @@ class Text extends BasicSupport { @Override protected String getDesc() throws IOException { - String content = getChapterContent(null, 0, null).trim(); - if (!content.isEmpty()) { - Chapter desc = bsPara.makeChapter(this, null, 0, "Description", - content, isHtml(), null); - StringBuilder builder = new StringBuilder(); - for (Paragraph para : desc) { - if (builder.length() > 0) { - builder.append("\n"); - } - builder.append(para.getContent()); - } - } - - return content; + return getChapterContent(null, 0, null).trim(); } protected Image getCover(File sourceFile) { -- 2.27.0