X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Ffanfix%2FMain.java;h=41206560a3bde407bf0d1f12ddc1f9081dc00d4d;hp=1c1bc545d59a88e7aeda74dbe79dfa871437581a;hb=9b863b20370118c95c6801b73dda951c7e507871;hpb=333f0e7b5e333e8f6222881ce35398f403fc4121 diff --git a/src/be/nikiroo/fanfix/Main.java b/src/be/nikiroo/fanfix/Main.java index 1c1bc54..4120656 100644 --- a/src/be/nikiroo/fanfix/Main.java +++ b/src/be/nikiroo/fanfix/Main.java @@ -4,16 +4,27 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.List; import be.nikiroo.fanfix.bundles.StringId; import be.nikiroo.fanfix.data.Chapter; +import be.nikiroo.fanfix.data.MetaData; import be.nikiroo.fanfix.data.Story; +import be.nikiroo.fanfix.library.BasicLibrary; +import be.nikiroo.fanfix.library.CacheLibrary; +import be.nikiroo.fanfix.library.LocalLibrary; +import be.nikiroo.fanfix.library.RemoteLibrary; +import be.nikiroo.fanfix.library.RemoteLibraryServer; 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.reader.Reader; +import be.nikiroo.fanfix.reader.Reader.ReaderType; import be.nikiroo.fanfix.supported.BasicSupport; -import be.nikiroo.fanfix.supported.BasicSupport.SupportType; +import be.nikiroo.fanfix.supported.SupportType; +import be.nikiroo.utils.Progress; +import be.nikiroo.utils.Version; +import be.nikiroo.utils.serial.server.ServerObject; /** * Main program entry point. @@ -22,7 +33,7 @@ import be.nikiroo.fanfix.supported.BasicSupport.SupportType; */ public class Main { private enum MainAction { - IMPORT, EXPORT, CONVERT, READ, READ_URL, LIST, HELP, SET_READER, START, + IMPORT, EXPORT, CONVERT, READ, READ_URL, LIST, HELP, SET_READER, START, VERSION, SERVER, STOP_SERVER, REMOTE, } /** @@ -33,8 +44,8 @@ public class Main { *
  • NOUTF: if set to 1 or 'true', the program will prefer non-unicode * {@link String}s when possible
  • *
  • CONFIG_DIR: a path where to look for the .properties files - * before taking the included ones; they will also be saved/updated into - * this path when the program starts
  • + * before taking the usual ones; they will also be saved/updated into this + * path when the program starts *
  • DEBUG: if set to 1 or 'true', the program will override the DEBUG_ERR * configuration value with 'true'
  • * @@ -49,8 +60,13 @@ public class Main { *
  • --read-url [URL] ([chapter number]): convert on the fly and read the * story, without saving it
  • *
  • --list ([type]): list the stories present in the library
  • - *
  • --set-reader [reader type]: set the reader type to CLI or LOCAL for - * this command
  • + *
  • --set-reader [reader type]: set the reader type to CLI, TUI or LOCAL + * for this command
  • + *
  • --version: get the version of the program
  • + *
  • --server [key] [port]: start a server on this port
  • + *
  • --stop-server [key] [port]: stop the running server on this port if + * any
  • + *
  • --remote [key] [host] [port]: use a the given remote library
  • * * * @param args @@ -59,11 +75,14 @@ public class Main { public static void main(String[] args) { String urlString = null; String luid = null; - String typeString = null; + String sourceString = null; String chapString = null; String target = null; + String key = null; MainAction action = MainAction.START; Boolean plusInfo = null; + String host = null; + Integer port = null; boolean noMoreActions = false; @@ -78,8 +97,9 @@ public class Main { action = MainAction.valueOf(args[i].substring(2) .toUpperCase().replace("-", "_")); } catch (Exception e) { - Instance.syserr(new IllegalArgumentException( - "Unknown action: " + args[i], e)); + Instance.getTraceHandler().error( + new IllegalArgumentException("Unknown action: " + + args[i], e)); exitCode = 255; } } @@ -98,8 +118,8 @@ public class Main { case EXPORT: if (luid == null) { luid = args[i]; - } else if (typeString == null) { - typeString = args[i]; + } else if (sourceString == null) { + sourceString = args[i]; } else if (target == null) { target = args[i]; } else { @@ -109,8 +129,8 @@ public class Main { case CONVERT: if (urlString == null) { urlString = args[i]; - } else if (typeString == null) { - typeString = args[i]; + } else if (sourceString == null) { + sourceString = args[i]; } else if (target == null) { target = args[i]; } else if (plusInfo == null) { @@ -124,8 +144,8 @@ public class Main { } break; case LIST: - if (typeString == null) { - typeString = args[i]; + if (sourceString == null) { + sourceString = args[i]; } else { exitCode = 255; } @@ -153,32 +173,130 @@ public class Main { break; case SET_READER: exitCode = setReaderType(args[i]); + action = MainAction.START; break; case START: exitCode = 255; // not supposed to be selected by user break; + case VERSION: + exitCode = 255; // no arguments for this option + break; + case SERVER: + case STOP_SERVER: + if (key == null) { + key = args[i]; + } else if (port == null) { + port = Integer.parseInt(args[i]); + } else { + exitCode = 255; + } + break; + case REMOTE: + if (key == null) { + key = args[i]; + } else if (host == null) { + host = args[i]; + } else if (port == null) { + port = Integer.parseInt(args[i]); + + BasicLibrary lib = new RemoteLibrary(key, host, port); + lib = new CacheLibrary(Instance.getRemoteDir(host), lib); + + BasicReader.setDefaultLibrary(lib); + + action = MainAction.START; + } else { + exitCode = 255; + } + break; + } + } + + final Progress mainProgress = new Progress(0, 80); + mainProgress.addProgressListener(new Progress.ProgressListener() { + private int current = mainProgress.getMin(); + + @Override + public void progress(Progress progress, String name) { + int diff = progress.getProgress() - current; + current += diff; + + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < diff; i++) { + builder.append('.'); + } + + System.err.print(builder.toString()); + + if (progress.isDone()) { + System.err.println(""); + } + } + }); + Progress pg = new Progress(); + mainProgress.addProgress(pg, mainProgress.getMax()); + + VersionCheck updates = VersionCheck.check(); + if (updates.isNewVersionAvailable()) { + // Sent to syserr so not to cause problem if one tries to capture a + // story content in text mode + System.err + .println("A new version of the program is available at https://github.com/nikiroo/fanfix/releases"); + System.err.println(""); + for (Version v : updates.getNewer()) { + System.err.println("\tVersion " + v); + System.err.println("\t-------------"); + System.err.println(""); + for (String item : updates.getChanges().get(v)) { + System.err.println("\t- " + item); + } + System.err.println(""); } } if (exitCode != 255) { switch (action) { case IMPORT: - exitCode = imprt(urlString); + exitCode = imprt(urlString, pg); + updates.ok(); // we consider it read break; case EXPORT: - exitCode = export(luid, typeString, target); + exitCode = export(luid, sourceString, target, pg); + updates.ok(); // we consider it read break; case CONVERT: - exitCode = convert(urlString, typeString, target, - plusInfo == null ? false : plusInfo); + exitCode = convert(urlString, sourceString, target, + plusInfo == null ? false : plusInfo, pg); + updates.ok(); // we consider it read break; case LIST: - exitCode = list(typeString); + if (BasicReader.getReader() == null) { + Instance.getTraceHandler() + .error(new Exception( + "No reader type has been configured")); + exitCode = 10; + break; + } + exitCode = list(sourceString); break; case READ: + if (BasicReader.getReader() == null) { + Instance.getTraceHandler() + .error(new Exception( + "No reader type has been configured")); + exitCode = 10; + break; + } exitCode = read(luid, chapString, true); break; case READ_URL: + if (BasicReader.getReader() == null) { + Instance.getTraceHandler() + .error(new Exception( + "No reader type has been configured")); + exitCode = 10; + break; + } exitCode = read(urlString, chapString, false); break; case HELP: @@ -186,11 +304,64 @@ public class Main { exitCode = 0; break; case SET_READER: + exitCode = 255; + break; + case VERSION: + System.out + .println(String.format("Fanfix version %s" + + "%nhttps://github.com/nikiroo/fanfix/" + + "%n\tWritten by Nikiroo", + Version.getCurrentVersion())); + updates.ok(); // we consider it read break; case START: - BasicReader.setDefaultReaderType(ReaderType.LOCAL); - BasicReader.getReader().start(null); + if (BasicReader.getReader() == null) { + Instance.getTraceHandler() + .error(new Exception( + "No reader type has been configured")); + exitCode = 10; + break; + } + BasicReader.getReader().browse(null); break; + case SERVER: + if (port == null) { + exitCode = 255; + break; + } + try { + ServerObject server = new RemoteLibraryServer(key, port); + server.setTraceHandler(Instance.getTraceHandler()); + server.run(); + } catch (IOException e) { + Instance.getTraceHandler().error(e); + } + return; + case STOP_SERVER: + if (port == null) { + exitCode = 255; + break; + } + + new RemoteLibrary(key, host, port).exit(); + break; + case REMOTE: + exitCode = 255; // should not be reachable (REMOTE -> START) + break; + } + } + + // We cannot do it when in GUI mode, because it is async... + // So if we close the temp files before it is actually used, + // we have a problem... + // TODO: close it at the correct time (for now, finalize try to do it) + if (false) { + try { + Instance.getTempFiles().close(); + } catch (IOException e) { + Instance.getTraceHandler().error( + new IOException( + "Cannot dispose of the temporary files", e)); } } @@ -204,48 +375,23 @@ public class Main { } /** - * Return an {@link URL} from this {@link String}, be it a file path or an - * actual {@link URL}. - * - * @param sourceString - * the source - * - * @return the corresponding {@link URL} - * - * @throws MalformedURLException - * if this is neither a file nor a conventional {@link URL} - */ - private static URL getUrl(String sourceString) throws MalformedURLException { - if (sourceString == null || sourceString.isEmpty()) { - throw new MalformedURLException("Empty url"); - } - - URL source = null; - try { - source = new URL(sourceString); - } catch (MalformedURLException e) { - File sourceFile = new File(sourceString); - source = sourceFile.toURI().toURL(); - } - - return source; - } - - /** - * Import the given resource into the {@link Library}. + * Import the given resource into the {@link LocalLibrary}. * * @param urlString * the resource to import + * @param pg + * the optional progress reporter * * @return the exit return code (0 = success) */ - public static int imprt(String urlString) { + public static int imprt(String urlString, Progress pg) { try { - Story story = Instance.getLibrary().imprt(getUrl(urlString)); + Story story = Instance.getLibrary().imprt( + BasicReader.getUrl(urlString), pg); System.out.println(story.getMeta().getLuid() + ": \"" + story.getMeta().getTitle() + "\" imported."); } catch (IOException e) { - Instance.syserr(e); + Instance.getTraceHandler().error(e); return 1; } @@ -253,7 +399,8 @@ public class Main { } /** - * Export the {@link Story} from the {@link Library} to the given target. + * Export the {@link Story} from the {@link LocalLibrary} to the given + * target. * * @param luid * the story LUID @@ -261,21 +408,24 @@ public class Main { * the {@link OutputType} to use * @param target * the target + * @param pg + * the optional progress reporter * * @return the exit return code (0 = success) */ - public static int export(String luid, String typeString, String target) { - OutputType type = OutputType.valueOfNullOkUC(typeString); + public static int export(String luid, String typeString, String target, + Progress pg) { + OutputType type = OutputType.valueOfNullOkUC(typeString, null); if (type == null) { - Instance.syserr(new Exception(trans(StringId.OUTPUT_DESC, - typeString))); + Instance.getTraceHandler().error( + new Exception(trans(StringId.OUTPUT_DESC, typeString))); return 1; } try { - Instance.getLibrary().export(luid, type, target); + Instance.getLibrary().export(luid, type, target, pg); } catch (IOException e) { - Instance.syserr(e); + Instance.getTraceHandler().error(e); return 4; } @@ -283,17 +433,28 @@ public class Main { } /** - * List the stories of the given type from the {@link Library} (unless NULL - * is passed, in which case all stories will be listed). + * List the stories of the given source from the {@link LocalLibrary} + * (unless NULL is passed, in which case all stories will be listed). * - * @param typeString - * the type to list the known stories of, or NULL to list all + * @param source + * the source to list the known stories of, or NULL to list all * stories * * @return the exit return code (0 = success) */ - private static int list(String type) { - BasicReader.getReader().start(type); + private static int list(String source) { + List stories; + stories = BasicReader.getReader().getLibrary().getListBySource(source); + + for (MetaData story : stories) { + String author = ""; + if (story.getAuthor() != null && !story.getAuthor().isEmpty()) { + author = " (" + story.getAuthor() + ")"; + } + + System.out.println(story.getLuid() + ": " + story.getTitle() + + author); + } return 0; } @@ -301,8 +462,8 @@ public class Main { * Start the CLI reader for this {@link Story}. * * @param story - * the LUID of the {@link Story} in the {@link Library} or - * the {@link Story} {@link URL} + * the LUID of the {@link Story} in the {@link LocalLibrary} + * or the {@link Story} {@link URL} * @param chapString * which {@link Chapter} to read (starting at 1), or NULL to get * the {@link Story} description @@ -314,26 +475,28 @@ public class Main { */ private static int read(String story, String chapString, boolean library) { try { - BasicReader reader = BasicReader.getReader(); + Reader reader = BasicReader.getReader(); if (library) { - reader.setStory(story); + reader.setMeta(story); } else { - reader.setStory(getUrl(story)); + reader.setMeta(BasicReader.getUrl(story), null); } if (chapString != null) { try { - reader.read(Integer.parseInt(chapString)); + reader.setChapter(Integer.parseInt(chapString)); + reader.read(); } catch (NumberFormatException e) { - Instance.syserr(new IOException( - "Chapter number cannot be parsed: " + chapString, e)); + Instance.getTraceHandler().error( + new IOException("Chapter number cannot be parsed: " + + chapString, e)); return 2; } } else { reader.read(); } } catch (IOException e) { - Instance.syserr(e); + Instance.getTraceHandler().error(e); return 1; } @@ -352,25 +515,28 @@ public class Main { * @param infoCover * TRUE to also export the cover and info file, even if the given * {@link OutputType} does not usually save them + * @param pg + * the optional progress reporter * * @return the exit return code (0 = success) */ - private static int convert(String urlString, String typeString, - String target, boolean infoCover) { + public static int convert(String urlString, String typeString, + String target, boolean infoCover, Progress pg) { int exitCode = 0; String sourceName = urlString; try { - URL source = getUrl(urlString); + URL source = BasicReader.getUrl(urlString); sourceName = source.toString(); if (source.toString().startsWith("file://")) { sourceName = sourceName.substring("file://".length()); } - OutputType type = OutputType.valueOfAllOkUC(typeString); + OutputType type = OutputType.valueOfAllOkUC(typeString, null); if (type == null) { - Instance.syserr(new IOException(trans( - StringId.ERR_BAD_OUTPUT_TYPE, typeString))); + Instance.getTraceHandler().error( + new IOException(trans(StringId.ERR_BAD_OUTPUT_TYPE, + typeString))); exitCode = 2; } else { @@ -378,32 +544,43 @@ public class Main { BasicSupport support = BasicSupport.getSupport(source); if (support != null) { - Story story = support.process(source); + Progress pgIn = new Progress(); + Progress pgOut = new Progress(); + if (pg != null) { + pg.setMax(2); + pg.addProgress(pgIn, 1); + pg.addProgress(pgOut, 1); + } + Story story = support.process(pgIn); try { target = new File(target).getAbsolutePath(); - BasicOutput.getOutput(type, infoCover).process( - story, target); + BasicOutput.getOutput(type, infoCover, infoCover) + .process(story, target, pgOut); } catch (IOException e) { - Instance.syserr(new IOException(trans( - StringId.ERR_SAVING, target), e)); + Instance.getTraceHandler().error( + new IOException(trans(StringId.ERR_SAVING, + target), e)); exitCode = 5; } } else { - Instance.syserr(new IOException(trans( - StringId.ERR_NOT_SUPPORTED, source))); + Instance.getTraceHandler().error( + new IOException(trans( + StringId.ERR_NOT_SUPPORTED, source))); exitCode = 4; } } catch (IOException e) { - Instance.syserr(new IOException(trans(StringId.ERR_LOADING, - sourceName), e)); + Instance.getTraceHandler().error( + new IOException(trans(StringId.ERR_LOADING, + sourceName), e)); exitCode = 3; } } } catch (MalformedURLException e) { - Instance.syserr(new IOException(trans(StringId.ERR_BAD_URL, - sourceName), e)); + Instance.getTraceHandler() + .error(new IOException(trans(StringId.ERR_BAD_URL, + sourceName), e)); exitCode = 1; } @@ -443,7 +620,7 @@ public class Main { for (OutputType type : OutputType.values()) { builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(), - type.getDesc())); + type.getDesc(true))); builder.append('\n'); } @@ -469,8 +646,9 @@ public class Main { BasicReader.setDefaultReaderType(readerType); return 0; } catch (IllegalArgumentException e) { - Instance.syserr(new IOException("Unknown reader type: " - + readerTypeString, e)); + Instance.getTraceHandler().error( + new IOException("Unknown reader type: " + readerTypeString, + e)); return 1; } }