Commit | Line | Data |
---|---|---|
08fe2e33 NR |
1 | package be.nikiroo.fanfix; |
2 | ||
57f02339 | 3 | import java.awt.image.BufferedImage; |
08fe2e33 | 4 | import java.io.File; |
4f661b2b | 5 | import java.io.FileFilter; |
08fe2e33 NR |
6 | import java.io.IOException; |
7 | import java.net.URL; | |
8 | import java.util.ArrayList; | |
22848428 | 9 | import java.util.Collections; |
08fe2e33 NR |
10 | import java.util.HashMap; |
11 | import java.util.List; | |
12 | import java.util.Map; | |
13 | import java.util.Map.Entry; | |
14 | ||
10d558d2 | 15 | import be.nikiroo.fanfix.bundles.Config; |
08fe2e33 NR |
16 | import be.nikiroo.fanfix.data.MetaData; |
17 | import be.nikiroo.fanfix.data.Story; | |
18 | import be.nikiroo.fanfix.output.BasicOutput; | |
19 | import be.nikiroo.fanfix.output.BasicOutput.OutputType; | |
70c9b112 | 20 | import be.nikiroo.fanfix.output.InfoCover; |
08fe2e33 NR |
21 | import be.nikiroo.fanfix.supported.BasicSupport; |
22 | import be.nikiroo.fanfix.supported.BasicSupport.SupportType; | |
68686a37 | 23 | import be.nikiroo.fanfix.supported.InfoReader; |
9843a5e5 | 24 | import be.nikiroo.utils.IOUtils; |
3b2b638f | 25 | import be.nikiroo.utils.Progress; |
08fe2e33 NR |
26 | |
27 | /** | |
28 | * Manage a library of Stories: import, export, list. | |
29 | * <p> | |
30 | * Each {@link Story} object will be associated with a (local to the library) | |
31 | * unique ID, the LUID, which will be used to identify the {@link Story}. | |
57f02339 NR |
32 | * <p> |
33 | * Most of the {@link Library} functions work on either the LUID or a partial | |
34 | * (cover not included) {@link MetaData} object. | |
08fe2e33 NR |
35 | * |
36 | * @author niki | |
37 | */ | |
38 | public class Library { | |
0d781e30 NR |
39 | protected File baseDir; |
40 | protected boolean localSpeed; | |
b0e88ebd | 41 | protected Map<MetaData, File> stories; |
0d781e30 | 42 | |
08fe2e33 | 43 | private int lastId; |
2206ef66 NR |
44 | private OutputType text; |
45 | private OutputType image; | |
08fe2e33 NR |
46 | |
47 | /** | |
48 | * Create a new {@link Library} with the given backend directory. | |
49 | * | |
50 | * @param dir | |
2206ef66 NR |
51 | * the directory where to find the {@link Story} objects |
52 | * @param text | |
53 | * the {@link OutputType} to save the text-focused stories into | |
54 | * @param image | |
55 | * the {@link OutputType} to save the images-focused stories into | |
08fe2e33 | 56 | */ |
2206ef66 | 57 | public Library(File dir, OutputType text, OutputType image) { |
0d781e30 NR |
58 | this(); |
59 | ||
08fe2e33 | 60 | this.baseDir = dir; |
0d781e30 | 61 | |
08fe2e33 | 62 | this.lastId = 0; |
2206ef66 NR |
63 | this.text = text; |
64 | this.image = image; | |
08fe2e33 NR |
65 | |
66 | dir.mkdirs(); | |
67 | } | |
68 | ||
0d781e30 NR |
69 | /** |
70 | * Create a new {@link Library} with no link to the local machine. | |
71 | * <p> | |
72 | * Reserved for extensions. | |
73 | */ | |
74 | protected Library() { | |
75 | this.stories = new HashMap<MetaData, File>(); | |
76 | } | |
77 | ||
4f661b2b NR |
78 | /** |
79 | * Refresh the {@link Library}, that is, make sure all stories are loaded. | |
80 | * | |
81 | * @param pg | |
82 | * the optional progress reporter | |
83 | */ | |
84 | public void refresh(Progress pg) { | |
85 | getStories(pg); | |
86 | } | |
87 | ||
333f0e7b | 88 | /** |
70c9b112 | 89 | * List all the known types (sources) of stories. |
333f0e7b NR |
90 | * |
91 | * @return the types | |
92 | */ | |
10d558d2 | 93 | public synchronized List<String> getTypes() { |
333f0e7b | 94 | List<String> list = new ArrayList<String>(); |
4f661b2b | 95 | for (Entry<MetaData, File> entry : getStories(null).entrySet()) { |
4310bae9 | 96 | String storyType = entry.getKey().getSource(); |
333f0e7b NR |
97 | if (!list.contains(storyType)) { |
98 | list.add(storyType); | |
99 | } | |
100 | } | |
101 | ||
4310bae9 NR |
102 | Collections.sort(list); |
103 | return list; | |
104 | } | |
105 | ||
106 | /** | |
107 | * List all the known authors of stories. | |
108 | * | |
109 | * @return the authors | |
110 | */ | |
111 | public synchronized List<String> getAuthors() { | |
112 | List<String> list = new ArrayList<String>(); | |
4f661b2b | 113 | for (Entry<MetaData, File> entry : getStories(null).entrySet()) { |
4310bae9 NR |
114 | String storyAuthor = entry.getKey().getAuthor(); |
115 | if (!list.contains(storyAuthor)) { | |
116 | list.add(storyAuthor); | |
117 | } | |
118 | } | |
119 | ||
120 | Collections.sort(list); | |
121 | return list; | |
122 | } | |
123 | ||
124 | /** | |
125 | * List all the stories of the given author in the {@link Library}, or all | |
126 | * the stories if NULL is passed as an author. | |
57f02339 NR |
127 | * <p> |
128 | * Cover images not included. | |
4310bae9 NR |
129 | * |
130 | * @param author | |
131 | * the author of the stories to retrieve, or NULL for all | |
132 | * | |
133 | * @return the stories | |
134 | */ | |
135 | public synchronized List<MetaData> getListByAuthor(String author) { | |
136 | List<MetaData> list = new ArrayList<MetaData>(); | |
4f661b2b | 137 | for (Entry<MetaData, File> entry : getStories(null).entrySet()) { |
4310bae9 NR |
138 | String storyAuthor = entry.getKey().getAuthor(); |
139 | if (author == null || author.equalsIgnoreCase(storyAuthor)) { | |
140 | list.add(entry.getKey()); | |
141 | } | |
142 | } | |
143 | ||
144 | Collections.sort(list); | |
333f0e7b NR |
145 | return list; |
146 | } | |
147 | ||
08fe2e33 NR |
148 | /** |
149 | * List all the stories of the given source type in the {@link Library}, or | |
150 | * all the stories if NULL is passed as a type. | |
57f02339 NR |
151 | * <p> |
152 | * Cover images not included. | |
08fe2e33 NR |
153 | * |
154 | * @param type | |
155 | * the type of story to retrieve, or NULL for all | |
156 | * | |
157 | * @return the stories | |
158 | */ | |
b0e88ebd | 159 | public synchronized List<MetaData> getListBySource(String type) { |
08fe2e33 | 160 | List<MetaData> list = new ArrayList<MetaData>(); |
b0e88ebd NR |
161 | for (MetaData meta : getStories(null).keySet()) { |
162 | String storyType = meta.getSource(); | |
333f0e7b | 163 | if (type == null || type.equalsIgnoreCase(storyType)) { |
b0e88ebd | 164 | list.add(meta); |
08fe2e33 NR |
165 | } |
166 | } | |
167 | ||
22848428 | 168 | Collections.sort(list); |
08fe2e33 NR |
169 | return list; |
170 | } | |
171 | ||
301791d3 | 172 | /** |
0d781e30 NR |
173 | * Retrieve a {@link MetaData} corresponding to the given {@link Story}, |
174 | * cover image <b>MAY</b> not be included. | |
301791d3 NR |
175 | * |
176 | * @param luid | |
177 | * the Library UID of the story | |
178 | * | |
179 | * @return the corresponding {@link Story} | |
180 | */ | |
10d558d2 | 181 | public synchronized MetaData getInfo(String luid) { |
301791d3 | 182 | if (luid != null) { |
4f661b2b | 183 | for (Entry<MetaData, File> entry : getStories(null).entrySet()) { |
301791d3 NR |
184 | if (luid.equals(entry.getKey().getLuid())) { |
185 | return entry.getKey(); | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
190 | return null; | |
191 | } | |
192 | ||
2206ef66 NR |
193 | /** |
194 | * Retrieve a {@link File} corresponding to the given {@link Story}. | |
195 | * | |
196 | * @param luid | |
197 | * the Library UID of the story | |
198 | * | |
199 | * @return the corresponding {@link Story} | |
200 | */ | |
10d558d2 | 201 | public synchronized File getFile(String luid) { |
2206ef66 | 202 | if (luid != null) { |
4f661b2b | 203 | for (Entry<MetaData, File> entry : getStories(null).entrySet()) { |
2206ef66 NR |
204 | if (luid.equals(entry.getKey().getLuid())) { |
205 | return entry.getValue(); | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
210 | return null; | |
211 | } | |
212 | ||
57f02339 NR |
213 | /** |
214 | * Return the cover image associated to this story. | |
215 | * | |
216 | * @param luid | |
217 | * the Library UID of the story | |
218 | * | |
219 | * @return the cover image | |
220 | */ | |
221 | public synchronized BufferedImage getCover(String luid) { | |
222 | MetaData meta = getInfo(luid); | |
223 | if (meta != null) { | |
0d781e30 | 224 | getFile(luid); // to help remote implementation |
57f02339 | 225 | try { |
0d781e30 NR |
226 | File infoFile = new File(getExpectedFile(meta).getPath() |
227 | + ".info"); | |
57f02339 NR |
228 | meta = readMeta(infoFile, true).getKey(); |
229 | return meta.getCover(); | |
230 | } catch (IOException e) { | |
231 | Instance.syserr(e); | |
232 | } | |
233 | } | |
234 | ||
235 | return null; | |
236 | } | |
237 | ||
08fe2e33 NR |
238 | /** |
239 | * Retrieve a specific {@link Story}. | |
240 | * | |
241 | * @param luid | |
242 | * the Library UID of the story | |
92fb0719 NR |
243 | * @param pg |
244 | * the optional progress reporter | |
08fe2e33 | 245 | * |
3d247bc3 | 246 | * @return the corresponding {@link Story} or NULL if not found |
08fe2e33 | 247 | */ |
10d558d2 | 248 | public synchronized Story getStory(String luid, Progress pg) { |
08fe2e33 | 249 | if (luid != null) { |
4f661b2b | 250 | for (Entry<MetaData, File> entry : getStories(null).entrySet()) { |
08fe2e33 | 251 | if (luid.equals(entry.getKey().getLuid())) { |
0d781e30 NR |
252 | MetaData meta = entry.getKey(); |
253 | File file = getFile(luid); // to help remote implementation | |
08fe2e33 | 254 | try { |
0d781e30 NR |
255 | SupportType type = SupportType.valueOfAllOkUC(meta |
256 | .getType()); | |
257 | URL url = file.toURI().toURL(); | |
fe999aa4 | 258 | if (type != null) { |
92fb0719 NR |
259 | return BasicSupport.getSupport(type).process(url, |
260 | pg); | |
fe999aa4 NR |
261 | } else { |
262 | throw new IOException("Unknown type: " | |
0d781e30 | 263 | + meta.getType()); |
fe999aa4 | 264 | } |
08fe2e33 NR |
265 | } catch (IOException e) { |
266 | // We should not have not-supported files in the | |
267 | // library | |
268 | Instance.syserr(new IOException( | |
0d781e30 | 269 | "Cannot load file from library: " + file, e)); |
08fe2e33 NR |
270 | } |
271 | } | |
272 | } | |
273 | } | |
274 | ||
92fb0719 NR |
275 | if (pg != null) { |
276 | pg.setMinMax(0, 1); | |
277 | pg.setProgress(1); | |
278 | } | |
279 | ||
08fe2e33 NR |
280 | return null; |
281 | } | |
282 | ||
283 | /** | |
284 | * Import the {@link Story} at the given {@link URL} into the | |
285 | * {@link Library}. | |
286 | * | |
287 | * @param url | |
288 | * the {@link URL} to import | |
92fb0719 NR |
289 | * @param pg |
290 | * the optional progress reporter | |
08fe2e33 NR |
291 | * |
292 | * @return the imported {@link Story} | |
293 | * | |
294 | * @throws IOException | |
295 | * in case of I/O error | |
296 | */ | |
92fb0719 | 297 | public Story imprt(URL url, Progress pg) throws IOException { |
08fe2e33 NR |
298 | BasicSupport support = BasicSupport.getSupport(url); |
299 | if (support == null) { | |
300 | throw new IOException("URL not supported: " + url.toString()); | |
301 | } | |
302 | ||
92fb0719 | 303 | return save(support.process(url, pg), null); |
08fe2e33 NR |
304 | } |
305 | ||
306 | /** | |
307 | * Export the {@link Story} to the given target in the given format. | |
308 | * | |
309 | * @param luid | |
310 | * the {@link Story} ID | |
311 | * @param type | |
312 | * the {@link OutputType} to transform it to | |
313 | * @param target | |
314 | * the target to save to | |
92fb0719 NR |
315 | * @param pg |
316 | * the optional progress reporter | |
08fe2e33 NR |
317 | * |
318 | * @return the saved resource (the main saved {@link File}) | |
319 | * | |
320 | * @throws IOException | |
321 | * in case of I/O error | |
322 | */ | |
92fb0719 | 323 | public File export(String luid, OutputType type, String target, Progress pg) |
08fe2e33 | 324 | throws IOException { |
bee7dffe NR |
325 | Progress pgGetStory = new Progress(); |
326 | Progress pgOut = new Progress(); | |
327 | if (pg != null) { | |
328 | pg.setMax(2); | |
329 | pg.addProgress(pgGetStory, 1); | |
330 | pg.addProgress(pgOut, 1); | |
331 | } | |
332 | ||
08fe2e33 NR |
333 | BasicOutput out = BasicOutput.getOutput(type, true); |
334 | if (out == null) { | |
335 | throw new IOException("Output type not supported: " + type); | |
336 | } | |
337 | ||
bee7dffe | 338 | Story story = getStory(luid, pgGetStory); |
73ce17ef NR |
339 | if (story == null) { |
340 | throw new IOException("Cannot find story to export: " + luid); | |
341 | } | |
342 | ||
bee7dffe | 343 | return out.process(story, target, pgOut); |
08fe2e33 NR |
344 | } |
345 | ||
346 | /** | |
2206ef66 NR |
347 | * Save a {@link Story} to the {@link Library}. |
348 | * | |
349 | * @param story | |
350 | * the {@link Story} to save | |
bee7dffe NR |
351 | * @param pg |
352 | * the optional progress reporter | |
2206ef66 NR |
353 | * |
354 | * @return the same {@link Story}, whose LUID may have changed | |
355 | * | |
356 | * @throws IOException | |
357 | * in case of I/O error | |
358 | */ | |
bee7dffe NR |
359 | public Story save(Story story, Progress pg) throws IOException { |
360 | return save(story, null, pg); | |
2206ef66 NR |
361 | } |
362 | ||
363 | /** | |
364 | * Save a {@link Story} to the {@link Library} -- the LUID <b>must</b> be | |
365 | * correct, or NULL to get the next free one. | |
08fe2e33 NR |
366 | * |
367 | * @param story | |
368 | * the {@link Story} to save | |
2206ef66 NR |
369 | * @param luid |
370 | * the <b>correct</b> LUID or NULL to get the next free one | |
bee7dffe NR |
371 | * @param pg |
372 | * the optional progress reporter | |
2206ef66 NR |
373 | * |
374 | * @return the same {@link Story}, whose LUID may have changed | |
08fe2e33 NR |
375 | * |
376 | * @throws IOException | |
377 | * in case of I/O error | |
378 | */ | |
10d558d2 NR |
379 | public synchronized Story save(Story story, String luid, Progress pg) |
380 | throws IOException { | |
a7d266e6 | 381 | // Do not change the original metadata, but change the original story |
301791d3 | 382 | MetaData key = story.getMeta().clone(); |
a7d266e6 | 383 | story.setMeta(key); |
08fe2e33 | 384 | |
2206ef66 | 385 | if (luid == null || luid.isEmpty()) { |
4f661b2b | 386 | getStories(null); // refresh lastId if needed |
2206ef66 NR |
387 | key.setLuid(String.format("%03d", (++lastId))); |
388 | } else { | |
389 | key.setLuid(luid); | |
390 | } | |
391 | ||
0d781e30 NR |
392 | getExpectedDir(key.getSource()).mkdirs(); |
393 | if (!getExpectedDir(key.getSource()).exists()) { | |
08fe2e33 NR |
394 | throw new IOException("Cannot create library dir"); |
395 | } | |
396 | ||
397 | OutputType out; | |
08fe2e33 | 398 | if (key != null && key.isImageDocument()) { |
2206ef66 | 399 | out = image; |
08fe2e33 | 400 | } else { |
2206ef66 | 401 | out = text; |
08fe2e33 | 402 | } |
2206ef66 | 403 | |
08fe2e33 | 404 | BasicOutput it = BasicOutput.getOutput(out, true); |
0d781e30 | 405 | it.process(story, getExpectedFile(key).getPath(), pg); |
10d558d2 NR |
406 | |
407 | // empty cache | |
408 | stories.clear(); | |
2206ef66 NR |
409 | |
410 | return story; | |
08fe2e33 NR |
411 | } |
412 | ||
10d558d2 NR |
413 | /** |
414 | * Delete the given {@link Story} from this {@link Library}. | |
415 | * | |
416 | * @param luid | |
417 | * the LUID of the target {@link Story} | |
418 | * | |
419 | * @return TRUE if it was deleted | |
420 | */ | |
421 | public synchronized boolean delete(String luid) { | |
422 | boolean ok = false; | |
423 | ||
70c9b112 NR |
424 | List<File> files = getFiles(luid); |
425 | if (!files.isEmpty()) { | |
426 | for (File file : files) { | |
427 | IOUtils.deltree(file); | |
428 | } | |
429 | ||
430 | ok = true; | |
431 | ||
432 | // clear cache | |
433 | stories.clear(); | |
434 | } | |
435 | ||
436 | return ok; | |
437 | } | |
438 | ||
439 | /** | |
440 | * Change the type (source) of the given {@link Story}. | |
441 | * | |
442 | * @param luid | |
443 | * the {@link Story} LUID | |
e1168b3c NR |
444 | * @param newType |
445 | * the new type | |
70c9b112 NR |
446 | * |
447 | * @return TRUE if the {@link Story} was found | |
448 | */ | |
449 | public synchronized boolean changeType(String luid, String newType) { | |
450 | MetaData meta = getInfo(luid); | |
451 | if (meta != null) { | |
452 | meta.setSource(newType); | |
0d781e30 | 453 | File newDir = getExpectedDir(meta.getSource()); |
70c9b112 NR |
454 | if (!newDir.exists()) { |
455 | newDir.mkdir(); | |
456 | } | |
457 | ||
458 | List<File> files = getFiles(luid); | |
459 | for (File file : files) { | |
460 | if (file.getName().endsWith(".info")) { | |
461 | try { | |
462 | String name = file.getName().replaceFirst("\\.info$", | |
463 | ""); | |
464 | InfoCover.writeInfo(newDir, name, meta); | |
465 | file.delete(); | |
466 | } catch (IOException e) { | |
467 | Instance.syserr(e); | |
468 | } | |
469 | } else { | |
470 | file.renameTo(new File(newDir, file.getName())); | |
471 | } | |
472 | } | |
473 | ||
474 | // clear cache | |
475 | stories.clear(); | |
476 | ||
477 | return true; | |
478 | } | |
479 | ||
480 | return false; | |
481 | } | |
482 | ||
0d781e30 NR |
483 | /** |
484 | * The library is accessed locally or at local speed (for operations like | |
485 | * {@link Library#getFile(String)}). | |
486 | * <p> | |
487 | * It could be cached, too, it is only about the access speed. | |
488 | * | |
489 | * @return TRUE if it is accessed locally | |
490 | */ | |
491 | public boolean isLocalSpeed() { | |
492 | return localSpeed; | |
493 | } | |
494 | ||
70c9b112 NR |
495 | /** |
496 | * Return the list of files/dirs on disk for this {@link Story}. | |
497 | * <p> | |
498 | * If the {@link Story} is not found, and empty list is returned. | |
499 | * | |
500 | * @param luid | |
501 | * the {@link Story} LUID | |
502 | * | |
503 | * @return the list of {@link File}s | |
504 | */ | |
505 | private List<File> getFiles(String luid) { | |
506 | List<File> files = new ArrayList<File>(); | |
507 | ||
10d558d2 | 508 | MetaData meta = getInfo(luid); |
0d781e30 | 509 | File file = getFile(luid); // to help remote implementation |
10d558d2 NR |
510 | |
511 | if (file != null) { | |
70c9b112 | 512 | files.add(file); |
9843a5e5 | 513 | |
70c9b112 NR |
514 | String readerExt = getOutputType(meta).getDefaultExtension(true); |
515 | String fileExt = getOutputType(meta).getDefaultExtension(false); | |
516 | ||
517 | String path = file.getAbsolutePath(); | |
518 | if (readerExt != null && !readerExt.equals(fileExt)) { | |
519 | path = path.substring(0, path.length() - readerExt.length()) | |
520 | + fileExt; | |
521 | file = new File(path); | |
522 | ||
523 | if (file.exists()) { | |
524 | files.add(file); | |
10d558d2 | 525 | } |
70c9b112 | 526 | } |
10d558d2 | 527 | |
70c9b112 NR |
528 | File infoFile = new File(path + ".info"); |
529 | if (!infoFile.exists()) { | |
530 | infoFile = new File(path.substring(0, | |
531 | path.length() - fileExt.length()) | |
532 | + ".info"); | |
10d558d2 NR |
533 | } |
534 | ||
70c9b112 NR |
535 | if (infoFile.exists()) { |
536 | files.add(infoFile); | |
537 | } | |
538 | ||
539 | String coverExt = "." | |
540 | + Instance.getConfig().getString(Config.IMAGE_FORMAT_COVER); | |
541 | File coverFile = new File(path + coverExt); | |
542 | if (!coverFile.exists()) { | |
543 | coverFile = new File(path.substring(0, | |
544 | path.length() - fileExt.length()) | |
545 | + coverExt); | |
546 | } | |
547 | ||
548 | if (coverFile.exists()) { | |
549 | files.add(coverFile); | |
550 | } | |
10d558d2 NR |
551 | } |
552 | ||
70c9b112 | 553 | return files; |
10d558d2 NR |
554 | } |
555 | ||
08fe2e33 NR |
556 | /** |
557 | * The directory (full path) where the {@link Story} related to this | |
558 | * {@link MetaData} should be located on disk. | |
559 | * | |
70c9b112 NR |
560 | * @param type |
561 | * the type (source) | |
08fe2e33 NR |
562 | * |
563 | * @return the target directory | |
564 | */ | |
0d781e30 | 565 | private File getExpectedDir(String type) { |
70c9b112 | 566 | String source = type.replaceAll("[^a-zA-Z0-9._+-]", "_"); |
08fe2e33 NR |
567 | return new File(baseDir, source); |
568 | } | |
569 | ||
570 | /** | |
571 | * The target (full path) where the {@link Story} related to this | |
572 | * {@link MetaData} should be located on disk. | |
573 | * | |
574 | * @param key | |
575 | * the {@link Story} {@link MetaData} | |
576 | * | |
577 | * @return the target | |
578 | */ | |
0d781e30 | 579 | private File getExpectedFile(MetaData key) { |
a4143cd7 NR |
580 | String title = key.getTitle(); |
581 | if (title == null) { | |
582 | title = ""; | |
583 | } | |
584 | title = title.replaceAll("[^a-zA-Z0-9._+-]", "_"); | |
0d781e30 NR |
585 | return new File(getExpectedDir(key.getSource()), key.getLuid() + "_" |
586 | + title); | |
08fe2e33 NR |
587 | } |
588 | ||
589 | /** | |
590 | * Return all the known stories in this {@link Library} object. | |
591 | * | |
4f661b2b NR |
592 | * @param pg |
593 | * the optional progress reporter | |
594 | * | |
08fe2e33 NR |
595 | * @return the stories |
596 | */ | |
0d781e30 | 597 | protected synchronized Map<MetaData, File> getStories(Progress pg) { |
4f661b2b NR |
598 | if (pg == null) { |
599 | pg = new Progress(); | |
600 | } else { | |
601 | pg.setMinMax(0, 100); | |
602 | } | |
603 | ||
08fe2e33 NR |
604 | if (stories.isEmpty()) { |
605 | lastId = 0; | |
68686a37 | 606 | |
4f661b2b NR |
607 | File[] dirs = baseDir.listFiles(new FileFilter() { |
608 | public boolean accept(File file) { | |
609 | return file != null && file.isDirectory(); | |
610 | } | |
611 | }); | |
612 | ||
613 | Progress pgDirs = new Progress(0, 100 * dirs.length); | |
614 | pg.addProgress(pgDirs, 100); | |
615 | ||
4f661b2b NR |
616 | for (File dir : dirs) { |
617 | File[] files = dir.listFiles(new FileFilter() { | |
618 | public boolean accept(File file) { | |
619 | return file != null | |
57f02339 NR |
620 | && file.getPath().toLowerCase() |
621 | .endsWith(".info"); | |
4f661b2b NR |
622 | } |
623 | }); | |
624 | ||
625 | Progress pgFiles = new Progress(0, files.length); | |
626 | pgDirs.addProgress(pgFiles, 100); | |
627 | pgDirs.setName("Loading from: " + dir.getName()); | |
628 | ||
629 | for (File file : files) { | |
57f02339 | 630 | pgFiles.setName(file.getName()); |
4f661b2b | 631 | try { |
57f02339 | 632 | Entry<MetaData, File> entry = readMeta(file, false); |
08fe2e33 | 633 | try { |
57f02339 | 634 | int id = Integer.parseInt(entry.getKey().getLuid()); |
4f661b2b NR |
635 | if (id > lastId) { |
636 | lastId = id; | |
08fe2e33 | 637 | } |
4f661b2b | 638 | |
57f02339 | 639 | stories.put(entry.getKey(), entry.getValue()); |
4f661b2b NR |
640 | } catch (Exception e) { |
641 | // not normal!! | |
57f02339 | 642 | throw new IOException( |
4f661b2b NR |
643 | "Cannot understand the LUID of " |
644 | + file.getPath() + ": " | |
57f02339 | 645 | + entry.getKey().getLuid(), e); |
08fe2e33 | 646 | } |
4f661b2b NR |
647 | } catch (IOException e) { |
648 | // We should not have not-supported files in the | |
649 | // library | |
650 | Instance.syserr(new IOException( | |
651 | "Cannot load file from library: " | |
652 | + file.getPath(), e)); | |
08fe2e33 | 653 | } |
57f02339 | 654 | pgFiles.add(1); |
08fe2e33 | 655 | } |
4f661b2b NR |
656 | |
657 | pgFiles.setName(null); | |
08fe2e33 | 658 | } |
4f661b2b NR |
659 | |
660 | pgDirs.setName("Loading directories"); | |
08fe2e33 NR |
661 | } |
662 | ||
663 | return stories; | |
664 | } | |
2206ef66 | 665 | |
57f02339 NR |
666 | private Entry<MetaData, File> readMeta(File infoFile, boolean withCover) |
667 | throws IOException { | |
668 | ||
669 | final MetaData meta = InfoReader.readMeta(infoFile, withCover); | |
670 | ||
671 | // Replace .info with whatever is needed: | |
672 | String path = infoFile.getPath(); | |
673 | path = path.substring(0, path.length() - ".info".length()); | |
674 | ||
675 | String newExt = getOutputType(meta).getDefaultExtension(true); | |
676 | ||
677 | File targetFile = new File(path + newExt); | |
678 | ||
679 | final File ffile = targetFile; | |
680 | return new Entry<MetaData, File>() { | |
681 | public File setValue(File value) { | |
682 | return null; | |
683 | } | |
684 | ||
685 | public File getValue() { | |
686 | return ffile; | |
687 | } | |
688 | ||
689 | public MetaData getKey() { | |
690 | return meta; | |
691 | } | |
692 | }; | |
693 | } | |
694 | ||
2206ef66 NR |
695 | /** |
696 | * Return the {@link OutputType} for this {@link Story}. | |
697 | * | |
698 | * @param meta | |
699 | * the {@link Story} {@link MetaData} | |
700 | * | |
701 | * @return the type | |
702 | */ | |
703 | private OutputType getOutputType(MetaData meta) { | |
704 | if (meta != null && meta.isImageDocument()) { | |
705 | return image; | |
706 | } else { | |
707 | return text; | |
708 | } | |
709 | } | |
08fe2e33 | 710 | } |