From ae78e5179d241ca5e2439048f960fe6d4a07c990 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 3 Dec 2017 18:34:00 +0100 Subject: [PATCH] Android compatibility --- Makefile.base | 53 +++++++----- changelog.md | 5 ++ ...es.jar => nikiroo-utils-4.0.1-sources.jar} | Bin 279694 -> 282403 bytes src/be/nikiroo/fanfix/DataLoader.java | 75 +++++++++++++---- src/be/nikiroo/fanfix/Instance.java | 76 +++++++++++++++--- src/be/nikiroo/fanfix/bundles/Config.java | 38 ++++----- src/be/nikiroo/fanfix/bundles/StringId.java | 16 ++-- src/be/nikiroo/fanfix/bundles/UiConfig.java | 2 +- .../nikiroo/fanfix/bundles/config.properties | 4 +- src/be/nikiroo/fanfix/bundles/ui.properties | 2 +- 10 files changed, 191 insertions(+), 80 deletions(-) rename libs/{nikiroo-utils-4.0.0-sources.jar => nikiroo-utils-4.0.1-sources.jar} (91%) diff --git a/Makefile.base b/Makefile.base index 3304c83..aeebcbd 100644 --- a/Makefile.base +++ b/Makefile.base @@ -1,3 +1,9 @@ +# Makefile base template +# +# Version: +# - 1.0.0: add a version comment +# - 1.1.0: add help, sjar + # Required parameters (the commented out ones are supposed to change per project): #MAIN = path to main java source to compile @@ -17,31 +23,34 @@ JAR = jar RJAR = java RJAR_FLAGS += -jar -# Usual options: -# make : to build the jar file -# make libs : to update the libraries into src/ -# make build : to update the binaries (not the jar) -# make test : to update the test binaries -# make build jar : to update the binaries and jar file -# make clean : to clean the directory of intermediate files -# make mrpropre : to clean the directory of all outputs -# make run : to run the program from the binaries -# make run-test : to run the test program from the binaries -# make jrun : to run the program from the jar file -# make install : to install the application into $PREFIX - -# Note: build is actually slower than rebuild in most cases except when -# small changes only are detected ; so we use rebuild by default - all: build jar -.PHONY: all clean mrproper mrpropre build run jrun jar resources test-resources install libs love +help: + @echo "Usual options:" + @echo "==============" + @echo " make : to build the jar file" + @echo " make help : to get this help screen" + @echo " make libs : to update the libraries into src/" + @echo " make build : to update the binaries (not the jar)" + @echo " make test : to update the test binaries" + @echo " make build jar : to update the binaries and jar file" + @echo " make sjar : to create the sources jar file" + @echo " make clean : to clean the directory of intermediate files" + @echo " make mrpropre : to clean the directory of all outputs" + @echo " make run : to run the program from the binaries" + @echo " make run-test : to run the test program from the binaries" + @echo " make jrun : to run the program from the jar file" + @echo " make install : to install the application into $PREFIX" + +.PHONY: all clean mrproper mrpropre build run jrun jar sjar resources test-resources install libs love bin: @mkdir -p bin jar: $(NAME).jar +sjar: $(NAME)-sources.jar + build: resources @echo Compiling program... @echo " src/$(MAIN)" @@ -118,15 +127,17 @@ libs: bin done ) @[ ! -d libs ] || touch bin/libs -$(NAME).jar: resources - @[ -e bin/$(MAIN).class ] || echo You need to build the sources - @[ -e bin/$(MAIN).class ] - @echo Making JAR file... +$(NAME)-sources.jar: libs + @echo Making sources JAR file... @echo > bin/manifest @[ "$(SJAR_FLAGS)" = "" ] || echo Creating $(NAME)-sources.jar... @[ "$(SJAR_FLAGS)" = "" ] || $(JAR) cfm $(NAME)-sources.jar bin/manifest $(SJAR_FLAGS) @[ "$(SJAR_FLAGS)" = "" ] || [ ! -e VERSION ] || echo Copying to "$(NAME)-`cat VERSION`-sources.jar"... @[ "$(SJAR_FLAGS)" = "" ] || [ ! -e VERSION ] || cp $(NAME)-sources.jar "$(NAME)-`cat VERSION`-sources.jar" + +$(NAME).jar: resources + @[ -e bin/$(MAIN).class ] || echo You need to build the sources + @[ -e bin/$(MAIN).class ] @echo "Main-Class: `echo "$(MAIN)" | sed 's:/:.:g'`" > bin/manifest @echo >> bin/manifest $(JAR) cfm $(NAME).jar bin/manifest $(JAR_FLAGS) diff --git a/changelog.md b/changelog.md index 57aa9b0..ebe3c87 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # Fanfix +# Version WIP + +- Update nikiroo-utils +- Android compatibility + # Version 1.6.3 - Bug fixes diff --git a/libs/nikiroo-utils-4.0.0-sources.jar b/libs/nikiroo-utils-4.0.1-sources.jar similarity index 91% rename from libs/nikiroo-utils-4.0.0-sources.jar rename to libs/nikiroo-utils-4.0.1-sources.jar index 72ad2349c73e1b4c1588223cf5403a3de34debf7..6618209437dc12c91b70c46ca19d5b954d2925f3 100644 GIT binary patch delta 18518 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 diff --git a/src/be/nikiroo/fanfix/DataLoader.java b/src/be/nikiroo/fanfix/DataLoader.java index 222c614..4a42218 100644 --- a/src/be/nikiroo/fanfix/DataLoader.java +++ b/src/be/nikiroo/fanfix/DataLoader.java @@ -9,9 +9,12 @@ import java.util.Map; import be.nikiroo.fanfix.bundles.Config; import be.nikiroo.fanfix.supported.BasicSupport; import be.nikiroo.utils.Cache; +import be.nikiroo.utils.CacheMemory; import be.nikiroo.utils.Downloader; +import be.nikiroo.utils.IOUtils; import be.nikiroo.utils.Image; import be.nikiroo.utils.ImageUtils; +import be.nikiroo.utils.TraceHandler; /** * This cache will manage Internet (and local) downloads, as well as put the @@ -23,8 +26,9 @@ import be.nikiroo.utils.ImageUtils; * @author niki */ public class DataLoader { - private Cache cache; private Downloader downloader; + private Cache downloadCache; + private Cache cache; /** * Create a new {@link DataLoader} object. @@ -47,10 +51,37 @@ public class DataLoader { */ public DataLoader(File dir, String UA, int hoursChanging, int hoursStable) throws IOException { - cache = new Cache(dir, hoursChanging, hoursStable); - cache.setTraceHandler(Instance.getTraceHandler()); downloader = new Downloader(UA); - downloader.setTraceHandler(Instance.getTraceHandler()); + downloadCache = new Cache(dir, hoursChanging, hoursStable); + cache = downloadCache; + } + + /** + * Create a new {@link DataLoader} object without disk cache (will keep a + * memory cache for manual cache operations). + * + * @param UA + * the User-Agent to use to download the resources + */ + public DataLoader(String UA) { + downloader = new Downloader(UA); + downloadCache = null; + cache = new CacheMemory(); + } + + /** + * The traces handler for this {@link Cache}. + * + * @param tracer + * the new traces handler + */ + public void setTraceHandler(TraceHandler tracer) { + downloader.setTraceHandler(tracer); + cache.setTraceHandler(tracer); + if (downloadCache != null) { + downloadCache.setTraceHandler(tracer); + } + } /** @@ -99,17 +130,29 @@ public class DataLoader { URL originalUrl) throws IOException { // MUST NOT return null try { - InputStream in = cache.load(originalUrl, false, stable); - Instance.getTraceHandler().trace( - "Cache " + (in != null ? "hit" : "miss") + ": " + url); + InputStream in = null; + + if (downloadCache != null) { + in = downloadCache.load(originalUrl, false, stable); + Instance.getTraceHandler().trace( + "Cache " + (in != null ? "hit" : "miss") + ": " + url); + } if (in == null) { try { in = openNoCache(url, support, null, null, null); - cache.save(in, originalUrl); - // ..But we want a resetable stream - in.close(); - in = cache.load(originalUrl, false, stable); + if (downloadCache != null) { + downloadCache.save(in, originalUrl); + // ..But we want a resetable stream + in.close(); + in = downloadCache.load(originalUrl, false, stable); + } else { + InputStream resetIn = IOUtils.forceResetableStream(in); + if (resetIn != in) { + in.close(); + in = resetIn; + } + } } catch (IOException e) { throw new IOException("Cannot save the url: " + (url == null ? "null" : url.toString()), e); @@ -193,7 +236,7 @@ public class DataLoader { */ public void refresh(URL url, BasicSupport support, boolean stable) throws IOException { - if (!cache.check(url, false, stable)) { + if (downloadCache != null && !downloadCache.check(url, false, stable)) { open(url, support, stable).close(); } } @@ -211,7 +254,7 @@ public class DataLoader { * */ public boolean check(URL url, boolean stable) { - return cache.check(url, false, stable); + return downloadCache != null && downloadCache.check(url, false, stable); } /** @@ -258,7 +301,6 @@ public class DataLoader { public void saveAsImage(Image img, File target, String format) throws IOException { ImageUtils.getInstance().saveAsImage(img, target, format); - } /** @@ -269,13 +311,12 @@ public class DataLoader { * @param uniqueID * a unique ID for this resource * - * @return the resulting {@link File} * * @throws IOException * in case of I/O error */ - public File addToCache(InputStream in, String uniqueID) throws IOException { - return cache.save(in, uniqueID); + public void addToCache(InputStream in, String uniqueID) throws IOException { + cache.save(in, uniqueID); } /** diff --git a/src/be/nikiroo/fanfix/Instance.java b/src/be/nikiroo/fanfix/Instance.java index 4dde3fa..82f4427 100644 --- a/src/be/nikiroo/fanfix/Instance.java +++ b/src/be/nikiroo/fanfix/Instance.java @@ -38,7 +38,7 @@ public class Instance { static { // Before we can configure it: - tracer = new TraceHandler(true, checkEnv("DEBUG"), false); + tracer = new TraceHandler(true, checkEnv("DEBUG"), checkEnv("DEBUG")); // Most of the rest is dependent upon this: config = new ConfigBundle(); @@ -49,8 +49,7 @@ public class Instance { } if (configDir == null) { - configDir = new File(System.getProperty("user.home"), ".fanfix") - .getPath(); + configDir = new File(getHome(), ".fanfix").getPath(); } if (!new File(configDir).exists()) { @@ -79,8 +78,7 @@ public class Instance { // Fix an old bug (we used to store custom translation files by // default): if (trans.getString(StringId.INPUT_DESC_CBZ) == null) { - // TODO: create the deleteFile method - // trans.deleteFile(configDir); + trans.deleteFile(configDir); } Bundles.setDirectory(configDir); @@ -103,6 +101,7 @@ public class Instance { if (checkEnv("DEBUG")) { debug = true; + trace = true; } tracer = new TraceHandler(true, debug, trace); @@ -140,8 +139,7 @@ public class Instance { if (lib == null) { tracer.error(new IOException( - "Cannot create remote library for: " - + getFile(Config.DEFAULT_LIBRARY))); + "Cannot create remote library for: " + remoteLib)); } } @@ -161,17 +159,19 @@ public class Instance { coverDir = null; } + String ua = config.getString(Config.USER_AGENT); try { - String ua = config.getString(Config.USER_AGENT); int hours = config.getInteger(Config.CACHE_MAX_TIME_CHANGING, -1); int hoursLarge = config .getInteger(Config.CACHE_MAX_TIME_STABLE, -1); - cache = new DataLoader(tmp, ua, hours, hoursLarge); } catch (IOException e) { tracer.error(new IOException( "Cannot create cache (will continue without cache)", e)); + cache = new DataLoader(ua); } + + cache.setTraceHandler(tracer); } /** @@ -197,6 +197,7 @@ public class Instance { } Instance.tracer = tracer; + cache.setTraceHandler(tracer); } /** @@ -217,6 +218,42 @@ public class Instance { return uiconfig; } + /** + * Reset the configuration. + * + * @param resetTrans + * also reset the translation files + */ + public static void resetConfig(boolean resetTrans) { + String dir = Bundles.getDirectory(); + Bundles.setDirectory(null); + try { + try { + ConfigBundle config = new ConfigBundle(); + config.updateFile(configDir); + } catch (IOException e) { + tracer.error(e); + } + try { + UiConfigBundle uiconfig = new UiConfigBundle(); + uiconfig.updateFile(configDir); + } catch (IOException e) { + tracer.error(e); + } + + if (resetTrans) { + try { + StringIdBundle trans = new StringIdBundle(null); + trans.updateFile(configDir); + } catch (IOException e) { + tracer.error(e); + } + } + } finally { + Bundles.setDirectory(dir); + } + } + /** * Get the (unique) {@link DataLoader} for the program. * @@ -353,8 +390,7 @@ public class Instance { if (path != null && !path.isEmpty()) { path = path.replace('/', File.separatorChar); if (path.contains("$HOME")) { - path = path.replace("$HOME", - "" + System.getProperty("user.home")); + path = path.replace("$HOME", getHome()); } file = new File(path); @@ -363,6 +399,24 @@ public class Instance { return file; } + /** + * Return the home directory from the system properties. + * + * @return the home + */ + private static String getHome() { + String home = System.getProperty("user.home"); + if (home == null || home.trim().isEmpty()) { + home = System.getProperty("java.io.tmpdir"); + } + + if (home == null) { + home = ""; + } + + return home; + } + /** * The language to use for the application (NULL = default system language). * diff --git a/src/be/nikiroo/fanfix/bundles/Config.java b/src/be/nikiroo/fanfix/bundles/Config.java index e3283ac..46edde9 100644 --- a/src/be/nikiroo/fanfix/bundles/Config.java +++ b/src/be/nikiroo/fanfix/bundles/Config.java @@ -15,48 +15,48 @@ public enum Config { @Meta(description = "reader type (CLI = simple output to console, TUI = Text User Interface with menus and windows, GUI = a GUI with locally stored files)", format = Format.FIXED_LIST, list = { "CLI", "GUI", "TUI" }, info = "Select the default reader to use to read stories") READER_TYPE, // - @Meta(format = Format.COMBO_LIST, list = { "INFO_TEXT", "EPUB", "HTML", - "TEXT" }, info = "One of the known output type", description = "The type of output for the Local Reader for non-images documents") + @Meta(def = "INFO_TEXT", format = Format.COMBO_LIST, list = { "INFO_TEXT", + "EPUB", "HTML", "TEXT" }, info = "One of the known output type", description = "The type of output for the Local Reader for non-images documents") NON_IMAGES_DOCUMENT_TYPE, // - @Meta(format = Format.COMBO_LIST, list = { "CBZ", "HTML" }, description = "The type of output for the Local Reader for images documents") + @Meta(def = "CBZ", format = Format.COMBO_LIST, list = { "CBZ", "HTML" }, description = "The type of output for the Local Reader for images documents") IMAGES_DOCUMENT_TYPE, // @Meta(description = "absolute path, $HOME variable supported, / is always accepted as dir separator", format = Format.DIRECTORY, info = "The directory where to store temporary files, defaults to directory 'tmp' in the conig directory (usually $HOME/.fanfix)") CACHE_DIR, // - @Meta(description = "delay in hours, or 0 for no cache, or -1 for infinite time (default)", format = Format.INT, info = "The delay after which a cached resource that is thought to change ~often is considered too old and triggers a refresh") + @Meta(def = "24", description = "delay in hours, or 0 for no cache, or -1 for infinite time (default)", format = Format.INT, info = "The delay after which a cached resource that is thought to change ~often is considered too old and triggers a refresh") CACHE_MAX_TIME_CHANGING, // - @Meta(description = "delay in hours, or 0 for no cache, or -1 for infinite time (default)", format = Format.INT, info = "The delay after which a cached resource that is thought to change rarely is considered too old and triggers a refresh") + @Meta(def = "720", description = "delay in hours, or 0 for no cache, or -1 for infinite time (default)", format = Format.INT, info = "The delay after which a cached resource that is thought to change rarely is considered too old and triggers a refresh") CACHE_MAX_TIME_STABLE, // - @Meta(description = "string", info = "The user-agent to use to download files") + @Meta(def = "Mozilla/5.0 (X11; Linux x86_64; rv:44.0) Gecko/20100101 Firefox/44.0 -- ELinks/0.9.3 (Linux 2.6.11 i686; 80x24)", description = "string", info = "The user-agent to use to download files") USER_AGENT, // - @Meta(description = "absolute path, $HOME variable supported, / is always accepted as dir separator", format = Format.DIRECTORY, info = "The directory where to get the default story covers") + @Meta(def = "$HOME/bin/epub/", description = "absolute path, $HOME variable supported, / is always accepted as dir separator", format = Format.DIRECTORY, info = "The directory where to get the default story covers") DEFAULT_COVERS_DIR, // @Meta(description = "string", info = "The default library to use (KEY:SERVER:PORT), or empty for the local library") DEFAULT_LIBRARY, // - @Meta(description = "absolute path, $HOME variable supported, / is always accepted as dir separator", format = Format.DIRECTORY, info = "The directory where to store the library") + @Meta(def = "$HOME/Books", description = "absolute path, $HOME variable supported, / is always accepted as dir separator", format = Format.DIRECTORY, info = "The directory where to store the library") LIBRARY_DIR, // - @Meta(description = "boolean", format = Format.BOOLEAN, info = "Show debug information on errors") + @Meta(def = "false", description = "boolean", format = Format.BOOLEAN, info = "Show debug information on errors") DEBUG_ERR, // - @Meta(description = "boolean", format = Format.BOOLEAN, info = "Show debug trace information") + @Meta(def = "false", description = "boolean", format = Format.BOOLEAN, info = "Show debug trace information") DEBUG_TRACE, // - @Meta(description = "image format", format = Format.COMBO_LIST, list = { + @Meta(def = "PNG", description = "image format", format = Format.COMBO_LIST, list = { "PNG", "JPG", "BMP" }, info = "Image format to use for cover images") IMAGE_FORMAT_COVER, // - @Meta(description = "image format", format = Format.COMBO_LIST, list = { + @Meta(def = "JPG", description = "image format", format = Format.COMBO_LIST, list = { "PNG", "JPG", "BMP" }, info = "Image format to use for content images") IMAGE_FORMAT_CONTENT, // @Meta(group = true) LATEX_LANG, // - @Meta(description = "LaTeX output language: English", info = "LaTeX full name") + @Meta(def = "english", description = "LaTeX output language: English", info = "LaTeX full name") LATEX_LANG_EN, // - @Meta(description = "LaTeX output language: French", info = "LaTeX full name") + @Meta(def = "french", description = "LaTeX output language: French", info = "LaTeX full name") LATEX_LANG_FR, // - @Meta(description = "other 'by' prefixes before author name, used to identify the author", array = true) + @Meta(def = "by,par,de,©,(c)", description = "other 'by' prefixes before author name, used to identify the author", array = true) BYS, // - @Meta(description = "List of languages codes used for chapter identification (should not be changed)", array = true, info = "EN,FR") + @Meta(def = "EN,FR", description = "List of languages codes used for chapter identification (should not be changed)", array = true, info = "EN,FR") CHAPTER, // - @Meta(description = "Chapter identification String: English", info = "used to identify a starting chapter in text mode") + @Meta(def = "Chapter", description = "Chapter identification String: English", info = "used to identify a starting chapter in text mode") CHAPTER_EN, // - @Meta(description = "Chapter identification String: French", info = "used to identify a starting chapter in text mode") + @Meta(def = "Chapitre", description = "Chapter identification String: French", info = "used to identify a starting chapter in text mode") CHAPTER_FR, // @Meta(description = "Login information (username) for YiffStar to have access to all the stories (should not be necessary anymore)") LOGIN_YIFFSTAR_USER, // @@ -70,6 +70,6 @@ public enum Config { LOGIN_FIMFICTION_APIKEY_CLIENT_SECRET, // @Meta(description = "Do not use the new API, even if we have a token, and force HTML scraping (default is false, use API if token or ID present)", format = Format.BOOLEAN) LOGIN_FIMFICTION_APIKEY_FORCE_HTML, // - @Meta(description = "A token is required to use the beta APIv2 from FimFiction (see APIKEY_CLIENT_*)", format = Format.PASSWORD) + @Meta(def = "Bearer WnZ5oHlzQoDocv1GcgHfcoqctHkSwL-D", description = "A token is required to use the beta APIv2 from FimFiction (see APIKEY_CLIENT_*)", format = Format.PASSWORD) LOGIN_FIMFICTION_APIKEY_TOKEN, // } diff --git a/src/be/nikiroo/fanfix/bundles/StringId.java b/src/be/nikiroo/fanfix/bundles/StringId.java index 96c67e2..aabc92a 100644 --- a/src/be/nikiroo/fanfix/bundles/StringId.java +++ b/src/be/nikiroo/fanfix/bundles/StringId.java @@ -49,19 +49,19 @@ public enum StringId { ERR_NOT_SUPPORTED, // @Meta(info = "%s = cover URL", description = "Failed to download cover : %s") ERR_BS_NO_COVER, // - @Meta(info = "single char", description = "Canonical OPEN SINGLE QUOTE char (for instance: `)") + @Meta(def = "`", info = "single char", description = "Canonical OPEN SINGLE QUOTE char (for instance: `)") OPEN_SINGLE_QUOTE, // - @Meta(info = "single char", description = "Canonical CLOSE SINGLE QUOTE char (for instance: ‘)") + @Meta(def = "‘", info = "single char", description = "Canonical CLOSE SINGLE QUOTE char (for instance: ‘)") CLOSE_SINGLE_QUOTE, // - @Meta(info = "single char", description = "Canonical OPEN DOUBLE QUOTE char (for instance: “)") + @Meta(def = "“", info = "single char", description = "Canonical OPEN DOUBLE QUOTE char (for instance: “)") OPEN_DOUBLE_QUOTE, // - @Meta(info = "single char", description = "Canonical CLOSE DOUBLE QUOTE char (for instance: ”)") + @Meta(def = "”", info = "single char", description = "Canonical CLOSE DOUBLE QUOTE char (for instance: ”)") CLOSE_DOUBLE_QUOTE, // - @Meta(description = "Name of the description fake chapter") + @Meta(def = "Description", description = "Name of the description fake chapter") DESCRIPTION, // - @Meta(info = "%d = number, %s = name", description = "Name of a chapter with a name") + @Meta(def = "Chapter %d: %s", info = "%d = number, %s = name", description = "Name of a chapter with a name") CHAPTER_NAMED, // - @Meta(info = "%d = number, %s = name", description = "Name of a chapter without name") + @Meta(def = "Chapter %d", info = "%d = number, %s = name", description = "Name of a chapter without name") CHAPTER_UNNAMED, // @Meta(info = "%s = type", description = "Default description when the type is not known by i18n") INPUT_DESC, // @@ -121,7 +121,7 @@ public enum StringId { OUTPUT_DESC_SHORT_HTML, // @Meta(info = "%s = the unknown 2-code language", description = "Error message for unknown 2-letter LaTeX language code") LATEX_LANG_UNKNOWN, // - @Meta(description = "'by' prefix before author name used to output the author, make sure it is covered by Config.BYS for input detection") + @Meta(def = "by", description = "'by' prefix before author name used to output the author, make sure it is covered by Config.BYS for input detection") BY, // ; diff --git a/src/be/nikiroo/fanfix/bundles/UiConfig.java b/src/be/nikiroo/fanfix/bundles/UiConfig.java index a4d8439..f36d2bb 100644 --- a/src/be/nikiroo/fanfix/bundles/UiConfig.java +++ b/src/be/nikiroo/fanfix/bundles/UiConfig.java @@ -10,7 +10,7 @@ import be.nikiroo.utils.resources.Meta.Format; */ @SuppressWarnings("javadoc") public enum UiConfig { - @Meta(format = Format.DIRECTORY, info = "absolute path, $HOME variable supported, / is always accepted as dir separator", description = "The directory where to store temporary files, defaults to directory 'tmp.reader' in the conig directory (usually $HOME/.fanfix)") + @Meta(format = Format.DIRECTORY, info = "absolute path, $HOME variable supported, / is always accepted as dir separator", description = "The directory where to store temporary files, defaults to directory 'tmp.reader' in the config directory (usually $HOME/.fanfix)") CACHE_DIR_LOCAL_READER, // @Meta(format = Format.COMBO_LIST, list = { "INFO_TEXT", "EPUB", "HTML", "TEXT" }, info = "One of the known output type", description = "The type of output for the GUI Reader for non-images documents") diff --git a/src/be/nikiroo/fanfix/bundles/config.properties b/src/be/nikiroo/fanfix/bundles/config.properties index a30e735..a9c9399 100644 --- a/src/be/nikiroo/fanfix/bundles/config.properties +++ b/src/be/nikiroo/fanfix/bundles/config.properties @@ -42,10 +42,10 @@ DEBUG_ERR = false DEBUG_TRACE = false # image format (FORMAT: COMBO_LIST) Image format to use for cover images # ALLOWED VALUES: "PNG" "JPG" "BMP" -IMAGE_FORMAT_COVER = png +IMAGE_FORMAT_COVER = PNG # image format (FORMAT: COMBO_LIST) Image format to use for content images # ALLOWED VALUES: "PNG" "JPG" "BMP" -IMAGE_FORMAT_CONTENT = png +IMAGE_FORMAT_CONTENT = JPG # This item is used as a group, its content is not expected to be used. LATEX_LANG = # LaTeX output language: English diff --git a/src/be/nikiroo/fanfix/bundles/ui.properties b/src/be/nikiroo/fanfix/bundles/ui.properties index 80e0a24..8756d63 100644 --- a/src/be/nikiroo/fanfix/bundles/ui.properties +++ b/src/be/nikiroo/fanfix/bundles/ui.properties @@ -2,7 +2,7 @@ # -# The directory where to store temporary files, defaults to directory 'tmp.reader' in the conig directory (usually $HOME/.fanfix) +# The directory where to store temporary files, defaults to directory 'tmp.reader' in the config directory (usually $HOME/.fanfix) # (FORMAT: DIRECTORY) absolute path, $HOME variable supported, / is always accepted as dir separator CACHE_DIR_LOCAL_READER = # The type of output for the GUI Reader for non-images documents -- 2.27.0