1 package be
.nikiroo
.fanfix
.supported
;
3 import java
.awt
.image
.BufferedImage
;
5 import java
.io
.IOException
;
6 import java
.io
.InputStream
;
7 import java
.net
.URISyntaxException
;
9 import java
.util
.ArrayList
;
10 import java
.util
.List
;
11 import java
.util
.Map
.Entry
;
12 import java
.util
.Scanner
;
14 import be
.nikiroo
.fanfix
.Instance
;
15 import be
.nikiroo
.fanfix
.bundles
.Config
;
16 import be
.nikiroo
.fanfix
.data
.MetaData
;
19 * Support class for local stories encoded in textual format, with a few rules:
21 * <li>The title must be on the first line</li>
22 * <li>The author (preceded by nothing, "by " or "©") must be on the second
23 * line, possibly with the publication date in parenthesis (i.e., "
24 * <tt>By Unknown (3rd October 1998)</tt>")</li>
25 * <li>Chapters must be declared with "<tt>Chapter x</tt>" or "
26 * <tt>Chapter x: NAME OF THE CHAPTER</tt>", where "<tt>x</tt>" is the chapter
28 * <li>A description of the story must be given as chapter number 0</li>
29 * <li>A cover may be present, with the same filename but a PNG, JPEG or JPG
35 class Text
extends BasicSupport
{
37 protected boolean isHtml() {
42 public String
getSourceName() {
47 protected MetaData
getMeta(URL source
, InputStream in
) throws IOException
{
48 MetaData meta
= new MetaData();
50 meta
.setTitle(getTitle(reset(in
)));
51 meta
.setAuthor(getAuthor(reset(in
)));
52 meta
.setDate(getDate(reset(in
)));
53 meta
.setTags(new ArrayList
<String
>());
54 meta
.setSource(getSourceName());
55 meta
.setPublisher(""); // often sourceName
56 meta
.setUuid(source
.toString());
58 meta
.setLang(getLang(source
, reset(in
))); // default is EN
59 meta
.setSubject(getSubject(source
));
60 meta
.setType(getType().toString());
61 meta
.setImageDocument(false);
62 meta
.setCover(getCover(source
));
67 private String
getSubject(URL source
) throws IOException
{
69 File file
= new File(source
.toURI());
70 return file
.getParentFile().getName();
71 } catch (URISyntaxException e
) {
72 throw new IOException("Cannot parse the URL to File: "
73 + source
.toString(), e
);
78 private String
getLang(URL source
, InputStream in
) throws IOException
{
79 @SuppressWarnings("resource")
80 Scanner scan
= new Scanner(in
, "UTF-8");
81 scan
.useDelimiter("\\n");
83 scan
.next(); // Author (Date)
84 String chapter0
= scan
.next(); // empty or Chapter 0
85 while (chapter0
.isEmpty()) {
86 chapter0
= scan
.next();
89 String lang
= detectChapter(chapter0
);
93 lang
= lang
.toUpperCase();
99 private String
getTitle(InputStream in
) throws IOException
{
100 @SuppressWarnings("resource")
101 Scanner scan
= new Scanner(in
, "UTF-8");
102 scan
.useDelimiter("\\n");
106 private String
getAuthor(InputStream in
) throws IOException
{
107 @SuppressWarnings("resource")
108 Scanner scan
= new Scanner(in
, "UTF-8");
109 scan
.useDelimiter("\\n");
111 String authorDate
= scan
.next();
113 String author
= authorDate
;
114 int pos
= authorDate
.indexOf('(');
116 author
= authorDate
.substring(0, pos
);
119 return fixAuthor(author
);
122 private String
getDate(InputStream in
) throws IOException
{
123 @SuppressWarnings("resource")
124 Scanner scan
= new Scanner(in
, "UTF-8");
125 scan
.useDelimiter("\\n");
127 String authorDate
= scan
.next();
130 int pos
= authorDate
.indexOf('(');
132 date
= authorDate
.substring(pos
+ 1).trim();
133 pos
= date
.lastIndexOf(')');
135 date
= date
.substring(0, pos
).trim();
143 protected String
getDesc(URL source
, InputStream in
) throws IOException
{
144 return getChapterContent(source
, in
, 0);
147 private BufferedImage
getCover(URL source
) throws IOException
{
150 path
= new File(source
.toURI()).getPath();
151 } catch (URISyntaxException e
) {
156 for (String ext
: new String
[] { ".txt", ".text", ".story" }) {
157 if (path
.endsWith(ext
)) {
158 path
= path
.substring(0, path
.length() - ext
.length());
162 return getImage(source
, path
);
166 protected List
<Entry
<String
, URL
>> getChapters(URL source
, InputStream in
)
168 List
<Entry
<String
, URL
>> chaps
= new ArrayList
<Entry
<String
, URL
>>();
169 @SuppressWarnings("resource")
170 Scanner scan
= new Scanner(in
, "UTF-8");
171 scan
.useDelimiter("\\n");
172 boolean descSkipped
= false;
173 boolean prevLineEmpty
= false;
174 while (scan
.hasNext()) {
175 String line
= scan
.next();
176 if (prevLineEmpty
&& detectChapter(line
) != null) {
178 String chapName
= Integer
.toString(chaps
.size());
179 int pos
= line
.indexOf(':');
180 if (pos
>= 0 && pos
+ 1 < line
.length()) {
181 chapName
= line
.substring(pos
+ 1).trim();
183 final URL value
= source
;
184 final String key
= chapName
;
185 chaps
.add(new Entry
<String
, URL
>() {
186 public URL
setValue(URL value
) {
190 public URL
getValue() {
194 public String
getKey() {
203 prevLineEmpty
= line
.trim().isEmpty();
210 protected String
getChapterContent(URL source
, InputStream in
, int number
)
212 StringBuilder builder
= new StringBuilder();
213 @SuppressWarnings("resource")
214 Scanner scan
= new Scanner(in
, "UTF-8");
215 scan
.useDelimiter("\\n");
216 boolean inChap
= false;
217 while (scan
.hasNext()) {
218 String line
= scan
.next();
219 if (detectChapter(line
, number
) != null) {
221 } else if (inChap
&& detectChapter(line
) != null) {
224 builder
.append(line
);
225 builder
.append("\n");
229 return builder
.toString();
233 protected boolean supports(URL url
) {
234 if ("file".equals(url
.getProtocol())) {
237 file
= new File(url
.toURI());
238 file
= new File(file
.getPath() + ".info");
239 } catch (URISyntaxException e
) {
244 return file
== null || !file
.exists();
251 * Check if the given line looks like a starting chapter in a supported
252 * language, and return the language if it does (or NULL if not).
257 * @return the language or NULL
259 private String
detectChapter(String line
) {
260 return detectChapter(line
, null);
264 * Check if the given line looks like the given starting chapter in a
265 * supported language, and return the language if it does (or NULL if not).
270 * @return the language or NULL
272 private String
detectChapter(String line
, Integer number
) {
273 line
= line
.toUpperCase();
274 for (String lang
: Instance
.getConfig().getString(Config
.CHAPTER
)
276 String chapter
= Instance
.getConfig().getStringX(Config
.CHAPTER
,
278 if (chapter
!= null && !chapter
.isEmpty()) {
279 chapter
= chapter
.toUpperCase() + " ";
280 if (line
.startsWith(chapter
)) {
281 if (number
!= null) {
282 // We want "[CHAPTER] [number]: [name]", with ": [name]"
284 String test
= line
.substring(chapter
.length()).trim();
285 if (test
.startsWith(Integer
.toString(number
))) {
286 test
= test
.substring(
287 Integer
.toString(number
).length()).trim();
288 if (test
.isEmpty() || test
.startsWith(":")) {