Merge branch 'subtree'
[fanfix.git] / src / be / nikiroo / fanfix / reader / BasicReader.java
1 package be.nikiroo.fanfix.reader;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.net.MalformedURLException;
6 import java.net.URL;
7 import java.text.ParseException;
8 import java.text.SimpleDateFormat;
9 import java.util.Date;
10 import java.util.Map;
11 import java.util.TreeMap;
12
13 import be.nikiroo.fanfix.Instance;
14 import be.nikiroo.fanfix.bundles.UiConfig;
15 import be.nikiroo.fanfix.data.MetaData;
16 import be.nikiroo.fanfix.data.Story;
17 import be.nikiroo.fanfix.library.BasicLibrary;
18 import be.nikiroo.utils.StringUtils;
19
20 /**
21 * The class that handles the different {@link Story} readers you can use.
22 *
23 * @author niki
24 */
25 public abstract class BasicReader {
26 /**
27 * Return an {@link URL} from this {@link String}, be it a file path or an
28 * actual {@link URL}.
29 *
30 * @param sourceString
31 * the source
32 *
33 * @return the corresponding {@link URL}
34 *
35 * @throws MalformedURLException
36 * if this is neither a file nor a conventional {@link URL}
37 */
38 public static URL getUrl(String sourceString) throws MalformedURLException {
39 if (sourceString == null || sourceString.isEmpty()) {
40 throw new MalformedURLException("Empty url");
41 }
42
43 URL source = null;
44 try {
45 source = new URL(sourceString);
46 } catch (MalformedURLException e) {
47 File sourceFile = new File(sourceString);
48 source = sourceFile.toURI().toURL();
49 }
50
51 return source;
52 }
53
54 /**
55 * Describe a {@link Story} from its {@link MetaData} and return a list of
56 * title/value that represent this {@link Story}.
57 *
58 * @param meta
59 * the {@link MetaData} to represent
60 *
61 * @return the information
62 */
63 public static Map<String, String> getMetaDesc(MetaData meta) {
64 Map<String, String> metaDesc = new TreeMap<String, String>();
65
66 // TODO: i18n
67
68 StringBuilder tags = new StringBuilder();
69 for (String tag : meta.getTags()) {
70 if (tags.length() > 0) {
71 tags.append(", ");
72 }
73 tags.append(tag);
74 }
75
76 // TODO: i18n
77 metaDesc.put("Author", meta.getAuthor());
78 metaDesc.put("Publication date", formatDate(meta.getDate()));
79 metaDesc.put("Published on", meta.getPublisher());
80 metaDesc.put("URL", meta.getUrl());
81 String count = "";
82 if (meta.getWords() > 0) {
83 count = StringUtils.formatNumber(meta.getWords());
84 }
85 if (meta.isImageDocument()) {
86 metaDesc.put("Number of images", count);
87 } else {
88 metaDesc.put("Number of words", count);
89 }
90 metaDesc.put("Source", meta.getSource());
91 metaDesc.put("Subject", meta.getSubject());
92 metaDesc.put("Language", meta.getLang());
93 metaDesc.put("Tags", tags.toString());
94
95 return metaDesc;
96 }
97
98 /**
99 * Open the {@link Story} with an external reader (the program will be
100 * passed the main file associated with this {@link Story}).
101 *
102 * @param lib
103 * the {@link BasicLibrary} to select the {@link Story} from
104 * @param luid
105 * the {@link Story} LUID
106 * @param sync
107 * execute the process synchronously (wait until it is terminated
108 * before returning)
109 *
110 * @throws IOException
111 * in case of I/O error
112 */
113 public void openExternal(BasicLibrary lib, String luid, boolean sync)
114 throws IOException {
115 MetaData meta = lib.getInfo(luid);
116 File target = lib.getFile(luid, null);
117
118 openExternal(meta, target, sync);
119 }
120
121 /**
122 * Open the {@link Story} with an external reader (the program will be
123 * passed the given target file).
124 *
125 * @param meta
126 * the {@link Story} to load
127 * @param target
128 * the target {@link File}
129 * @param sync
130 * execute the process synchronously (wait until it is terminated
131 * before returning)
132 *
133 * @throws IOException
134 * in case of I/O error
135 */
136 protected void openExternal(MetaData meta, File target, boolean sync)
137 throws IOException {
138 String program = null;
139 if (meta.isImageDocument()) {
140 program = Instance.getInstance().getUiConfig().getString(UiConfig.IMAGES_DOCUMENT_READER);
141 } else {
142 program = Instance.getInstance().getUiConfig().getString(UiConfig.NON_IMAGES_DOCUMENT_READER);
143 }
144
145 if (program != null && program.trim().isEmpty()) {
146 program = null;
147 }
148
149 start(target, program, sync);
150 }
151
152 /**
153 * Start a file and open it with the given program if given or the first
154 * default system starter we can find.
155 *
156 * @param target
157 * the target to open
158 * @param program
159 * the program to use or NULL for the default system starter
160 * @param sync
161 * execute the process synchronously (wait until it is terminated
162 * before returning)
163 *
164 * @throws IOException
165 * in case of I/O error
166 */
167 protected void start(File target, String program, boolean sync)
168 throws IOException {
169
170 Process proc = null;
171 if (program == null) {
172 boolean ok = false;
173 for (String starter : new String[] { "xdg-open", "open", "see",
174 "start", "run" }) {
175 try {
176 Instance.getInstance().getTraceHandler().trace("starting external program");
177 proc = Runtime.getRuntime().exec(new String[] { starter, target.getAbsolutePath() });
178 ok = true;
179 break;
180 } catch (IOException e) {
181 }
182 }
183 if (!ok) {
184 throw new IOException("Cannot find a program to start the file");
185 }
186 } else {
187 Instance.getInstance().getTraceHandler().trace("starting external program");
188 proc = Runtime.getRuntime().exec(
189 new String[] { program, target.getAbsolutePath() });
190 }
191
192 if (proc != null && sync) {
193 try {
194 proc.waitFor();
195 } catch (InterruptedException e) {
196 }
197 }
198 }
199
200 static private String formatDate(String date) {
201 long ms = 0;
202
203 if (date != null && !date.isEmpty()) {
204 try {
205 ms = StringUtils.toTime(date);
206 } catch (ParseException e) {
207 }
208
209 if (ms <= 0) {
210 SimpleDateFormat sdf = new SimpleDateFormat(
211 "yyyy-MM-dd'T'HH:mm:ssSSS");
212 try {
213 ms = sdf.parse(date).getTime();
214 } catch (ParseException e) {
215 }
216 }
217
218 if (ms > 0) {
219 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
220 return sdf.format(new Date(ms));
221 }
222 }
223
224 if (date == null) {
225 date = "";
226 }
227
228 // :(
229 return date;
230 }
231 }