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