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
;
11 import java
.util
.TreeMap
;
13 import be
.nikiroo
.fanfix
.Instance
;
14 import be
.nikiroo
.fanfix
.bundles
.Config
;
15 import be
.nikiroo
.fanfix
.bundles
.UiConfig
;
16 import be
.nikiroo
.fanfix
.data
.MetaData
;
17 import be
.nikiroo
.fanfix
.data
.Story
;
18 import be
.nikiroo
.fanfix
.library
.BasicLibrary
;
19 import be
.nikiroo
.fanfix
.library
.LocalLibrary
;
20 import be
.nikiroo
.fanfix
.supported
.BasicSupport
;
21 import be
.nikiroo
.utils
.Progress
;
22 import be
.nikiroo
.utils
.StringUtils
;
23 import be
.nikiroo
.utils
.serial
.SerialUtils
;
26 * The class that handles the different {@link Story} readers you can use.
28 * All the readers should be accessed via {@link BasicReader#getReader()}.
32 public abstract class BasicReader
implements Reader
{
33 private static BasicLibrary defaultLibrary
= Instance
.getLibrary();
34 private static ReaderType defaultType
= ReaderType
.GUI
;
36 private BasicLibrary lib
;
37 private MetaData meta
;
42 * Take the default reader type configuration from the config file.
45 String typeString
= Instance
.getConfig().getString(Config
.READER_TYPE
);
46 if (typeString
!= null && !typeString
.isEmpty()) {
48 ReaderType type
= ReaderType
.valueOf(typeString
.toUpperCase());
50 } catch (IllegalArgumentException e
) {
57 public synchronized Story
getStory(Progress pg
) {
59 story
= getLibrary().getStory(meta
.getLuid(), pg
);
66 public BasicLibrary
getLibrary() {
75 public void setLibrary(BasicLibrary lib
) {
80 public synchronized MetaData
getMeta() {
85 public synchronized void setMeta(MetaData meta
) throws IOException
{
86 setMeta(meta
== null ?
null : meta
.getLuid()); // must check the library
90 public synchronized void setMeta(String luid
) throws IOException
{
92 meta
= getLibrary().getInfo(luid
);
95 throw new IOException("Cannot retrieve story from library: " + luid
);
100 public synchronized void setMeta(URL url
, Progress pg
) throws IOException
{
101 BasicSupport support
= BasicSupport
.getSupport(url
);
102 if (support
== null) {
103 throw new IOException("URL not supported: " + url
.toString());
106 story
= support
.process(pg
);
108 throw new IOException(
109 "Cannot retrieve story from external source: "
113 meta
= story
.getMeta();
117 public int getChapter() {
122 public void setChapter(int chapter
) {
123 this.chapter
= chapter
;
127 * Return a new {@link BasicReader} ready for use if one is configured.
129 * Can return NULL if none are configured.
131 * @return a {@link BasicReader}, or NULL if none configured
133 public static Reader
getReader() {
135 if (defaultType
!= null) {
136 return (Reader
) SerialUtils
.createObject(defaultType
139 } catch (Exception e
) {
140 Instance
.getTraceHandler().error(
141 new Exception("Cannot create a reader of type: "
142 + defaultType
+ " (Not compiled in?)", e
));
149 * The default {@link Reader.ReaderType} used when calling
150 * {@link BasicReader#getReader()}.
152 * @return the default type
154 public static ReaderType
getDefaultReaderType() {
159 * The default {@link Reader.ReaderType} used when calling
160 * {@link BasicReader#getReader()}.
163 * the new default type
165 public static void setDefaultReaderType(ReaderType defaultType
) {
166 BasicReader
.defaultType
= defaultType
;
170 * Change the default {@link LocalLibrary} to open with the
171 * {@link BasicReader}s.
174 * the new {@link LocalLibrary}
176 public static void setDefaultLibrary(BasicLibrary lib
) {
177 BasicReader
.defaultLibrary
= lib
;
181 * Return an {@link URL} from this {@link String}, be it a file path or an
182 * actual {@link URL}.
184 * @param sourceString
187 * @return the corresponding {@link URL}
189 * @throws MalformedURLException
190 * if this is neither a file nor a conventional {@link URL}
192 public static URL
getUrl(String sourceString
) throws MalformedURLException
{
193 if (sourceString
== null || sourceString
.isEmpty()) {
194 throw new MalformedURLException("Empty url");
199 source
= new URL(sourceString
);
200 } catch (MalformedURLException e
) {
201 File sourceFile
= new File(sourceString
);
202 source
= sourceFile
.toURI().toURL();
209 * Describe a {@link Story} from its {@link MetaData} and return a list of
210 * title/value that represent this {@link Story}.
213 * the {@link MetaData} to represent
215 * @return the information
217 public static Map
<String
, String
> getMetaDesc(MetaData meta
) {
218 Map
<String
, String
> metaDesc
= new TreeMap
<String
, String
>();
222 StringBuilder tags
= new StringBuilder();
223 for (String tag
: meta
.getTags()) {
224 if (tags
.length() > 0) {
230 metaDesc
.put("Author", meta
.getAuthor());
231 metaDesc
.put("Publication date", formatDate(meta
.getDate()));
232 metaDesc
.put("Published on", meta
.getPublisher());
233 metaDesc
.put("URL", meta
.getUrl());
234 if (meta
.isImageDocument()) {
235 metaDesc
.put("Number of images", format(meta
.getWords()));
237 metaDesc
.put("Number of words", format(meta
.getWords()));
239 metaDesc
.put("Source", meta
.getSource());
240 metaDesc
.put("Subject", meta
.getSubject());
241 metaDesc
.put("Language", meta
.getLang());
242 metaDesc
.put("Tags", tags
.toString());
248 * Open the {@link Story} with an external reader (the program will be
249 * passed the main file associated with this {@link Story}).
252 * the {@link BasicLibrary} to select the {@link Story} from
254 * the {@link Story} LUID
256 * execute the process synchronously (wait until it is terminated
259 * @throws IOException
260 * in case of I/O error
263 public void openExternal(BasicLibrary lib
, String luid
, boolean sync
)
265 MetaData meta
= lib
.getInfo(luid
);
266 File target
= lib
.getFile(luid
, null);
268 openExternal(meta
, target
, sync
);
272 * Open the {@link Story} with an external reader (the program will be
273 * passed the given target file).
276 * the {@link Story} to load
278 * the target {@link File}
280 * execute the process synchronously (wait until it is terminated
283 * @throws IOException
284 * in case of I/O error
286 protected void openExternal(MetaData meta
, File target
, boolean sync
)
288 String program
= null;
289 if (meta
.isImageDocument()) {
290 program
= Instance
.getUiConfig().getString(
291 UiConfig
.IMAGES_DOCUMENT_READER
);
293 program
= Instance
.getUiConfig().getString(
294 UiConfig
.NON_IMAGES_DOCUMENT_READER
);
297 if (program
!= null && program
.trim().isEmpty()) {
301 start(target
, program
, sync
);
305 * Start a file and open it with the given program if given or the first
306 * default system starter we can find.
311 * the program to use or NULL for the default system starter
313 * execute the process synchronously (wait until it is terminated
316 * @throws IOException
317 * in case of I/O error
319 protected void start(File target
, String program
, boolean sync
)
323 if (program
== null) {
325 for (String starter
: new String
[] { "xdg-open", "open", "see",
328 Instance
.getTraceHandler().trace(
329 "starting external program");
330 proc
= Runtime
.getRuntime().exec(
331 new String
[] { starter
, target
.getAbsolutePath() });
334 } catch (IOException e
) {
338 throw new IOException("Cannot find a program to start the file");
341 Instance
.getTraceHandler().trace("starting external program");
342 proc
= Runtime
.getRuntime().exec(
343 new String
[] { program
, target
.getAbsolutePath() });
346 if (proc
!= null && sync
) {
349 } catch (InterruptedException e
) {
354 static private String
format(long value
) {
359 value
= value
/ 1000;
364 if (!display
.isEmpty()) {
365 display
= "." + display
;
367 display
= (value
% 1000) + display
;
368 value
= value
/ 1000;
371 return display
+ suffix
;
374 static private String
formatDate(String date
) {
378 ms
= StringUtils
.toTime(date
);
379 } catch (ParseException e
) {
383 SimpleDateFormat sdf
= new SimpleDateFormat(
384 "yyyy-MM-dd'T'HH:mm:ssSSS");
386 ms
= sdf
.parse(date
).getTime();
387 } catch (ParseException e
) {
392 SimpleDateFormat sdf
= new SimpleDateFormat("yyyy-MM-dd");
393 return sdf
.format(new Date(ms
));