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