Library fixes + "make install" fix
[fanfix.git] / src / be / nikiroo / fanfix / Library.java
CommitLineData
08fe2e33
NR
1package be.nikiroo.fanfix;
2
3import java.io.File;
4import java.io.IOException;
5import java.net.URL;
6import java.util.ArrayList;
7import java.util.HashMap;
8import java.util.List;
9import java.util.Map;
10import java.util.Map.Entry;
11
12import be.nikiroo.fanfix.bundles.Config;
13import be.nikiroo.fanfix.data.MetaData;
14import be.nikiroo.fanfix.data.Story;
15import be.nikiroo.fanfix.output.BasicOutput;
16import be.nikiroo.fanfix.output.BasicOutput.OutputType;
17import be.nikiroo.fanfix.supported.BasicSupport;
18import be.nikiroo.fanfix.supported.BasicSupport.SupportType;
19
20/**
21 * Manage a library of Stories: import, export, list.
22 * <p>
23 * Each {@link Story} object will be associated with a (local to the library)
24 * unique ID, the LUID, which will be used to identify the {@link Story}.
25 *
26 * @author niki
27 */
28public class Library {
29 private File baseDir;
30 private Map<MetaData, File> stories;
08fe2e33
NR
31 private int lastId;
32
33 /**
34 * Create a new {@link Library} with the given backend directory.
35 *
36 * @param dir
37 * the directoy where to find the {@link Story} objects
38 */
39 public Library(File dir) {
40 this.baseDir = dir;
41 this.stories = new HashMap<MetaData, File>();
42 this.lastId = 0;
43
44 dir.mkdirs();
45 }
46
47 /**
48 * List all the stories of the given source type in the {@link Library}, or
49 * all the stories if NULL is passed as a type.
50 *
51 * @param type
52 * the type of story to retrieve, or NULL for all
53 *
54 * @return the stories
55 */
56 public List<MetaData> getList(SupportType type) {
57 String typeString = type == null ? null : type.getSourceName();
58
59 List<MetaData> list = new ArrayList<MetaData>();
60 for (Entry<MetaData, File> entry : getStories().entrySet()) {
61 String storyType = entry.getValue().getParentFile().getName();
62 if (typeString == null || typeString.equalsIgnoreCase(storyType)) {
63 list.add(entry.getKey());
64 }
65 }
66
67 return list;
68 }
69
70 /**
71 * Retrieve a specific {@link Story}.
72 *
73 * @param luid
74 * the Library UID of the story
75 *
76 * @return the corresponding {@link Story}
77 */
78 public Story getStory(String luid) {
79 if (luid != null) {
80 for (Entry<MetaData, File> entry : getStories().entrySet()) {
81 if (luid.equals(entry.getKey().getLuid())) {
82 try {
fe999aa4
NR
83 SupportType type = SupportType.valueOfAllOkUC(entry
84 .getKey().getType());
85 URL url = entry.getValue().toURI().toURL();
86 if (type != null) {
87 return BasicSupport.getSupport(type).process(url);
88 } else {
89 throw new IOException("Unknown type: "
90 + entry.getKey().getType());
91 }
08fe2e33
NR
92 } catch (IOException e) {
93 // We should not have not-supported files in the
94 // library
95 Instance.syserr(new IOException(
96 "Cannot load file from library: "
97 + entry.getValue().getPath(), e));
98 }
99 }
100 }
101 }
102
103 return null;
104 }
105
106 /**
107 * Import the {@link Story} at the given {@link URL} into the
108 * {@link Library}.
109 *
110 * @param url
111 * the {@link URL} to import
112 *
113 * @return the imported {@link Story}
114 *
115 * @throws IOException
116 * in case of I/O error
117 */
118 public Story imprt(URL url) throws IOException {
119 BasicSupport support = BasicSupport.getSupport(url);
120 if (support == null) {
121 throw new IOException("URL not supported: " + url.toString());
122 }
123
124 getStories(); // refresh lastId
125 Story story = support.process(url);
126 story.getMeta().setLuid(String.format("%03d", (++lastId)));
127 save(story);
128
129 return story;
130 }
131
132 /**
133 * Export the {@link Story} to the given target in the given format.
134 *
135 * @param luid
136 * the {@link Story} ID
137 * @param type
138 * the {@link OutputType} to transform it to
139 * @param target
140 * the target to save to
141 *
142 * @return the saved resource (the main saved {@link File})
143 *
144 * @throws IOException
145 * in case of I/O error
146 */
147 public File export(String luid, OutputType type, String target)
148 throws IOException {
149 BasicOutput out = BasicOutput.getOutput(type, true);
150 if (out == null) {
151 throw new IOException("Output type not supported: " + type);
152 }
153
154 return out.process(getStory(luid), target);
155 }
156
157 /**
158 * Save a story as-is to the {@link Library} -- the LUID <b>must</b> be
159 * correct.
160 *
161 * @param story
162 * the {@link Story} to save
163 *
164 * @throws IOException
165 * in case of I/O error
166 */
167 private void save(Story story) throws IOException {
168 MetaData key = story.getMeta();
169
170 getDir(key).mkdirs();
171 if (!getDir(key).exists()) {
172 throw new IOException("Cannot create library dir");
173 }
174
175 OutputType out;
176 SupportType in;
177 if (key != null && key.isImageDocument()) {
178 in = SupportType.CBZ;
179 out = OutputType.CBZ;
180 } else {
181 in = SupportType.INFO_TEXT;
182 out = OutputType.INFO_TEXT;
183 }
184 BasicOutput it = BasicOutput.getOutput(out, true);
185 File file = it.process(story, getFile(key).getPath());
186 getStories().put(
187 BasicSupport.getSupport(in).processMeta(file.toURI().toURL())
188 .getMeta(), file);
189 }
190
191 /**
192 * The directory (full path) where the {@link Story} related to this
193 * {@link MetaData} should be located on disk.
194 *
195 * @param key
196 * the {@link Story} {@link MetaData}
197 *
198 * @return the target directory
199 */
200 private File getDir(MetaData key) {
201 String source = key.getSource().replaceAll("[^a-zA-Z0-9._+-]", "_");
202 return new File(baseDir, source);
203 }
204
205 /**
206 * The target (full path) where the {@link Story} related to this
207 * {@link MetaData} should be located on disk.
208 *
209 * @param key
210 * the {@link Story} {@link MetaData}
211 *
212 * @return the target
213 */
214 private File getFile(MetaData key) {
215 String title = key.getTitle().replaceAll("[^a-zA-Z0-9._+-]", "_");
216 return new File(getDir(key), key.getLuid() + "_" + title);
217 }
218
219 /**
220 * Return all the known stories in this {@link Library} object.
221 *
222 * @return the stories
223 */
224 private Map<MetaData, File> getStories() {
225 if (stories.isEmpty()) {
226 lastId = 0;
fe999aa4
NR
227 String format = "."
228 + Instance.getConfig().getString(Config.IMAGE_FORMAT_COVER)
229 .toLowerCase();
08fe2e33
NR
230 for (File dir : baseDir.listFiles()) {
231 if (dir.isDirectory()) {
232 for (File file : dir.listFiles()) {
233 try {
234 String path = file.getPath().toLowerCase();
235 if (!path.endsWith(".info")
236 && !path.endsWith(format)) {
fe999aa4
NR
237 // TODO: export .info reading to a class and use
238 // it here
239 SupportType type = SupportType.INFO_TEXT;
240 if (path.toLowerCase().endsWith(".cbz")) {
241 type = SupportType.CBZ;
242 }
243 BasicSupport support = BasicSupport
244 .getSupport(type);
245 MetaData meta = support.processMeta(
08fe2e33 246 file.toURI().toURL()).getMeta();
d3c15421
NR
247 if (meta != null) {
248 stories.put(meta, file);
249 try {
250 int id = Integer.parseInt(meta
251 .getLuid());
252 if (id > lastId) {
253 lastId = id;
254 }
255 } catch (Exception e) {
256 // not normal!!
257 Instance.syserr(new IOException(
258 "Cannot understand the LUID of "
259 + file.getPath() + ": "
260 + meta.getLuid(), e));
08fe2e33 261 }
d3c15421 262 } else {
08fe2e33
NR
263 // not normal!!
264 Instance.syserr(new IOException(
d3c15421
NR
265 "Cannot get metadata for: "
266 + file.getPath()));
08fe2e33
NR
267 }
268 }
269 } catch (IOException e) {
270 // We should not have not-supported files in the
271 // library
272 Instance.syserr(new IOException(
273 "Cannot load file from library: "
274 + file.getPath(), e));
275 }
276 }
277 }
278 }
279 }
280
281 return stories;
282 }
283}