From d011400048cae6884f0d94c320498429b45fb48a Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Sun, 12 Feb 2017 11:44:44 +0100 Subject: [PATCH] Main.java: new actins available New actions are available: --help, --set-reader The code to handle them has been changed, too --- src/be/nikiroo/fanfix/Instance.java | 44 ++- src/be/nikiroo/fanfix/Main.java | 295 +++++++++++++----- src/be/nikiroo/fanfix/bundles/StringId.java | 4 +- .../nikiroo/fanfix/bundles/config.properties | 2 +- .../fanfix/bundles/resources.properties | 19 +- src/be/nikiroo/fanfix/reader/BasicReader.java | 46 ++- .../fanfix/supported/BasicSupport.java | 22 +- src/be/nikiroo/fanfix/supported/InfoText.java | 2 +- 8 files changed, 321 insertions(+), 113 deletions(-) diff --git a/src/be/nikiroo/fanfix/Instance.java b/src/be/nikiroo/fanfix/Instance.java index 94e854a..4e4705b 100644 --- a/src/be/nikiroo/fanfix/Instance.java +++ b/src/be/nikiroo/fanfix/Instance.java @@ -23,9 +23,9 @@ public class Instance { private static File readerTmp; static { + // Most of the rest is dependant upon this: config = new ConfigBundle(); - // config dependent: trans = new StringIdBundle(getLang()); lib = new Library(getFile(Config.LIBRARY_DIR)); debug = Instance.getConfig().getBoolean(Config.DEBUG_ERR, false); @@ -33,6 +33,14 @@ public class Instance { File tmp = getFile(Config.CACHE_DIR); readerTmp = getFile(Config.CACHE_DIR_LOCAL_READER); + if (checkEnv("NOUTF")) { + trans.setUnicode(false); + } + + if (checkEnv("DEBUG")) { + debug = true; + } + if (tmp == null || readerTmp == null) { String tmpDir = System.getProperty("java.io.tmpdir"); if (tmpDir != null) { @@ -54,17 +62,6 @@ public class Instance { + coverDir)); coverDir = null; } - // - - String noutf = System.getenv("NOUTF"); - if (noutf != null) { - noutf = noutf.trim().toLowerCase(); - if ("yes".equals(noutf) || "true".equals(noutf) - || "on".equals(noutf) || "1".equals(noutf) - || "y".equals(noutf)) { - trans.setUnicode(false); - } - } String configDir = System.getenv("CONFIG_DIR"); if (configDir != null) { @@ -89,7 +86,6 @@ public class Instance { } try { - String ua = config.getString(Config.USER_AGENT); int hours = config.getInteger(Config.CACHE_MAX_TIME_CHANGING, -1); int hoursLarge = config @@ -209,4 +205,26 @@ public class Instance { return lang; } + + /** + * Check that the given environment variable is "enabled". + * + * @param key + * the variable to check + * + * @return TRUE if it is + */ + private static boolean checkEnv(String key) { + String value = System.getenv(key); + if (value != null) { + value = value.trim().toLowerCase(); + if ("yes".equals(value) || "true".equals(value) + || "on".equals(value) || "1".equals(value) + || "y".equals(value)) { + return true; + } + } + + return false; + } } diff --git a/src/be/nikiroo/fanfix/Main.java b/src/be/nikiroo/fanfix/Main.java index 30febd3..10bccec 100644 --- a/src/be/nikiroo/fanfix/Main.java +++ b/src/be/nikiroo/fanfix/Main.java @@ -11,6 +11,7 @@ import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.output.BasicOutput; import be.nikiroo.fanfix.output.BasicOutput.OutputType; import be.nikiroo.fanfix.reader.BasicReader; +import be.nikiroo.fanfix.reader.BasicReader.ReaderType; import be.nikiroo.fanfix.supported.BasicSupport; import be.nikiroo.fanfix.supported.BasicSupport.SupportType; @@ -20,68 +21,180 @@ import be.nikiroo.fanfix.supported.BasicSupport.SupportType; * @author niki */ public class Main { + private enum MainAction { + IMPORT, EXPORT, CONVERT, READ, READ_URL, LIST, HELP, SET_READER + } + /** * Main program entry point. *

* Known environment variables: *

+ *

+ *

* * @param args - *
    - *
  1. --import [URL]: import into library
  2. --export [id] - * [output_type] [target]: export story to target
  3. - * --convert [URL] [output_type] [target]: convert URL into - * target
  4. --read [id]: read the given story from the - * library
  5. --read-url [URL]: convert on the fly and read - * the story, without saving it
  6. --list: list the stories - * present in the library
  7. - *
+ * see method description */ public static void main(String[] args) { - int exitCode = 255; + String urlString = null; + String luid = null; + String typeString = null; + String chapString = null; + String target = null; + String readerTypeString = null; + MainAction action = null; + Boolean plusInfo = null; + + boolean noMoreActions = false; + + int exitCode = 0; + for (int i = 0; exitCode == 0 && i < args.length; i++) { + // Action (--) handling: + if (!noMoreActions && args[i].startsWith("--")) { + if (args[i].equals("--")) { + noMoreActions = true; + } else { + try { + action = MainAction.valueOf(args[i].substring(2) + .toUpperCase().replace("-", "_")); + } catch (Exception e) { + Instance.syserr(new IllegalArgumentException( + "Unknown action: " + args[i], e)); + exitCode = 255; + } + } - if (args.length > 0) { - String action = args[0]; - if (action.equals("--import")) { - if (args.length > 1) { - exitCode = imprt(args[1]); + continue; + } + + switch (action) { + case IMPORT: + if (urlString == null) { + urlString = args[i]; + } else { + exitCode = 255; + } + break; + case EXPORT: + if (luid == null) { + luid = args[i]; + } else if (typeString == null) { + typeString = args[i]; + } else if (target == null) { + target = args[i]; + } else { + exitCode = 255; + } + break; + case CONVERT: + if (urlString == null) { + urlString = args[i]; + } else if (typeString == null) { + typeString = args[i]; + } else if (target == null) { + target = args[i]; + } else if (plusInfo == null) { + if ("+info".equals(args[i])) { + plusInfo = true; + } else { + exitCode = 255; + } + } else { + exitCode = 255; } - } else if (action.equals("--export")) { - if (args.length > 3) { - exitCode = export(args[1], args[2], args[3]); + break; + case LIST: + if (typeString == null) { + typeString = args[i]; + } else { + exitCode = 255; } - } else if (action.equals("--convert")) { - if (args.length > 3) { - exitCode = convert( - args[1], - args[2], - args[3], - args.length > 4 ? args[4].toLowerCase().equals( - "+info") : false); + break; + case READ: + if (luid == null) { + luid = args[i]; + } else if (chapString == null) { + chapString = args[i]; + } else { + exitCode = 255; } - } else if (action.equals("--list")) { - exitCode = list(args.length > 1 ? args[1] : null); - } else if (action.equals("--read-url")) { - if (args.length > 1) { - exitCode = read(args[1], args.length > 2 ? args[2] : null, - false); + break; + case READ_URL: + if (urlString == null) { + urlString = args[i]; + } else if (chapString == null) { + chapString = args[i]; + } else { + exitCode = 255; } - } else if (action.equals("--read")) { - if (args.length > 1) { - exitCode = read(args[1], args.length > 2 ? args[2] : null, - true); + break; + case HELP: + exitCode = 255; + break; + case SET_READER: + if (readerTypeString == null) { + readerTypeString = args[i]; + } else { + exitCode = 255; } + break; + } + } + + if (exitCode != 255) { + switch (action) { + case IMPORT: + exitCode = imprt(urlString); + break; + case EXPORT: + exitCode = export(urlString, typeString, target); + break; + case CONVERT: + exitCode = convert(urlString, typeString, target, + plusInfo == null ? false : plusInfo); + break; + case LIST: + exitCode = list(typeString); + break; + case READ: + exitCode = read(luid, chapString, true); + break; + case READ_URL: + exitCode = read(urlString, chapString, false); + break; + case HELP: + syntax(true); + exitCode = 0; + break; + case SET_READER: + exitCode = setReaderType(readerTypeString); + break; } } if (exitCode == 255) { - syntax(); + syntax(false); } if (exitCode != 0) { @@ -120,14 +233,14 @@ public class Main { /** * Import the given resource into the {@link Library}. * - * @param sourceString + * @param urlString * the resource to import * * @return the exit return code (0 = success) */ - private static int imprt(String sourceString) { + private static int imprt(String urlString) { try { - Story story = Instance.getLibrary().imprt(getUrl(sourceString)); + Story story = Instance.getLibrary().imprt(getUrl(urlString)); System.out.println(story.getMeta().getLuid() + ": \"" + story.getMeta().getTitle() + "\" imported."); } catch (IOException e) { @@ -141,7 +254,7 @@ public class Main { /** * Export the {@link Story} from the {@link Library} to the given target. * - * @param sourceString + * @param urlString * the story LUID * @param typeString * the {@link OutputType} to use @@ -150,8 +263,7 @@ public class Main { * * @return the exit return code (0 = success) */ - private static int export(String sourceString, String typeString, - String target) { + private static int export(String urlString, String typeString, String target) { OutputType type = OutputType.valueOfNullOkUC(typeString); if (type == null) { Instance.syserr(new Exception(trans(StringId.OUTPUT_DESC, @@ -160,7 +272,7 @@ public class Main { } try { - Story story = Instance.getLibrary().imprt(new URL(sourceString)); + Story story = Instance.getLibrary().imprt(new URL(urlString)); Instance.getLibrary().export(story.getMeta().getLuid(), type, target); } catch (IOException e) { @@ -202,7 +314,7 @@ public class Main { * @param story * the LUID of the {@link Story} in the {@link Library} or * the {@link Story} {@link URL} - * @param chap + * @param chapString * which {@link Chapter} to read (starting at 1), or NULL to get * the {@link Story} description * @param library @@ -211,7 +323,7 @@ public class Main { * * @return the exit return code (0 = success) */ - private static int read(String story, String chap, boolean library) { + private static int read(String story, String chapString, boolean library) { try { BasicReader reader = BasicReader.getReader(); if (library) { @@ -220,8 +332,14 @@ public class Main { reader.setStory(getUrl(story)); } - if (chap != null) { - reader.read(Integer.parseInt(chap)); + if (chapString != null) { + try { + reader.read(Integer.parseInt(chapString)); + } catch (NumberFormatException e) { + Instance.syserr(new IOException( + "Chapter number cannot be parsed: " + chapString, e)); + return 2; + } } else { reader.read(); } @@ -236,11 +354,11 @@ public class Main { /** * Convert the {@link Story} into another format. * - * @param sourceString + * @param urlString * the source {@link Story} to convert * @param typeString * the {@link OutputType} to convert to - * @param filename + * @param target * the target file * @param infoCover * TRUE to also export the cover and info file, even if the given @@ -248,13 +366,13 @@ public class Main { * * @return the exit return code (0 = success) */ - private static int convert(String sourceString, String typeString, - String filename, boolean infoCover) { + private static int convert(String urlString, String typeString, + String target, boolean infoCover) { int exitCode = 0; - String sourceName = sourceString; + String sourceName = urlString; try { - URL source = getUrl(sourceString); + URL source = getUrl(urlString); sourceName = source.toString(); if (source.toString().startsWith("file://")) { sourceName = sourceName.substring("file://".length()); @@ -273,12 +391,12 @@ public class Main { Story story = support.process(source); try { - filename = new File(filename).getAbsolutePath(); + target = new File(target).getAbsolutePath(); BasicOutput.getOutput(type, infoCover).process( - story, filename); + story, target); } catch (IOException e) { Instance.syserr(new IOException(trans( - StringId.ERR_SAVING, filename), e)); + StringId.ERR_SAVING, target), e)); exitCode = 5; } } else { @@ -315,27 +433,54 @@ public class Main { } /** - * Display the correct syntax of the program to the user. + * Display the correct syntax of the program to the user to stdout, or an + * error message if the syntax used was wrong on stderr. + * + * @param showHelp + * TRUE to show the syntax help, FALSE to show "syntax error" */ - private static void syntax() { - StringBuilder builder = new StringBuilder(); - for (SupportType type : SupportType.values()) { - builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(), - type.getDesc())); - builder.append('\n'); - } + private static void syntax(boolean showHelp) { + if (showHelp) { + StringBuilder builder = new StringBuilder(); + for (SupportType type : SupportType.values()) { + builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(), + type.getDesc())); + builder.append('\n'); + } - String typesIn = builder.toString(); - builder.setLength(0); + String typesIn = builder.toString(); + builder.setLength(0); - for (OutputType type : OutputType.values()) { - builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(), - type.getDesc())); - builder.append('\n'); - } + for (OutputType type : OutputType.values()) { + builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(), + type.getDesc())); + builder.append('\n'); + } - String typesOut = builder.toString(); + String typesOut = builder.toString(); - System.err.println(trans(StringId.ERR_SYNTAX, typesIn, typesOut)); + System.out.println(trans(StringId.HELP_SYNTAX, typesIn, typesOut)); + } else { + System.err.println(trans(StringId.ERR_SYNTAX)); + } + } + + /** + * Set the default reader type for this session only (it can be changed in + * the configuration file, too, but this value will override it). + * + * @param readerTypeString + * the type + */ + private static int setReaderType(String readerTypeString) { + try { + ReaderType readerType = ReaderType.valueOf(readerTypeString); + BasicReader.setDefaultReaderType(readerType); + return 0; + } catch (IllegalArgumentException e) { + Instance.syserr(new IOException("Unknown reader type: " + + readerTypeString, e)); + return 1; + } } } diff --git a/src/be/nikiroo/fanfix/bundles/StringId.java b/src/be/nikiroo/fanfix/bundles/StringId.java index 39cb0b2..124003c 100644 --- a/src/be/nikiroo/fanfix/bundles/StringId.java +++ b/src/be/nikiroo/fanfix/bundles/StringId.java @@ -30,7 +30,9 @@ public enum StringId { * Use it when you need a real translation but still don't have a key. */ DUMMY, // - @Meta(what = "error message", where = "cli", format = "%s = supported input, %s = supported output", info = "syntax error message") + @Meta(what = "help message", where = "cli", format = "%s = supported input, %s = supported output", info = "help message for the syntax") + HELP_SYNTAX, // + @Meta(what = "error message", where = "cli", format = "", info = "syntax error message") ERR_SYNTAX, // @Meta(what = "error message", where = "cli", format = "%s = support name, %s = support desc", info = "an input or output support type description") ERR_SYNTAX_TYPE, // diff --git a/src/be/nikiroo/fanfix/bundles/config.properties b/src/be/nikiroo/fanfix/bundles/config.properties index 79f2ac9..dd9fa1d 100644 --- a/src/be/nikiroo/fanfix/bundles/config.properties +++ b/src/be/nikiroo/fanfix/bundles/config.properties @@ -31,7 +31,7 @@ DEFAULT_COVERS_DIR = $HOME/bin/epub/ LIBRARY_DIR = $HOME/Books # (WHAT: boolean, FORMAT: 'true' or 'false') # Show debug information on errors -DEBUG_ERR = true +DEBUG_ERR = false # (WHAT: image format, FORMAT: PNG, JPG, BMP...) # Image format to use for cover images IMAGE_FORMAT_COVER = png diff --git a/src/be/nikiroo/fanfix/bundles/resources.properties b/src/be/nikiroo/fanfix/bundles/resources.properties index 13f6c2f..c835624 100644 --- a/src/be/nikiroo/fanfix/bundles/resources.properties +++ b/src/be/nikiroo/fanfix/bundles/resources.properties @@ -7,23 +7,26 @@ # -# (WHAT: error message, WHERE: cli, FORMAT: %s = supported input, %s = supported output) -# syntax error message -ERR_SYNTAX = Syntax error\n\ -\n\ -Valid options:\n\ +# (WHAT: help message, WHERE: cli, FORMAT: %s = supported input, %s = supported output) +# help message for the syntax +HELP_SYNTAX = Valid options:\n\ \t--import [URL]: import into library\n\ \t--export [id] [output_type] [target]: export story to target\n\ -\t--convert [URL] [output_type] [target]: convert URL into target\n\ -\t--read [id]: read the given story from the library\n\ -\t--read-url [URL]: convert on the fly and read the story, without saving it\n\ +\t--convert [URL] [output_type] [target] (+info): convert URL into target\n\ +\t--read [id] ([chapter number]): read the given story from the library\n\ +\t--read-url [URL] ([chapter number]): convert on the fly and read the story, without saving it\n\ \t--list: list the stories present in the library\n\ +\t--set-reader [reader type]: set the reader type to CLI or LOCAL for this command\n\ +\t--help: this help message\n\ \n\ Supported input types:\n\ %s\n\ \n\ Supported output types:\n\ %s +# (WHAT: error message, WHERE: cli) +# syntax error message +ERR_SYNTAX = Syntax error (try "--help") # (WHAT: error message, WHERE: cli, FORMAT: %s = support name, %s = support desc) # an input or output support type description ERR_SYNTAX_TYPE = %s: %s diff --git a/src/be/nikiroo/fanfix/reader/BasicReader.java b/src/be/nikiroo/fanfix/reader/BasicReader.java index eeb00af..34133e4 100644 --- a/src/be/nikiroo/fanfix/reader/BasicReader.java +++ b/src/be/nikiroo/fanfix/reader/BasicReader.java @@ -5,6 +5,7 @@ import java.net.URL; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.Library; +import be.nikiroo.fanfix.bundles.Config; import be.nikiroo.fanfix.data.Story; import be.nikiroo.fanfix.supported.BasicSupport; import be.nikiroo.fanfix.supported.BasicSupport.SupportType; @@ -24,12 +25,23 @@ public abstract class BasicReader { LOCAL } - private static ReaderType defaultType; + private static ReaderType defaultType = ReaderType.CLI; private Story story; private ReaderType type; + /** + * Take the default reader type configuration from the config file. + */ static { - // TODO: default type from config + String typeString = Instance.getConfig().getString(Config.READER_TYPE); + if (typeString != null && !typeString.isEmpty()) { + try { + ReaderType type = ReaderType.valueOf(typeString.toUpperCase()); + defaultType = type; + } catch (IllegalArgumentException e) { + // Do nothing + } + } } /** @@ -73,7 +85,17 @@ public abstract class BasicReader { public void setStory(String luid) throws IOException { story = Instance.getLibrary().getStory(luid); if (story == null) { - throw new IOException("Cannot retrieve story from library: " + luid); + // if the LUID is wrong and < 3, pad it to 3 chars with "0" then + // retry (since LUIDs are %03d) + if (luid != null && luid.length() < 3) { + while (luid.length() < 3) { + luid = "0" + luid; + } + setStory(luid); + } else { + throw new IOException("Cannot retrieve story from library: " + + luid); + } } } @@ -128,16 +150,20 @@ public abstract class BasicReader { public abstract void start(SupportType type); /** - * Return a new {@link BasicReader} ready for use. + * Return a new {@link BasicReader} ready for use if one is configured. + *

+ * Can return NULL if none are configured. * - * @return a {@link BasicReader} + * @return a {@link BasicReader}, or NULL if none configured */ public static BasicReader getReader() { - switch (defaultType) { - // case LOCAL: - // return new LocalReader().setType(ReaderType.LOCAL); - case CLI: - return new CliReader().setType(ReaderType.CLI); + if (defaultType != null) { + switch (defaultType) { + // case LOCAL: + // return new LocalReader().setType(ReaderType.LOCAL); + case CLI: + return new CliReader().setType(ReaderType.CLI); + } } return null; diff --git a/src/be/nikiroo/fanfix/supported/BasicSupport.java b/src/be/nikiroo/fanfix/supported/BasicSupport.java index 74f1115..ded09c2 100644 --- a/src/be/nikiroo/fanfix/supported/BasicSupport.java +++ b/src/be/nikiroo/fanfix/supported/BasicSupport.java @@ -653,7 +653,9 @@ public abstract class BasicSupport { * @param in * the input * @param needle - * a string that must be found inside the target line + * a string that must be found inside the target line (also + * supports "^" at start to say "only if it starts with" the + * needle) * @param relativeLine * the line to return based upon the target line position (-1 = * the line before, 0 = the target line...) @@ -675,7 +677,9 @@ public abstract class BasicSupport { * @param in * the input * @param needle - * a string that must be found inside the target line + * a string that must be found inside the target line (also + * supports "^" at start to say "only if it starts with" the + * needle) * @param relativeLine * the line to return based upon the target line position (-1 = * the line before, 0 = the target line...) @@ -697,8 +701,18 @@ public abstract class BasicSupport { while (scan.hasNext()) { lines.add(scan.next()); - if (index == -1 && lines.get(lines.size() - 1).contains(needle)) { - index = lines.size() - 1; + if (index == -1) { + if (needle.startsWith("^")) { + if (lines.get(lines.size() - 1).startsWith( + needle.substring(1))) { + index = lines.size() - 1; + } + + } else { + if (lines.get(lines.size() - 1).contains(needle)) { + index = lines.size() - 1; + } + } } if (index >= 0 && index + relativeLine < lines.size()) { diff --git a/src/be/nikiroo/fanfix/supported/InfoText.java b/src/be/nikiroo/fanfix/supported/InfoText.java index a627714..021b8c0 100644 --- a/src/be/nikiroo/fanfix/supported/InfoText.java +++ b/src/be/nikiroo/fanfix/supported/InfoText.java @@ -215,7 +215,7 @@ class InfoText extends Text { * in case of I/O error */ private String getInfoTag(URL source, String key) throws IOException { - key += "="; + key = "^" + key + "="; File file; try { -- 2.27.0