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
;
17 import be
.nikiroo
.utils
.Progress
;
20 * Support class for local stories encoded in textual format, with a few rules:
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
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
36 class Text
extends BasicSupport
{
38 protected boolean isHtml() {
43 public String
getSourceName() {
48 protected MetaData
getMeta(URL source
, InputStream in
) throws IOException
{
49 MetaData meta
= new MetaData();
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());
56 meta
.setUrl(source
.toString());
57 meta
.setPublisher("");
58 meta
.setUuid(source
.toString());
60 meta
.setLang(getLang(source
, reset(in
))); // default is EN
61 meta
.setSubject(getSubject(source
));
62 meta
.setType(getType().toString());
63 meta
.setImageDocument(false);
64 meta
.setCover(getCover(source
));
69 private String
getSubject(URL source
) throws IOException
{
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
);
80 private String
getLang(URL source
, InputStream in
) throws IOException
{
81 @SuppressWarnings("resource")
82 Scanner scan
= new Scanner(in
, "UTF-8");
83 scan
.useDelimiter("\\n");
85 scan
.next(); // Author (Date)
86 String chapter0
= scan
.next(); // empty or Chapter 0
87 while (chapter0
.isEmpty()) {
88 chapter0
= scan
.next();
91 String lang
= detectChapter(chapter0
, 0);
94 lang
= detectChapter(chapter0
, 1);
100 lang
= lang
.toUpperCase();
106 private String
getTitle(InputStream in
) throws IOException
{
107 @SuppressWarnings("resource")
108 Scanner scan
= new Scanner(in
, "UTF-8");
109 scan
.useDelimiter("\\n");
113 private String
getAuthor(InputStream in
) throws IOException
{
114 @SuppressWarnings("resource")
115 Scanner scan
= new Scanner(in
, "UTF-8");
116 scan
.useDelimiter("\\n");
118 String authorDate
= scan
.next();
120 String author
= authorDate
;
121 int pos
= authorDate
.indexOf('(');
123 author
= authorDate
.substring(0, pos
);
126 return fixAuthor(author
);
129 private String
getDate(InputStream in
) throws IOException
{
130 @SuppressWarnings("resource")
131 Scanner scan
= new Scanner(in
, "UTF-8");
132 scan
.useDelimiter("\\n");
134 String authorDate
= scan
.next();
137 int pos
= authorDate
.indexOf('(');
139 date
= authorDate
.substring(pos
+ 1).trim();
140 pos
= date
.lastIndexOf(')');
142 date
= date
.substring(0, pos
).trim();
150 protected String
getDesc(URL source
, InputStream in
) throws IOException
{
151 return getChapterContent(source
, in
, 0, null);
154 private BufferedImage
getCover(URL source
) throws IOException
{
157 path
= new File(source
.toURI()).getPath();
158 } catch (URISyntaxException e
) {
163 for (String ext
: new String
[] { ".txt", ".text", ".story" }) {
164 if (path
.endsWith(ext
)) {
165 path
= path
.substring(0, path
.length() - ext
.length());
169 return getImage(this, source
, path
);
173 protected List
<Entry
<String
, URL
>> getChapters(URL source
, InputStream in
,
174 Progress pg
) throws IOException
{
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");
179 boolean prevLineEmpty
= false;
180 while (scan
.hasNext()) {
181 String line
= scan
.next();
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();
188 final URL value
= source
;
189 final String key
= chapName
;
190 chaps
.add(new Entry
<String
, URL
>() {
191 public URL
setValue(URL value
) {
195 public URL
getValue() {
199 public String
getKey() {
205 prevLineEmpty
= line
.trim().isEmpty();
212 protected String
getChapterContent(URL source
, InputStream in
, int number
,
213 Progress pg
) throws IOException
{
214 StringBuilder builder
= new StringBuilder();
215 @SuppressWarnings("resource")
216 Scanner scan
= new Scanner(in
, "UTF-8");
217 scan
.useDelimiter("\\n");
218 boolean inChap
= false;
219 while (scan
.hasNext()) {
220 String line
= scan
.next();
221 if (detectChapter(line
, number
) != null) {
223 } else if (inChap
&& detectChapter(line
, number
+ 1) != null) {
226 builder
.append(line
);
227 builder
.append("\n");
231 return builder
.toString();
235 protected boolean supports(URL url
) {
236 if ("file".equals(url
.getProtocol())) {
239 file
= new File(url
.toURI());
240 file
= new File(file
.getPath() + ".info");
241 } catch (URISyntaxException e
) {
246 return file
== null || !file
.exists();
253 * Check if the given line looks like the given starting chapter in a
254 * supported language, and return the language if it does (or NULL if not).
259 * @return the language or NULL
261 private String
detectChapter(String line
, int number
) {
262 line
= line
.toUpperCase();
263 for (String lang
: Instance
.getConfig().getString(Config
.CHAPTER
)
265 String chapter
= Instance
.getConfig().getStringX(Config
.CHAPTER
,
267 if (chapter
!= null && !chapter
.isEmpty()) {
268 chapter
= chapter
.toUpperCase() + " ";
269 if (line
.startsWith(chapter
)) {
270 // We want "[CHAPTER] [number]: [name]", with ": [name]"
272 String test
= line
.substring(chapter
.length()).trim();
273 if (test
.startsWith(Integer
.toString(number
))) {
275 .substring(Integer
.toString(number
).length())
277 if (test
.isEmpty() || test
.startsWith(":")) {