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