Commit | Line | Data |
---|---|---|
08fe2e33 NR |
1 | package be.nikiroo.fanfix.supported; |
2 | ||
68686a37 | 3 | import java.awt.image.BufferedImage; |
08fe2e33 NR |
4 | import java.io.File; |
5 | import java.io.IOException; | |
6 | import java.io.InputStream; | |
7 | import java.net.URISyntaxException; | |
8 | import java.net.URL; | |
9 | import java.util.ArrayList; | |
10 | import java.util.List; | |
11 | import java.util.Map.Entry; | |
12 | import java.util.Scanner; | |
13 | ||
14 | import be.nikiroo.fanfix.Instance; | |
15 | import be.nikiroo.fanfix.bundles.Config; | |
68686a37 | 16 | import be.nikiroo.fanfix.data.MetaData; |
ed08c171 | 17 | import be.nikiroo.utils.Progress; |
08fe2e33 NR |
18 | |
19 | /** | |
20 | * Support class for local stories encoded in textual format, with a few rules: | |
21 | * <ul> | |
22 | * <li>The title must be on the first line</li> | |
23 | * <li>The author (preceded by nothing, "by " or "©") must be on the second | |
24 | * line, possibly with the publication date in parenthesis (i.e., " | |
25 | * <tt>By Unknown (3rd October 1998)</tt>")</li> | |
26 | * <li>Chapters must be declared with "<tt>Chapter x</tt>" or " | |
27 | * <tt>Chapter x: NAME OF THE CHAPTER</tt>", where "<tt>x</tt>" is the chapter | |
28 | * number</li> | |
29 | * <li>A description of the story must be given as chapter number 0</li> | |
30 | * <li>A cover may be present, with the same filename but a PNG, JPEG or JPG | |
31 | * extension</li< | |
32 | * </ul> | |
33 | * | |
34 | * @author niki | |
35 | */ | |
36 | class Text extends BasicSupport { | |
37 | @Override | |
38 | protected boolean isHtml() { | |
39 | return false; | |
40 | } | |
41 | ||
42 | @Override | |
43 | public String getSourceName() { | |
44 | return "text"; | |
45 | } | |
46 | ||
47 | @Override | |
68686a37 NR |
48 | protected MetaData getMeta(URL source, InputStream in) throws IOException { |
49 | MetaData meta = new MetaData(); | |
50 | ||
51 | meta.setTitle(getTitle(reset(in))); | |
52 | meta.setAuthor(getAuthor(reset(in))); | |
53 | meta.setDate(getDate(reset(in))); | |
54 | meta.setTags(new ArrayList<String>()); | |
55 | meta.setSource(getSourceName()); | |
2206ef66 NR |
56 | meta.setUrl(source.toString()); |
57 | meta.setPublisher(""); | |
68686a37 NR |
58 | meta.setUuid(source.toString()); |
59 | meta.setLuid(""); | |
211f7ddb | 60 | meta.setLang(getLang(reset(in))); // default is EN |
68686a37 NR |
61 | meta.setSubject(getSubject(source)); |
62 | meta.setType(getType().toString()); | |
63 | meta.setImageDocument(false); | |
64 | meta.setCover(getCover(source)); | |
65 | ||
66 | return meta; | |
08fe2e33 NR |
67 | } |
68 | ||
68686a37 | 69 | private String getSubject(URL source) throws IOException { |
08fe2e33 NR |
70 | try { |
71 | File file = new File(source.toURI()); | |
72 | return file.getParentFile().getName(); | |
73 | } catch (URISyntaxException e) { | |
74 | throw new IOException("Cannot parse the URL to File: " | |
75 | + source.toString(), e); | |
76 | } | |
77 | ||
78 | } | |
79 | ||
211f7ddb | 80 | private String getLang(InputStream in) { |
08fe2e33 NR |
81 | @SuppressWarnings("resource") |
82 | Scanner scan = new Scanner(in, "UTF-8"); | |
83 | scan.useDelimiter("\\n"); | |
84 | scan.next(); // Title | |
85 | scan.next(); // Author (Date) | |
86 | String chapter0 = scan.next(); // empty or Chapter 0 | |
87 | while (chapter0.isEmpty()) { | |
88 | chapter0 = scan.next(); | |
89 | } | |
90 | ||
22848428 NR |
91 | String lang = detectChapter(chapter0, 0); |
92 | if (lang == null) { | |
93 | // No description?? | |
94 | lang = detectChapter(chapter0, 1); | |
95 | } | |
96 | ||
08fe2e33 | 97 | if (lang == null) { |
68686a37 | 98 | lang = "EN"; |
08fe2e33 NR |
99 | } else { |
100 | lang = lang.toUpperCase(); | |
101 | } | |
102 | ||
103 | return lang; | |
104 | } | |
105 | ||
211f7ddb | 106 | private String getTitle(InputStream in) { |
08fe2e33 NR |
107 | @SuppressWarnings("resource") |
108 | Scanner scan = new Scanner(in, "UTF-8"); | |
109 | scan.useDelimiter("\\n"); | |
110 | return scan.next(); | |
111 | } | |
112 | ||
211f7ddb | 113 | private String getAuthor(InputStream in) { |
08fe2e33 NR |
114 | @SuppressWarnings("resource") |
115 | Scanner scan = new Scanner(in, "UTF-8"); | |
116 | scan.useDelimiter("\\n"); | |
117 | scan.next(); | |
118 | String authorDate = scan.next(); | |
119 | ||
120 | String author = authorDate; | |
121 | int pos = authorDate.indexOf('('); | |
122 | if (pos >= 0) { | |
123 | author = authorDate.substring(0, pos); | |
124 | } | |
125 | ||
68686a37 | 126 | return fixAuthor(author); |
08fe2e33 NR |
127 | } |
128 | ||
211f7ddb | 129 | private String getDate(InputStream in) { |
08fe2e33 NR |
130 | @SuppressWarnings("resource") |
131 | Scanner scan = new Scanner(in, "UTF-8"); | |
132 | scan.useDelimiter("\\n"); | |
133 | scan.next(); | |
134 | String authorDate = scan.next(); | |
135 | ||
136 | String date = ""; | |
137 | int pos = authorDate.indexOf('('); | |
138 | if (pos >= 0) { | |
139 | date = authorDate.substring(pos + 1).trim(); | |
140 | pos = date.lastIndexOf(')'); | |
141 | if (pos >= 0) { | |
142 | date = date.substring(0, pos).trim(); | |
143 | } | |
144 | } | |
145 | ||
146 | return date; | |
147 | } | |
148 | ||
149 | @Override | |
68686a37 | 150 | protected String getDesc(URL source, InputStream in) throws IOException { |
ed08c171 | 151 | return getChapterContent(source, in, 0, null); |
08fe2e33 NR |
152 | } |
153 | ||
211f7ddb | 154 | private BufferedImage getCover(URL source) { |
08fe2e33 NR |
155 | String path; |
156 | try { | |
157 | path = new File(source.toURI()).getPath(); | |
158 | } catch (URISyntaxException e) { | |
159 | Instance.syserr(e); | |
160 | path = null; | |
161 | } | |
162 | ||
163 | for (String ext : new String[] { ".txt", ".text", ".story" }) { | |
164 | if (path.endsWith(ext)) { | |
165 | path = path.substring(0, path.length() - ext.length()); | |
166 | } | |
167 | } | |
168 | ||
333f0e7b | 169 | return getImage(this, source, path); |
08fe2e33 NR |
170 | } |
171 | ||
172 | @Override | |
ed08c171 NR |
173 | protected List<Entry<String, URL>> getChapters(URL source, InputStream in, |
174 | Progress pg) throws IOException { | |
08fe2e33 NR |
175 | List<Entry<String, URL>> chaps = new ArrayList<Entry<String, URL>>(); |
176 | @SuppressWarnings("resource") | |
177 | Scanner scan = new Scanner(in, "UTF-8"); | |
178 | scan.useDelimiter("\\n"); | |
08fe2e33 NR |
179 | boolean prevLineEmpty = false; |
180 | while (scan.hasNext()) { | |
181 | String line = scan.next(); | |
22848428 NR |
182 | if (prevLineEmpty && detectChapter(line, chaps.size() + 1) != null) { |
183 | String chapName = Integer.toString(chaps.size() + 1); | |
184 | int pos = line.indexOf(':'); | |
185 | if (pos >= 0 && pos + 1 < line.length()) { | |
186 | chapName = line.substring(pos + 1).trim(); | |
187 | } | |
188 | final URL value = source; | |
189 | final String key = chapName; | |
190 | chaps.add(new Entry<String, URL>() { | |
211f7ddb | 191 | @Override |
22848428 NR |
192 | public URL setValue(URL value) { |
193 | return null; | |
08fe2e33 | 194 | } |
08fe2e33 | 195 | |
211f7ddb | 196 | @Override |
22848428 NR |
197 | public URL getValue() { |
198 | return value; | |
199 | } | |
08fe2e33 | 200 | |
211f7ddb | 201 | @Override |
22848428 NR |
202 | public String getKey() { |
203 | return key; | |
204 | } | |
205 | }); | |
08fe2e33 NR |
206 | } |
207 | ||
208 | prevLineEmpty = line.trim().isEmpty(); | |
209 | } | |
210 | ||
211 | return chaps; | |
212 | } | |
213 | ||
214 | @Override | |
ed08c171 NR |
215 | protected String getChapterContent(URL source, InputStream in, int number, |
216 | Progress pg) throws IOException { | |
08fe2e33 NR |
217 | StringBuilder builder = new StringBuilder(); |
218 | @SuppressWarnings("resource") | |
219 | Scanner scan = new Scanner(in, "UTF-8"); | |
220 | scan.useDelimiter("\\n"); | |
221 | boolean inChap = false; | |
08fe2e33 NR |
222 | while (scan.hasNext()) { |
223 | String line = scan.next(); | |
68686a37 NR |
224 | if (detectChapter(line, number) != null) { |
225 | inChap = true; | |
22848428 | 226 | } else if (inChap && detectChapter(line, number + 1) != null) { |
68686a37 NR |
227 | break; |
228 | } else if (inChap) { | |
229 | builder.append(line); | |
230 | builder.append("\n"); | |
08fe2e33 | 231 | } |
08fe2e33 NR |
232 | } |
233 | ||
234 | return builder.toString(); | |
235 | } | |
236 | ||
237 | @Override | |
238 | protected boolean supports(URL url) { | |
239 | if ("file".equals(url.getProtocol())) { | |
240 | File file; | |
241 | try { | |
242 | file = new File(url.toURI()); | |
243 | file = new File(file.getPath() + ".info"); | |
244 | } catch (URISyntaxException e) { | |
245 | Instance.syserr(e); | |
246 | file = null; | |
247 | } | |
248 | ||
249 | return file == null || !file.exists(); | |
250 | } | |
251 | ||
252 | return false; | |
253 | } | |
254 | ||
08fe2e33 NR |
255 | /** |
256 | * Check if the given line looks like the given starting chapter in a | |
257 | * supported language, and return the language if it does (or NULL if not). | |
258 | * | |
259 | * @param line | |
260 | * the line to check | |
261 | * | |
262 | * @return the language or NULL | |
263 | */ | |
22848428 | 264 | private String detectChapter(String line, int number) { |
08fe2e33 NR |
265 | line = line.toUpperCase(); |
266 | for (String lang : Instance.getConfig().getString(Config.CHAPTER) | |
267 | .split(",")) { | |
268 | String chapter = Instance.getConfig().getStringX(Config.CHAPTER, | |
269 | lang); | |
270 | if (chapter != null && !chapter.isEmpty()) { | |
271 | chapter = chapter.toUpperCase() + " "; | |
272 | if (line.startsWith(chapter)) { | |
22848428 NR |
273 | // We want "[CHAPTER] [number]: [name]", with ": [name]" |
274 | // optional | |
275 | String test = line.substring(chapter.length()).trim(); | |
276 | if (test.startsWith(Integer.toString(number))) { | |
277 | test = test | |
278 | .substring(Integer.toString(number).length()) | |
279 | .trim(); | |
280 | if (test.isEmpty() || test.startsWith(":")) { | |
281 | return lang; | |
08fe2e33 | 282 | } |
08fe2e33 NR |
283 | } |
284 | } | |
285 | } | |
286 | } | |
287 | ||
288 | return null; | |
289 | } | |
290 | } |