Merge branch 'master' into search
[nikiroo-utils.git] / src / be / nikiroo / fanfix / Main.java
CommitLineData
08fe2e33
NR
1package be.nikiroo.fanfix;
2
3import java.io.File;
4import java.io.IOException;
5import java.net.MalformedURLException;
6import java.net.URL;
91b82a5c 7import java.util.ArrayList;
f569d249 8import java.util.List;
08fe2e33
NR
9
10import be.nikiroo.fanfix.bundles.StringId;
11import be.nikiroo.fanfix.data.Chapter;
f569d249 12import be.nikiroo.fanfix.data.MetaData;
08fe2e33 13import be.nikiroo.fanfix.data.Story;
ff05b828
NR
14import be.nikiroo.fanfix.library.BasicLibrary;
15import be.nikiroo.fanfix.library.CacheLibrary;
e42573a0
NR
16import be.nikiroo.fanfix.library.LocalLibrary;
17import be.nikiroo.fanfix.library.RemoteLibrary;
18import be.nikiroo.fanfix.library.RemoteLibraryServer;
08fe2e33
NR
19import be.nikiroo.fanfix.output.BasicOutput;
20import be.nikiroo.fanfix.output.BasicOutput.OutputType;
3727aae2 21import be.nikiroo.fanfix.reader.BasicReader;
e42573a0
NR
22import be.nikiroo.fanfix.reader.Reader;
23import be.nikiroo.fanfix.reader.Reader.ReaderType;
91b82a5c 24import be.nikiroo.fanfix.searchable.BasicSearchable;
08fe2e33 25import be.nikiroo.fanfix.supported.BasicSupport;
0ffa4754 26import be.nikiroo.fanfix.supported.SupportType;
3b2b638f 27import be.nikiroo.utils.Progress;
39c3c689 28import be.nikiroo.utils.Version;
62c63b07 29import be.nikiroo.utils.serial.server.ServerObject;
08fe2e33
NR
30
31/**
32 * Main program entry point.
33 *
34 * @author niki
35 */
36public class Main {
d0114000 37 private enum MainAction {
91b82a5c 38 IMPORT, EXPORT, CONVERT, READ, READ_URL, LIST, HELP, SET_READER, START, VERSION, SERVER, STOP_SERVER, REMOTE, SET_SOURCE, SET_TITLE, SET_AUTHOR, SEARCH, SEARCH_TAG
d0114000
NR
39 }
40
08fe2e33
NR
41 /**
42 * Main program entry point.
43 * <p>
44 * Known environment variables:
45 * <ul>
d0114000 46 * <li>NOUTF: if set to 1 or 'true', the program will prefer non-unicode
08fe2e33
NR
47 * {@link String}s when possible</li>
48 * <li>CONFIG_DIR: a path where to look for the <tt>.properties</tt> files
edd46289
NR
49 * before taking the usual ones; they will also be saved/updated into this
50 * path when the program starts</li>
d0114000
NR
51 * <li>DEBUG: if set to 1 or 'true', the program will override the DEBUG_ERR
52 * configuration value with 'true'</li>
53 * </ul>
54 * <p>
55 * <ul>
56 * <li>--import [URL]: import into library</li>
57 * <li>--export [id] [output_type] [target]: export story to target</li>
58 * <li>--convert [URL] [output_type] [target] (+info): convert URL into
59 * target</li>
60 * <li>--read [id] ([chapter number]): read the given story from the library
61 * </li>
333f0e7b 62 * <li>--read-url [URL] ([chapter number]): convert on the fly and read the
d0114000 63 * story, without saving it</li>
91b82a5c
NR
64 * <li>--search WEBSITE [free text] ([page] ([item])): search for the given terms,
65 * show the given page (page 0 means "how many page do we have", starts at page 1)</li>
66 * <li>--search-tag WEBSITE ([tag 1] [tag2...] ([page] ([item]))): list the known
67 * tags or search the stories for the given tag(s), show the given page of results
68 * (page 0 means "how many page do we have", starts at page 1)</li>
333f0e7b 69 * <li>--list ([type]): list the stories present in the library</li>
e10b51a2
NR
70 * <li>--set-source [id] [new source]: change the source of the given story</li>
71 * <li>--set-title [id] [new title]: change the title of the given story</li>
72 * <li>--set-author [id] [new author]: change the author of the given story</li>
c1873e56
NR
73 * <li>--set-reader [reader type]: set the reader type to CLI, TUI or LOCAL
74 * for this command</li>
39c3c689 75 * <li>--version: get the version of the program</li>
2070ced5
NR
76 * <li>--server [key] [port]: start a server on this port</li>
77 * <li>--stop-server [key] [port]: stop the running server on this port if
78 * any</li>
79 * <li>--remote [key] [host] [port]: use a the given remote library</li>
08fe2e33
NR
80 * </ul>
81 *
82 * @param args
d0114000 83 * see method description
08fe2e33
NR
84 */
85 public static void main(String[] args) {
d0114000
NR
86 String urlString = null;
87 String luid = null;
b0e88ebd 88 String sourceString = null;
e10b51a2
NR
89 String titleString = null;
90 String authorString = null;
d0114000
NR
91 String chapString = null;
92 String target = null;
2070ced5 93 String key = null;
333f0e7b 94 MainAction action = MainAction.START;
d0114000 95 Boolean plusInfo = null;
b0e88ebd
NR
96 String host = null;
97 Integer port = null;
91b82a5c
NR
98 SupportType searchOn = null;
99 String search = null;
100 List<String> tags = new ArrayList<String>();
101 Integer page = null;
102 Integer item = null;
73ce17ef 103
d0114000
NR
104 boolean noMoreActions = false;
105
106 int exitCode = 0;
107 for (int i = 0; exitCode == 0 && i < args.length; i++) {
108 // Action (--) handling:
109 if (!noMoreActions && args[i].startsWith("--")) {
110 if (args[i].equals("--")) {
111 noMoreActions = true;
112 } else {
113 try {
114 action = MainAction.valueOf(args[i].substring(2)
115 .toUpperCase().replace("-", "_"));
116 } catch (Exception e) {
62c63b07
NR
117 Instance.getTraceHandler().error(
118 new IllegalArgumentException("Unknown action: "
119 + args[i], e));
d0114000
NR
120 exitCode = 255;
121 }
122 }
08fe2e33 123
d0114000
NR
124 continue;
125 }
126
127 switch (action) {
128 case IMPORT:
129 if (urlString == null) {
130 urlString = args[i];
131 } else {
132 exitCode = 255;
133 }
134 break;
135 case EXPORT:
136 if (luid == null) {
137 luid = args[i];
b0e88ebd
NR
138 } else if (sourceString == null) {
139 sourceString = args[i];
d0114000
NR
140 } else if (target == null) {
141 target = args[i];
142 } else {
143 exitCode = 255;
144 }
145 break;
146 case CONVERT:
147 if (urlString == null) {
148 urlString = args[i];
b0e88ebd
NR
149 } else if (sourceString == null) {
150 sourceString = args[i];
d0114000
NR
151 } else if (target == null) {
152 target = args[i];
153 } else if (plusInfo == null) {
154 if ("+info".equals(args[i])) {
155 plusInfo = true;
156 } else {
157 exitCode = 255;
158 }
159 } else {
160 exitCode = 255;
08fe2e33 161 }
d0114000
NR
162 break;
163 case LIST:
b0e88ebd
NR
164 if (sourceString == null) {
165 sourceString = args[i];
d0114000
NR
166 } else {
167 exitCode = 255;
08fe2e33 168 }
d0114000 169 break;
e10b51a2
NR
170 case SET_SOURCE:
171 if (luid == null) {
172 luid = args[i];
173 } else if (sourceString == null) {
174 sourceString = args[i];
175 } else {
176 exitCode = 255;
177 }
178 break;
179 case SET_TITLE:
180 if (luid == null) {
181 luid = args[i];
182 } else if (sourceString == null) {
183 titleString = args[i];
184 } else {
185 exitCode = 255;
186 }
187 break;
188 case SET_AUTHOR:
189 if (luid == null) {
190 luid = args[i];
191 } else if (sourceString == null) {
192 authorString = args[i];
193 } else {
194 exitCode = 255;
195 }
196 break;
d0114000
NR
197 case READ:
198 if (luid == null) {
199 luid = args[i];
200 } else if (chapString == null) {
201 chapString = args[i];
202 } else {
203 exitCode = 255;
08fe2e33 204 }
d0114000
NR
205 break;
206 case READ_URL:
207 if (urlString == null) {
208 urlString = args[i];
209 } else if (chapString == null) {
210 chapString = args[i];
211 } else {
212 exitCode = 255;
08fe2e33 213 }
d0114000 214 break;
91b82a5c
NR
215 case SEARCH:
216 if (searchOn == null) {
217 searchOn = SupportType.valueOfAllOkUC(args[i]);
218
219 if (searchOn == null) {
220 Instance.getTraceHandler().error(
221 "Website not known: <" + args[i] + ">");
222 exitCode = 255;
223 }
224
225 if (BasicSearchable.getSearchable(searchOn) == null) {
226 Instance.getTraceHandler().error(
227 "Website not supported: " + searchOn);
228 exitCode = 255;
229 }
230 } else if (search == null) {
231 search = args[i];
232 } else if (page == null) {
233 try {
234 page = Integer.parseInt(args[i]);
235 } catch (NumberFormatException e) {
236 Instance.getTraceHandler().error(
237 new Exception("Incorrect page number: <"
238 + args[i] + ">", e));
239 exitCode = 255;
240 }
241 } else if (item == null) {
242 try {
243 item = Integer.parseInt(args[i]);
244 } catch (NumberFormatException e) {
245 Instance.getTraceHandler().error(
246 new Exception("Incorrect item number: <"
247 + args[i] + ">", e));
248 exitCode = 255;
249 }
250 } else {
251 exitCode = 255;
252 }
253 break;
254 case SEARCH_TAG:
255 if (searchOn == null) {
256 searchOn = SupportType.valueOfAllOkUC(args[i]);
257
258 if (searchOn == null) {
259 Instance.getTraceHandler().error(
260 "Website not known: <" + args[i] + ">");
261 exitCode = 255;
262 }
263
264 if (BasicSearchable.getSearchable(searchOn) == null) {
265 Instance.getTraceHandler().error(
266 "Website not supported: " + searchOn);
267 exitCode = 255;
268 }
269 } else {
270 tags.add(args[i]);
271 }
272 break;
d0114000
NR
273 case HELP:
274 exitCode = 255;
275 break;
276 case SET_READER:
7de079f1 277 exitCode = setReaderType(args[i]);
c1873e56 278 action = MainAction.START;
d0114000 279 break;
333f0e7b
NR
280 case START:
281 exitCode = 255; // not supposed to be selected by user
282 break;
39c3c689
NR
283 case VERSION:
284 exitCode = 255; // no arguments for this option
b0e88ebd
NR
285 break;
286 case SERVER:
5e848e6a 287 case STOP_SERVER:
2070ced5
NR
288 if (key == null) {
289 key = args[i];
290 } else if (port == null) {
b0e88ebd
NR
291 port = Integer.parseInt(args[i]);
292 } else {
293 exitCode = 255;
294 }
295 break;
296 case REMOTE:
2070ced5
NR
297 if (key == null) {
298 key = args[i];
299 } else if (host == null) {
b0e88ebd
NR
300 host = args[i];
301 } else if (port == null) {
302 port = Integer.parseInt(args[i]);
ff05b828 303
2070ced5 304 BasicLibrary lib = new RemoteLibrary(key, host, port);
5895a958 305 lib = new CacheLibrary(Instance.getRemoteDir(host), lib);
ff05b828
NR
306
307 BasicReader.setDefaultLibrary(lib);
5e848e6a 308
b0e88ebd
NR
309 action = MainAction.START;
310 } else {
311 exitCode = 255;
312 }
313 break;
d0114000
NR
314 }
315 }
316
92fb0719
NR
317 final Progress mainProgress = new Progress(0, 80);
318 mainProgress.addProgressListener(new Progress.ProgressListener() {
319 private int current = mainProgress.getMin();
320
211f7ddb 321 @Override
92fb0719
NR
322 public void progress(Progress progress, String name) {
323 int diff = progress.getProgress() - current;
324 current += diff;
325
1822d603
NR
326 if (diff <= 0)
327 return;
328
92fb0719
NR
329 StringBuilder builder = new StringBuilder();
330 for (int i = 0; i < diff; i++) {
331 builder.append('.');
332 }
333
334 System.err.print(builder.toString());
335
336 if (progress.isDone()) {
337 System.err.println("");
338 }
339 }
340 });
341 Progress pg = new Progress();
342 mainProgress.addProgress(pg, mainProgress.getMax());
343
b42117f1
NR
344 VersionCheck updates = VersionCheck.check();
345 if (updates.isNewVersionAvailable()) {
346 // Sent to syserr so not to cause problem if one tries to capture a
347 // story content in text mode
348 System.err
349 .println("A new version of the program is available at https://github.com/nikiroo/fanfix/releases");
350 System.err.println("");
351 for (Version v : updates.getNewer()) {
352 System.err.println("\tVersion " + v);
353 System.err.println("\t-------------");
354 System.err.println("");
91b82a5c
NR
355 for (String it : updates.getChanges().get(v)) {
356 System.err.println("\t- " + it);
b42117f1
NR
357 }
358 System.err.println("");
359 }
360 }
361
d0114000
NR
362 if (exitCode != 255) {
363 switch (action) {
364 case IMPORT:
92fb0719 365 exitCode = imprt(urlString, pg);
b42117f1 366 updates.ok(); // we consider it read
d0114000
NR
367 break;
368 case EXPORT:
b0e88ebd 369 exitCode = export(luid, sourceString, target, pg);
b42117f1 370 updates.ok(); // we consider it read
d0114000
NR
371 break;
372 case CONVERT:
b0e88ebd 373 exitCode = convert(urlString, sourceString, target,
92fb0719 374 plusInfo == null ? false : plusInfo, pg);
b42117f1 375 updates.ok(); // we consider it read
d0114000
NR
376 break;
377 case LIST:
99ccbdf6 378 if (BasicReader.getReader() == null) {
62c63b07
NR
379 Instance.getTraceHandler()
380 .error(new Exception(
381 "No reader type has been configured"));
99ccbdf6
NR
382 exitCode = 10;
383 break;
384 }
b0e88ebd 385 exitCode = list(sourceString);
d0114000 386 break;
e10b51a2
NR
387 case SET_SOURCE:
388 try {
389 Instance.getLibrary().changeSource(luid, sourceString, pg);
390 } catch (IOException e1) {
391 Instance.getTraceHandler().error(e1);
392 exitCode = 21;
393 }
394 break;
395 case SET_TITLE:
396 try {
397 Instance.getLibrary().changeTitle(luid, titleString, pg);
398 } catch (IOException e1) {
399 Instance.getTraceHandler().error(e1);
400 exitCode = 22;
401 }
402 break;
403 case SET_AUTHOR:
404 try {
405 Instance.getLibrary().changeAuthor(luid, authorString, pg);
406 } catch (IOException e1) {
407 Instance.getTraceHandler().error(e1);
408 exitCode = 23;
409 }
410 break;
d0114000 411 case READ:
99ccbdf6 412 if (BasicReader.getReader() == null) {
62c63b07
NR
413 Instance.getTraceHandler()
414 .error(new Exception(
415 "No reader type has been configured"));
99ccbdf6
NR
416 exitCode = 10;
417 break;
418 }
d0114000
NR
419 exitCode = read(luid, chapString, true);
420 break;
421 case READ_URL:
99ccbdf6 422 if (BasicReader.getReader() == null) {
62c63b07
NR
423 Instance.getTraceHandler()
424 .error(new Exception(
425 "No reader type has been configured"));
99ccbdf6
NR
426 exitCode = 10;
427 break;
428 }
d0114000 429 exitCode = read(urlString, chapString, false);
91b82a5c
NR
430 break;
431 case SEARCH:
432 if (searchOn == null || search == null) {
433 exitCode = 255;
434 break;
435 }
436
437 if (page == null) {
438 page = 1;
439 }
440 if (item == null) {
441 item = 0;
442 }
443
444 if (BasicReader.getReader() == null) {
445 Instance.getTraceHandler()
446 .error(new Exception(
447 "No reader type has been configured"));
448 exitCode = 10;
449 break;
450 }
451
452 try {
453 BasicReader.getReader().search(searchOn, search, page, item);
454 } catch (IOException e1) {
455 Instance.getTraceHandler().error(e1);
456 }
457
458 break;
459 case SEARCH_TAG:
460 if (searchOn == null) {
461 exitCode = 255;
462 break;
463 }
464
465 item = 0;
466 page = 1;
467
468 try {
b3b9a1cd 469 page = Integer.parseInt(tags.get(tags.size()-1));
91b82a5c
NR
470 tags.remove(tags.size() - 1);
471
472 try {
473 int tmp = Integer.parseInt(tags.get(tags.size()-1));
474 tags.remove(tags.size() - 1);
475
b3b9a1cd
NR
476 item = page;
477 page = tmp;
91b82a5c
NR
478 } catch (Exception e) {
479 }
480 } catch (Exception e) {
481 }
482
483 if (BasicReader.getReader() == null) {
484 Instance.getTraceHandler()
485 .error(new Exception(
486 "No reader type has been configured"));
487 exitCode = 10;
488 break;
489 }
490
491 try {
492 BasicReader.getReader().searchTag(searchOn, page, item, tags.toArray(new String[]{}));
493 } catch (IOException e1) {
494 Instance.getTraceHandler().error(e1);
495 }
496
d0114000
NR
497 break;
498 case HELP:
499 syntax(true);
500 exitCode = 0;
501 break;
502 case SET_READER:
b0e88ebd 503 exitCode = 255;
d0114000 504 break;
39c3c689
NR
505 case VERSION:
506 System.out
507 .println(String.format("Fanfix version %s"
9fe3f177
NR
508 + "%nhttps://github.com/nikiroo/fanfix/"
509 + "%n\tWritten by Nikiroo",
39c3c689 510 Version.getCurrentVersion()));
b42117f1 511 updates.ok(); // we consider it read
39c3c689 512 break;
333f0e7b 513 case START:
99ccbdf6 514 if (BasicReader.getReader() == null) {
62c63b07
NR
515 Instance.getTraceHandler()
516 .error(new Exception(
517 "No reader type has been configured"));
99ccbdf6
NR
518 exitCode = 10;
519 break;
520 }
b0e88ebd
NR
521 BasicReader.getReader().browse(null);
522 break;
523 case SERVER:
524 if (port == null) {
525 exitCode = 255;
526 break;
527 }
528 try {
62c63b07 529 ServerObject server = new RemoteLibraryServer(key, port);
22b2b942 530 server.setTraceHandler(Instance.getTraceHandler());
edf79e5e 531 server.run();
b0e88ebd 532 } catch (IOException e) {
62c63b07 533 Instance.getTraceHandler().error(e);
b0e88ebd
NR
534 }
535 return;
5e848e6a
NR
536 case STOP_SERVER:
537 if (port == null) {
538 exitCode = 255;
539 break;
540 }
541
468b960b 542 new RemoteLibrary(key, host, port).exit();
5e848e6a 543 break;
b0e88ebd 544 case REMOTE:
99ccbdf6 545 exitCode = 255; // should not be reachable (REMOTE -> START)
333f0e7b 546 break;
08fe2e33
NR
547 }
548 }
549
350bc060
NR
550 try {
551 Instance.getTempFiles().close();
552 } catch (IOException e) {
553 Instance.getTraceHandler()
554 .error(new IOException(
555 "Cannot dispose of the temporary files", e));
2aac79c7
NR
556 }
557
08fe2e33 558 if (exitCode == 255) {
d0114000 559 syntax(false);
08fe2e33
NR
560 }
561
31e28683 562 System.exit(exitCode);
08fe2e33
NR
563 }
564
08fe2e33 565 /**
68e2c6d2 566 * Import the given resource into the {@link LocalLibrary}.
08fe2e33 567 *
d0114000 568 * @param urlString
08fe2e33 569 * the resource to import
92fb0719
NR
570 * @param pg
571 * the optional progress reporter
08fe2e33
NR
572 *
573 * @return the exit return code (0 = success)
574 */
92fb0719 575 public static int imprt(String urlString, Progress pg) {
08fe2e33 576 try {
3b2b638f
NR
577 Story story = Instance.getLibrary().imprt(
578 BasicReader.getUrl(urlString), pg);
08fe2e33
NR
579 System.out.println(story.getMeta().getLuid() + ": \""
580 + story.getMeta().getTitle() + "\" imported.");
581 } catch (IOException e) {
62c63b07 582 Instance.getTraceHandler().error(e);
08fe2e33
NR
583 return 1;
584 }
585
586 return 0;
587 }
588
589 /**
68e2c6d2
NR
590 * Export the {@link Story} from the {@link LocalLibrary} to the given
591 * target.
08fe2e33 592 *
73ce17ef 593 * @param luid
08fe2e33
NR
594 * the story LUID
595 * @param typeString
596 * the {@link OutputType} to use
597 * @param target
598 * the target
92fb0719
NR
599 * @param pg
600 * the optional progress reporter
08fe2e33
NR
601 *
602 * @return the exit return code (0 = success)
603 */
92fb0719
NR
604 public static int export(String luid, String typeString, String target,
605 Progress pg) {
e604986c 606 OutputType type = OutputType.valueOfNullOkUC(typeString, null);
08fe2e33 607 if (type == null) {
62c63b07
NR
608 Instance.getTraceHandler().error(
609 new Exception(trans(StringId.OUTPUT_DESC, typeString)));
08fe2e33
NR
610 return 1;
611 }
612
613 try {
92fb0719 614 Instance.getLibrary().export(luid, type, target, pg);
08fe2e33 615 } catch (IOException e) {
62c63b07 616 Instance.getTraceHandler().error(e);
08fe2e33
NR
617 return 4;
618 }
619
620 return 0;
621 }
622
623 /**
68e2c6d2
NR
624 * List the stories of the given source from the {@link LocalLibrary}
625 * (unless NULL is passed, in which case all stories will be listed).
08fe2e33 626 *
b0e88ebd
NR
627 * @param source
628 * the source to list the known stories of, or NULL to list all
333f0e7b 629 * stories
08fe2e33
NR
630 *
631 * @return the exit return code (0 = success)
632 */
b0e88ebd 633 private static int list(String source) {
f569d249
NR
634 List<MetaData> stories;
635 stories = BasicReader.getReader().getLibrary().getListBySource(source);
636
637 for (MetaData story : stories) {
638 String author = "";
639 if (story.getAuthor() != null && !story.getAuthor().isEmpty()) {
640 author = " (" + story.getAuthor() + ")";
641 }
642
643 System.out.println(story.getLuid() + ": " + story.getTitle()
644 + author);
645 }
08fe2e33
NR
646 return 0;
647 }
648
649 /**
350bc060 650 * Start the current reader for this {@link Story}.
08fe2e33
NR
651 *
652 * @param story
68e2c6d2
NR
653 * the LUID of the {@link Story} in the {@link LocalLibrary}
654 * <b>or</b> the {@link Story} {@link URL}
d0114000 655 * @param chapString
08fe2e33
NR
656 * which {@link Chapter} to read (starting at 1), or NULL to get
657 * the {@link Story} description
658 * @param library
659 * TRUE if the source is the {@link Story} LUID, FALSE if it is a
660 * {@link URL}
661 *
662 * @return the exit return code (0 = success)
663 */
d0114000 664 private static int read(String story, String chapString, boolean library) {
08fe2e33 665 try {
e42573a0 666 Reader reader = BasicReader.getReader();
08fe2e33 667 if (library) {
bc2ea776 668 reader.setMeta(story);
08fe2e33 669 } else {
bc2ea776 670 reader.setMeta(BasicReader.getUrl(story), null);
08fe2e33
NR
671 }
672
d0114000
NR
673 if (chapString != null) {
674 try {
bc2ea776 675 reader.setChapter(Integer.parseInt(chapString));
350bc060 676 reader.read(true);
d0114000 677 } catch (NumberFormatException e) {
62c63b07
NR
678 Instance.getTraceHandler().error(
679 new IOException("Chapter number cannot be parsed: "
680 + chapString, e));
d0114000
NR
681 return 2;
682 }
08fe2e33 683 } else {
350bc060 684 reader.read(true);
08fe2e33
NR
685 }
686 } catch (IOException e) {
62c63b07 687 Instance.getTraceHandler().error(e);
08fe2e33
NR
688 return 1;
689 }
690
691 return 0;
692 }
693
694 /**
695 * Convert the {@link Story} into another format.
696 *
d0114000 697 * @param urlString
08fe2e33
NR
698 * the source {@link Story} to convert
699 * @param typeString
700 * the {@link OutputType} to convert to
d0114000 701 * @param target
08fe2e33
NR
702 * the target file
703 * @param infoCover
704 * TRUE to also export the cover and info file, even if the given
705 * {@link OutputType} does not usually save them
92fb0719
NR
706 * @param pg
707 * the optional progress reporter
08fe2e33
NR
708 *
709 * @return the exit return code (0 = success)
710 */
f7460e4c 711 public static int convert(String urlString, String typeString,
92fb0719 712 String target, boolean infoCover, Progress pg) {
08fe2e33
NR
713 int exitCode = 0;
714
826e4569 715 Instance.getTraceHandler().trace("Convert: " + urlString);
d0114000 716 String sourceName = urlString;
08fe2e33 717 try {
3b2b638f 718 URL source = BasicReader.getUrl(urlString);
08fe2e33
NR
719 sourceName = source.toString();
720 if (source.toString().startsWith("file://")) {
721 sourceName = sourceName.substring("file://".length());
722 }
723
e604986c 724 OutputType type = OutputType.valueOfAllOkUC(typeString, null);
08fe2e33 725 if (type == null) {
62c63b07
NR
726 Instance.getTraceHandler().error(
727 new IOException(trans(StringId.ERR_BAD_OUTPUT_TYPE,
728 typeString)));
08fe2e33
NR
729
730 exitCode = 2;
731 } else {
732 try {
733 BasicSupport support = BasicSupport.getSupport(source);
333f0e7b 734
08fe2e33 735 if (support != null) {
350bc060
NR
736 Instance.getTraceHandler().trace(
737 "Support found: " + support.getClass());
bee7dffe
NR
738 Progress pgIn = new Progress();
739 Progress pgOut = new Progress();
740 if (pg != null) {
741 pg.setMax(2);
742 pg.addProgress(pgIn, 1);
743 pg.addProgress(pgOut, 1);
744 }
08fe2e33 745
0ffa4754 746 Story story = support.process(pgIn);
08fe2e33 747 try {
d0114000 748 target = new File(target).getAbsolutePath();
925298fd
NR
749 BasicOutput.getOutput(type, infoCover, infoCover)
750 .process(story, target, pgOut);
08fe2e33 751 } catch (IOException e) {
62c63b07
NR
752 Instance.getTraceHandler().error(
753 new IOException(trans(StringId.ERR_SAVING,
754 target), e));
08fe2e33
NR
755 exitCode = 5;
756 }
757 } else {
62c63b07
NR
758 Instance.getTraceHandler().error(
759 new IOException(trans(
760 StringId.ERR_NOT_SUPPORTED, source)));
08fe2e33
NR
761
762 exitCode = 4;
763 }
764 } catch (IOException e) {
62c63b07
NR
765 Instance.getTraceHandler().error(
766 new IOException(trans(StringId.ERR_LOADING,
767 sourceName), e));
08fe2e33
NR
768 exitCode = 3;
769 }
770 }
771 } catch (MalformedURLException e) {
62c63b07
NR
772 Instance.getTraceHandler()
773 .error(new IOException(trans(StringId.ERR_BAD_URL,
774 sourceName), e));
08fe2e33
NR
775 exitCode = 1;
776 }
777
778 return exitCode;
779 }
780
781 /**
782 * Simple shortcut method to call {link Instance#getTrans()#getString()}.
783 *
784 * @param id
785 * the ID to translate
786 *
787 * @return the translated result
788 */
789 private static String trans(StringId id, Object... params) {
790 return Instance.getTrans().getString(id, params);
791 }
792
793 /**
d0114000
NR
794 * Display the correct syntax of the program to the user to stdout, or an
795 * error message if the syntax used was wrong on stderr.
796 *
797 * @param showHelp
798 * TRUE to show the syntax help, FALSE to show "syntax error"
08fe2e33 799 */
d0114000
NR
800 private static void syntax(boolean showHelp) {
801 if (showHelp) {
802 StringBuilder builder = new StringBuilder();
803 for (SupportType type : SupportType.values()) {
804 builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(),
805 type.getDesc()));
806 builder.append('\n');
807 }
08fe2e33 808
d0114000
NR
809 String typesIn = builder.toString();
810 builder.setLength(0);
08fe2e33 811
d0114000
NR
812 for (OutputType type : OutputType.values()) {
813 builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(),
4d205683 814 type.getDesc(true)));
d0114000
NR
815 builder.append('\n');
816 }
08fe2e33 817
d0114000 818 String typesOut = builder.toString();
08fe2e33 819
d0114000
NR
820 System.out.println(trans(StringId.HELP_SYNTAX, typesIn, typesOut));
821 } else {
822 System.err.println(trans(StringId.ERR_SYNTAX));
823 }
824 }
825
826 /**
827 * Set the default reader type for this session only (it can be changed in
828 * the configuration file, too, but this value will override it).
829 *
830 * @param readerTypeString
831 * the type
832 */
833 private static int setReaderType(String readerTypeString) {
834 try {
7de079f1
NR
835 ReaderType readerType = ReaderType.valueOf(readerTypeString
836 .toUpperCase());
d0114000
NR
837 BasicReader.setDefaultReaderType(readerType);
838 return 0;
839 } catch (IllegalArgumentException e) {
62c63b07
NR
840 Instance.getTraceHandler().error(
841 new IOException("Unknown reader type: " + readerTypeString,
842 e));
d0114000
NR
843 return 1;
844 }
08fe2e33
NR
845 }
846}