Prepare for LocalReader
[fanfix.git] / src / be / nikiroo / fanfix / Main.java
1 package be.nikiroo.fanfix;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7
8 import be.nikiroo.fanfix.bundles.StringId;
9 import be.nikiroo.fanfix.data.Chapter;
10 import be.nikiroo.fanfix.data.Story;
11 import be.nikiroo.fanfix.output.BasicOutput;
12 import be.nikiroo.fanfix.output.BasicOutput.OutputType;
13 import be.nikiroo.fanfix.reader.BasicReader;
14 import be.nikiroo.fanfix.supported.BasicSupport;
15 import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
16
17 /**
18 * Main program entry point.
19 *
20 * @author niki
21 */
22 public class Main {
23 /**
24 * Main program entry point.
25 * <p>
26 * Known environment variables:
27 * <ul>
28 * <li>NOUTF: if set to 1, the program will prefer non-unicode
29 * {@link String}s when possible</li>
30 * <li>CONFIG_DIR: a path where to look for the <tt>.properties</tt> files
31 * before taking the included ones; they will also be saved/updated into
32 * this path when the program starts</li>
33 * </ul>
34 *
35 * @param args
36 * <ol>
37 * <li>--import [URL]: import into library</li> <li>--export [id]
38 * [output_type] [target]: export story to target</li> <li>
39 * --convert [URL] [output_type] [target]: convert URL into
40 * target</li> <li>--read [id]: read the given story from the
41 * library</li> <li>--read-url [URL]: convert on the fly and read
42 * the story, without saving it</li> <li>--list: list the stories
43 * present in the library</li>
44 * </ol>
45 */
46 public static void main(String[] args) {
47 int exitCode = 255;
48
49 if (args.length > 0) {
50 String action = args[0];
51 if (action.equals("--import")) {
52 if (args.length > 1) {
53 exitCode = imprt(args[1]);
54 }
55 } else if (action.equals("--export")) {
56 if (args.length > 3) {
57 exitCode = export(args[1], args[2], args[3]);
58 }
59 } else if (action.equals("--convert")) {
60 if (args.length > 3) {
61 exitCode = convert(
62 args[1],
63 args[2],
64 args[3],
65 args.length > 4 ? args[4].toLowerCase().equals(
66 "+info") : false);
67 }
68 } else if (action.equals("--list")) {
69 exitCode = list(args.length > 1 ? args[1] : null);
70 } else if (action.equals("--read-url")) {
71 if (args.length > 1) {
72 exitCode = read(args[1], args.length > 2 ? args[2] : null,
73 false);
74 }
75 } else if (action.equals("--read")) {
76 if (args.length > 1) {
77 exitCode = read(args[1], args.length > 2 ? args[2] : null,
78 true);
79 }
80 }
81 }
82
83 if (exitCode == 255) {
84 syntax();
85 }
86
87 if (exitCode != 0) {
88 System.exit(exitCode);
89 }
90 }
91
92 /**
93 * Return an {@link URL} from this {@link String}, be it a file path or an
94 * actual {@link URL}.
95 *
96 * @param sourceString
97 * the source
98 *
99 * @return the corresponding {@link URL}
100 *
101 * @throws MalformedURLException
102 * if this is neither a file nor a conventional {@link URL}
103 */
104 private static URL getUrl(String sourceString) throws MalformedURLException {
105 if (sourceString == null || sourceString.isEmpty()) {
106 throw new MalformedURLException("Empty url");
107 }
108
109 URL source = null;
110 try {
111 source = new URL(sourceString);
112 } catch (MalformedURLException e) {
113 File sourceFile = new File(sourceString);
114 source = sourceFile.toURI().toURL();
115 }
116
117 return source;
118 }
119
120 /**
121 * Import the given resource into the {@link Library}.
122 *
123 * @param sourceString
124 * the resource to import
125 *
126 * @return the exit return code (0 = success)
127 */
128 private static int imprt(String sourceString) {
129 try {
130 Story story = Instance.getLibrary().imprt(getUrl(sourceString));
131 System.out.println(story.getMeta().getLuid() + ": \""
132 + story.getMeta().getTitle() + "\" imported.");
133 } catch (IOException e) {
134 Instance.syserr(e);
135 return 1;
136 }
137
138 return 0;
139 }
140
141 /**
142 * Export the {@link Story} from the {@link Library} to the given target.
143 *
144 * @param sourceString
145 * the story LUID
146 * @param typeString
147 * the {@link OutputType} to use
148 * @param target
149 * the target
150 *
151 * @return the exit return code (0 = success)
152 */
153 private static int export(String sourceString, String typeString,
154 String target) {
155 OutputType type = OutputType.valueOfNullOkUC(typeString);
156 if (type == null) {
157 Instance.syserr(new Exception(trans(StringId.OUTPUT_DESC,
158 typeString)));
159 return 1;
160 }
161
162 try {
163 Story story = Instance.getLibrary().imprt(new URL(sourceString));
164 Instance.getLibrary().export(story.getMeta().getLuid(), type,
165 target);
166 } catch (IOException e) {
167 Instance.syserr(e);
168 return 4;
169 }
170
171 return 0;
172 }
173
174 /**
175 * List the stories of the given type from the {@link Library} (unless NULL
176 * is passed, in which case all stories will be listed).
177 *
178 * @param typeString
179 * the {@link SupportType} to list the known stories of, or NULL
180 * to list all stories
181 *
182 * @return the exit return code (0 = success)
183 */
184 private static int list(String typeString) {
185 SupportType type = null;
186 try {
187 type = SupportType.valueOfNullOkUC(typeString);
188 } catch (Exception e) {
189 Instance.syserr(new Exception(
190 trans(StringId.INPUT_DESC, typeString), e));
191 return 1;
192 }
193
194 BasicReader.getReader().start(type);
195
196 return 0;
197 }
198
199 /**
200 * Start the CLI reader for this {@link Story}.
201 *
202 * @param story
203 * the LUID of the {@link Story} in the {@link Library} <b>or</b>
204 * the {@link Story} {@link URL}
205 * @param chap
206 * which {@link Chapter} to read (starting at 1), or NULL to get
207 * the {@link Story} description
208 * @param library
209 * TRUE if the source is the {@link Story} LUID, FALSE if it is a
210 * {@link URL}
211 *
212 * @return the exit return code (0 = success)
213 */
214 private static int read(String story, String chap, boolean library) {
215 try {
216 BasicReader reader = BasicReader.getReader();
217 if (library) {
218 reader.setStory(story);
219 } else {
220 reader.setStory(getUrl(story));
221 }
222
223 if (chap != null) {
224 reader.read(Integer.parseInt(chap));
225 } else {
226 reader.read();
227 }
228 } catch (IOException e) {
229 Instance.syserr(e);
230 return 1;
231 }
232
233 return 0;
234 }
235
236 /**
237 * Convert the {@link Story} into another format.
238 *
239 * @param sourceString
240 * the source {@link Story} to convert
241 * @param typeString
242 * the {@link OutputType} to convert to
243 * @param filename
244 * the target file
245 * @param infoCover
246 * TRUE to also export the cover and info file, even if the given
247 * {@link OutputType} does not usually save them
248 *
249 * @return the exit return code (0 = success)
250 */
251 private static int convert(String sourceString, String typeString,
252 String filename, boolean infoCover) {
253 int exitCode = 0;
254
255 String sourceName = sourceString;
256 try {
257 URL source = getUrl(sourceString);
258 sourceName = source.toString();
259 if (source.toString().startsWith("file://")) {
260 sourceName = sourceName.substring("file://".length());
261 }
262
263 OutputType type = OutputType.valueOfAllOkUC(typeString);
264 if (type == null) {
265 Instance.syserr(new IOException(trans(
266 StringId.ERR_BAD_OUTPUT_TYPE, typeString)));
267
268 exitCode = 2;
269 } else {
270 try {
271 BasicSupport support = BasicSupport.getSupport(source);
272 if (support != null) {
273 Story story = support.process(source);
274
275 try {
276 filename = new File(filename).getAbsolutePath();
277 BasicOutput.getOutput(type, infoCover).process(
278 story, filename);
279 } catch (IOException e) {
280 Instance.syserr(new IOException(trans(
281 StringId.ERR_SAVING, filename), e));
282 exitCode = 5;
283 }
284 } else {
285 Instance.syserr(new IOException(trans(
286 StringId.ERR_NOT_SUPPORTED, source)));
287
288 exitCode = 4;
289 }
290 } catch (IOException e) {
291 Instance.syserr(new IOException(trans(StringId.ERR_LOADING,
292 sourceName), e));
293 exitCode = 3;
294 }
295 }
296 } catch (MalformedURLException e) {
297 Instance.syserr(new IOException(trans(StringId.ERR_BAD_URL,
298 sourceName), e));
299 exitCode = 1;
300 }
301
302 return exitCode;
303 }
304
305 /**
306 * Simple shortcut method to call {link Instance#getTrans()#getString()}.
307 *
308 * @param id
309 * the ID to translate
310 *
311 * @return the translated result
312 */
313 private static String trans(StringId id, Object... params) {
314 return Instance.getTrans().getString(id, params);
315 }
316
317 /**
318 * Display the correct syntax of the program to the user.
319 */
320 private static void syntax() {
321 StringBuilder builder = new StringBuilder();
322 for (SupportType type : SupportType.values()) {
323 builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(),
324 type.getDesc()));
325 builder.append('\n');
326 }
327
328 String typesIn = builder.toString();
329 builder.setLength(0);
330
331 for (OutputType type : OutputType.values()) {
332 builder.append(trans(StringId.ERR_SYNTAX_TYPE, type.toString(),
333 type.getDesc()));
334 builder.append('\n');
335 }
336
337 String typesOut = builder.toString();
338
339 System.err.println(trans(StringId.ERR_SYNTAX, typesIn, typesOut));
340 }
341 }