change config names
[fanfix.git] / src / be / nikiroo / fanfix / supported / InfoReader.java
CommitLineData
68686a37
NR
1package be.nikiroo.fanfix.supported;
2
3import java.io.File;
4import java.io.FileInputStream;
5import java.io.FileNotFoundException;
6import java.io.IOException;
7import java.io.InputStream;
333f0e7b 8import java.net.URL;
68686a37
NR
9import java.util.ArrayList;
10import java.util.List;
7445f856 11import java.util.Scanner;
68686a37 12
2d2a3222
NR
13import be.nikiroo.fanfix.Instance;
14import be.nikiroo.fanfix.bundles.Config;
68686a37 15import be.nikiroo.fanfix.data.MetaData;
bb7021f2 16import be.nikiroo.utils.Image;
67837328 17import be.nikiroo.utils.streams.MarkableFileInputStream;
68686a37
NR
18
19// not complete: no "description" tag
20public class InfoReader {
57f02339
NR
21 public static MetaData readMeta(File infoFile, boolean withCover)
22 throws IOException {
68686a37
NR
23 if (infoFile == null) {
24 throw new IOException("File is null");
25 }
26
27 if (infoFile.exists()) {
67837328 28 InputStream in = new MarkableFileInputStream(infoFile);
68686a37 29 try {
57f02339 30 return createMeta(infoFile.toURI().toURL(), in, withCover);
68686a37
NR
31 } finally {
32 in.close();
68686a37 33 }
68686a37 34 }
211f7ddb
NR
35
36 throw new FileNotFoundException(
37 "File given as argument does not exists: "
38 + infoFile.getAbsolutePath());
68686a37
NR
39 }
40
57f02339
NR
41 private static MetaData createMeta(URL sourceInfoFile, InputStream in,
42 boolean withCover) throws IOException {
68686a37
NR
43 MetaData meta = new MetaData();
44
45 meta.setTitle(getInfoTag(in, "TITLE"));
46 meta.setAuthor(getInfoTag(in, "AUTHOR"));
47 meta.setDate(getInfoTag(in, "DATE"));
48 meta.setTags(getInfoTagList(in, "TAGS", ","));
49 meta.setSource(getInfoTag(in, "SOURCE"));
2206ef66 50 meta.setUrl(getInfoTag(in, "URL"));
68686a37
NR
51 meta.setPublisher(getInfoTag(in, "PUBLISHER"));
52 meta.setUuid(getInfoTag(in, "UUID"));
53 meta.setLuid(getInfoTag(in, "LUID"));
54 meta.setLang(getInfoTag(in, "LANG"));
55 meta.setSubject(getInfoTag(in, "SUBJECT"));
56 meta.setType(getInfoTag(in, "TYPE"));
57 meta.setImageDocument(getInfoTagBoolean(in, "IMAGES_DOCUMENT", false));
57f02339 58 if (withCover) {
16a81ef7
NR
59 String infoTag = getInfoTag(in, "COVER");
60 if (infoTag != null && !infoTag.trim().isEmpty()) {
0ffa4754 61 meta.setCover(BasicSupportHelper.getImage(null, sourceInfoFile,
16a81ef7
NR
62 infoTag));
63 }
2d2a3222 64 if (meta.getCover() == null) {
bb7021f2
NR
65 // Second chance: try to check for a cover next to the info file
66 meta.setCover(getCoverByName(sourceInfoFile));
2d2a3222 67 }
57f02339 68 }
793f1071
NR
69 try {
70 meta.setWords(Long.parseLong(getInfoTag(in, "WORDCOUNT")));
71 } catch (NumberFormatException e) {
72 meta.setWords(0);
73 }
74 meta.setCreationDate(getInfoTag(in, "CREATION_DATE"));
a9eb3f46 75 meta.setFakeCover(Boolean.parseBoolean(getInfoTag(in, "FAKE_COVER")));
68686a37 76
57f02339 77 if (withCover && meta.getCover() == null) {
0ffa4754 78 meta.setCover(BasicSupportHelper.getDefaultCover(meta.getSubject()));
68686a37
NR
79 }
80
81 return meta;
82 }
83
bb7021f2
NR
84 /**
85 * Return the cover image if it is next to the source file.
86 *
87 * @param sourceInfoFile
88 * the source file
89 *
90 * @return the cover if present, NULL if not
91 */
92 public static Image getCoverByName(URL sourceInfoFile) {
30478c5b
NR
93 Image cover = null;
94
95 File basefile = new File(sourceInfoFile.getFile());
96
97 String ext = "."
13fdb89a 98 + Instance.getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER)
30478c5b
NR
99 .toLowerCase();
100
101 // Without removing ext
102 cover = BasicSupportHelper.getImage(null, sourceInfoFile,
103 basefile.getAbsolutePath() + ext);
104
105 // Try without ext
106 String name = basefile.getName();
107 int pos = name.lastIndexOf(".");
108 if (cover == null && pos > 0) {
109 name = name.substring(0, pos);
9ac581ab 110 basefile = new File(basefile.getParent(), name);
30478c5b 111
30478c5b
NR
112 cover = BasicSupportHelper.getImage(null, sourceInfoFile,
113 basefile.getAbsolutePath() + ext);
bb7021f2
NR
114 }
115
30478c5b 116 return cover;
bb7021f2
NR
117 }
118
68686a37
NR
119 private static boolean getInfoTagBoolean(InputStream in, String key,
120 boolean def) throws IOException {
121 Boolean value = getInfoTagBoolean(in, key);
122 return value == null ? def : value;
123 }
124
125 private static Boolean getInfoTagBoolean(InputStream in, String key)
126 throws IOException {
127 String value = getInfoTag(in, key);
128 if (value != null && !value.trim().isEmpty()) {
129 value = value.toLowerCase().trim();
130 return value.equals("1") || value.equals("on")
131 || value.equals("true") || value.equals("yes");
132 }
133
134 return null;
135 }
136
137 private static List<String> getInfoTagList(InputStream in, String key,
138 String separator) throws IOException {
139 List<String> list = new ArrayList<String>();
140 String tt = getInfoTag(in, key);
141 if (tt != null) {
142 for (String tag : tt.split(separator)) {
143 list.add(tag.trim());
144 }
145 }
146
147 return list;
148 }
149
150 /**
151 * Return the value of the given tag in the <tt>.info</tt> file if present.
152 *
153 * @param key
154 * the tag key
155 *
156 * @return the value or NULL
157 *
158 * @throws IOException
159 * in case of I/O error
160 */
161 private static String getInfoTag(InputStream in, String key)
162 throws IOException {
163 key = "^" + key + "=";
164
165 if (in != null) {
166 in.reset();
7445f856 167 String value = getLine(in, key, 0);
68686a37
NR
168 if (value != null && !value.isEmpty()) {
169 value = value.trim().substring(key.length() - 1).trim();
170 if (value.startsWith("'") && value.endsWith("'")
171 || value.startsWith("\"") && value.endsWith("\"")) {
172 value = value.substring(1, value.length() - 1).trim();
173 }
174
175 return value;
176 }
177 }
178
179 return null;
180 }
7445f856
NR
181
182 /**
183 * Return the first line from the given input which correspond to the given
184 * selectors.
185 *
186 * @param in
187 * the input
188 * @param needle
189 * a string that must be found inside the target line (also
190 * supports "^" at start to say "only if it starts with" the
191 * needle)
192 * @param relativeLine
193 * the line to return based upon the target line position (-1 =
194 * the line before, 0 = the target line...)
195 *
196 * @return the line
197 */
198 static private String getLine(InputStream in, String needle,
199 int relativeLine) {
200 return getLine(in, needle, relativeLine, true);
201 }
202
203 /**
204 * Return a line from the given input which correspond to the given
205 * selectors.
206 *
207 * @param in
208 * the input
209 * @param needle
210 * a string that must be found inside the target line (also
211 * supports "^" at start to say "only if it starts with" the
212 * needle)
213 * @param relativeLine
214 * the line to return based upon the target line position (-1 =
215 * the line before, 0 = the target line...)
216 * @param first
217 * takes the first result (as opposed to the last one, which will
218 * also always spend the input)
219 *
220 * @return the line
221 */
222 static private String getLine(InputStream in, String needle,
223 int relativeLine, boolean first) {
224 String rep = null;
225
226 List<String> lines = new ArrayList<String>();
227 @SuppressWarnings("resource")
228 Scanner scan = new Scanner(in, "UTF-8");
229 int index = -1;
230 scan.useDelimiter("\\n");
231 while (scan.hasNext()) {
232 lines.add(scan.next());
233
234 if (index == -1) {
235 if (needle.startsWith("^")) {
236 if (lines.get(lines.size() - 1).startsWith(
237 needle.substring(1))) {
238 index = lines.size() - 1;
239 }
240
241 } else {
242 if (lines.get(lines.size() - 1).contains(needle)) {
243 index = lines.size() - 1;
244 }
245 }
246 }
247
248 if (index >= 0 && index + relativeLine < lines.size()) {
249 rep = lines.get(index + relativeLine);
250 if (first) {
251 break;
252 }
253 }
254 }
255
256 return rep;
257 }
68686a37 258}