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