1 package be
.nikiroo
.fanfix
.reader
;
4 import java
.io
.IOException
;
5 import java
.net
.MalformedURLException
;
7 import java
.text
.ParseException
;
8 import java
.text
.SimpleDateFormat
;
9 import java
.util
.AbstractMap
.SimpleEntry
;
10 import java
.util
.ArrayList
;
11 import java
.util
.Date
;
12 import java
.util
.List
;
13 import java
.util
.Map
.Entry
;
15 import be
.nikiroo
.fanfix
.Instance
;
16 import be
.nikiroo
.fanfix
.bundles
.Config
;
17 import be
.nikiroo
.fanfix
.bundles
.UiConfig
;
18 import be
.nikiroo
.fanfix
.data
.MetaData
;
19 import be
.nikiroo
.fanfix
.data
.Story
;
20 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
21 import be
.nikiroo
.fanfix
.library
.LocalLibrary
;
22 import be
.nikiroo
.fanfix
.supported
.BasicSupport
;
23 import be
.nikiroo
.utils
.Progress
;
24 import be
.nikiroo
.utils
.StringUtils
;
25 import be
.nikiroo
.utils
.serial
.SerialUtils
;
28 * The class that handles the different {@link Story} readers you can use.
30 * All the readers should be accessed via {@link BasicReader#getReader()}.
34 public abstract class BasicReader
implements Reader
{
35 private static BasicLibrary defaultLibrary
= Instance
.getLibrary();
36 private static ReaderType defaultType
= ReaderType
.GUI
;
38 private BasicLibrary lib
;
39 private MetaData meta
;
44 * Take the default reader type configuration from the config file.
47 String typeString
= Instance
.getConfig().getString(Config
.READER_TYPE
);
48 if (typeString
!= null && !typeString
.isEmpty()) {
50 ReaderType type
= ReaderType
.valueOf(typeString
.toUpperCase());
52 } catch (IllegalArgumentException e
) {
59 public synchronized Story
getStory(Progress pg
) {
61 story
= getLibrary().getStory(meta
.getLuid(), pg
);
68 public BasicLibrary
getLibrary() {
77 public void setLibrary(BasicLibrary lib
) {
82 public synchronized MetaData
getMeta() {
87 public synchronized void setMeta(MetaData meta
) throws IOException
{
88 setMeta(meta
== null ?
null : meta
.getLuid()); // must check the library
92 public synchronized void setMeta(String luid
) throws IOException
{
94 meta
= getLibrary().getInfo(luid
);
97 throw new IOException("Cannot retrieve story from library: " + luid
);
102 public synchronized void setMeta(URL url
, Progress pg
) throws IOException
{
103 BasicSupport support
= BasicSupport
.getSupport(url
);
104 if (support
== null) {
105 throw new IOException("URL not supported: " + url
.toString());
108 story
= support
.process(pg
);
110 throw new IOException(
111 "Cannot retrieve story from external source: "
115 meta
= story
.getMeta();
119 public int getChapter() {
124 public void setChapter(int chapter
) {
125 this.chapter
= chapter
;
129 * Return a new {@link BasicReader} ready for use if one is configured.
131 * Can return NULL if none are configured.
133 * @return a {@link BasicReader}, or NULL if none configured
135 public static Reader
getReader() {
137 if (defaultType
!= null) {
138 return (Reader
) SerialUtils
.createObject(defaultType
141 } catch (Exception e
) {
142 Instance
.getTraceHandler().error(
143 new Exception("Cannot create a reader of type: "
144 + defaultType
+ " (Not compiled in?)", e
));
151 * The default {@link Reader.ReaderType} used when calling
152 * {@link BasicReader#getReader()}.
154 * @return the default type
156 public static ReaderType
getDefaultReaderType() {
161 * The default {@link Reader.ReaderType} used when calling
162 * {@link BasicReader#getReader()}.
165 * the new default type
167 public static void setDefaultReaderType(ReaderType defaultType
) {
168 BasicReader
.defaultType
= defaultType
;
172 * Change the default {@link LocalLibrary} to open with the
173 * {@link BasicReader}s.
176 * the new {@link LocalLibrary}
178 public static void setDefaultLibrary(BasicLibrary lib
) {
179 BasicReader
.defaultLibrary
= lib
;
183 * Return an {@link URL} from this {@link String}, be it a file path or an
184 * actual {@link URL}.
186 * @param sourceString
189 * @return the corresponding {@link URL}
191 * @throws MalformedURLException
192 * if this is neither a file nor a conventional {@link URL}
194 public static URL
getUrl(String sourceString
) throws MalformedURLException
{
195 if (sourceString
== null || sourceString
.isEmpty()) {
196 throw new MalformedURLException("Empty url");
201 source
= new URL(sourceString
);
202 } catch (MalformedURLException e
) {
203 File sourceFile
= new File(sourceString
);
204 source
= sourceFile
.toURI().toURL();
211 * Describe a {@link Story} from its {@link MetaData} and return a list of
212 * title/value that represent this {@link Story}.
215 * the {@link MetaData} to represent
217 * @return the information
219 public static List
<Entry
<String
, String
>> getMetaDesc(MetaData meta
) {
220 List
<Entry
<String
, String
>> metaDesc
= new ArrayList
<Entry
<String
, String
>>();
224 StringBuilder tags
= new StringBuilder();
225 for (String tag
: meta
.getTags()) {
226 if (tags
.length() > 0) {
232 metaDesc
.add(new SimpleEntry
<String
, String
>("Author", meta
.getAuthor()));
233 metaDesc
.add(new SimpleEntry
<String
, String
>("Publication date",
234 formatDate(meta
.getDate())));
235 metaDesc
.add(new SimpleEntry
<String
, String
>("Published on", meta
237 metaDesc
.add(new SimpleEntry
<String
, String
>("URL", meta
.getUrl()));
238 metaDesc
.add(new SimpleEntry
<String
, String
>("Word count", format(meta
240 metaDesc
.add(new SimpleEntry
<String
, String
>("Source", meta
.getSource()));
241 metaDesc
.add(new SimpleEntry
<String
, String
>("Subject", meta
243 metaDesc
.add(new SimpleEntry
<String
, String
>("Language", meta
.getLang()));
244 metaDesc
.add(new SimpleEntry
<String
, String
>("Tags", tags
.toString()));
250 * Open the {@link Story} with an external reader (the program will be
251 * passed the main file associated with this {@link Story}).
254 * the {@link BasicLibrary} to select the {@link Story} from
256 * the {@link Story} LUID
258 * execute the process synchronously (wait until it is terminated
261 * @throws IOException
262 * in case of I/O error
265 public void openExternal(BasicLibrary lib
, String luid
, boolean sync
)
267 MetaData meta
= lib
.getInfo(luid
);
268 File target
= lib
.getFile(luid
, null);
270 openExternal(meta
, target
, sync
);
274 * Open the {@link Story} with an external reader (the program will be
275 * passed the given target file).
278 * the {@link Story} to load
280 * the target {@link File}
282 * execute the process synchronously (wait until it is terminated
285 * @throws IOException
286 * in case of I/O error
288 protected void openExternal(MetaData meta
, File target
, boolean sync
)
290 String program
= null;
291 if (meta
.isImageDocument()) {
292 program
= Instance
.getUiConfig().getString(
293 UiConfig
.IMAGES_DOCUMENT_READER
);
295 program
= Instance
.getUiConfig().getString(
296 UiConfig
.NON_IMAGES_DOCUMENT_READER
);
299 if (program
!= null && program
.trim().isEmpty()) {
303 start(target
, program
, sync
);
307 * Start a file and open it with the given program if given or the first
308 * default system starter we can find.
313 * the program to use or NULL for the default system starter
315 * execute the process synchronously (wait until it is terminated
318 * @throws IOException
319 * in case of I/O error
321 protected void start(File target
, String program
, boolean sync
)
325 if (program
== null) {
327 for (String starter
: new String
[] { "xdg-open", "open", "see",
330 Instance
.getTraceHandler().trace(
331 "starting external program");
332 proc
= Runtime
.getRuntime().exec(
333 new String
[] { starter
, target
.getAbsolutePath() });
336 } catch (IOException e
) {
340 throw new IOException("Cannot find a program to start the file");
343 Instance
.getTraceHandler().trace("starting external program");
344 proc
= Runtime
.getRuntime().exec(
345 new String
[] { program
, target
.getAbsolutePath() });
348 if (proc
!= null && sync
) {
349 while (proc
.isAlive()) {
352 } catch (InterruptedException e
) {
358 static private String
format(long value
) {
362 if (!display
.isEmpty()) {
363 display
= "." + display
;
365 display
= (value
% 1000) + display
;
366 value
= value
/ 1000;
372 static private String
formatDate(String date
) {
376 ms
= StringUtils
.toTime(date
);
377 } catch (ParseException e
) {
381 SimpleDateFormat sdf
= new SimpleDateFormat(
382 "yyyy-MM-dd'T'HH:mm:ssXXX");
384 ms
= sdf
.parse(date
).getTime();
385 } catch (ParseException e
) {
390 SimpleDateFormat sdf
= new SimpleDateFormat("yyyy-MM-dd");
391 return sdf
.format(new Date(ms
));