Remove or move java.awt dependencies
[nikiroo-utils.git] / src / be / nikiroo / fanfix / supported / Epub.java
1 package be.nikiroo.fanfix.supported;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.net.URL;
8 import java.net.URLDecoder;
9 import java.util.ArrayList;
10 import java.util.List;
11 import java.util.Map.Entry;
12 import java.util.zip.ZipEntry;
13 import java.util.zip.ZipInputStream;
14
15 import be.nikiroo.fanfix.Instance;
16 import be.nikiroo.fanfix.data.MetaData;
17 import be.nikiroo.utils.IOUtils;
18 import be.nikiroo.utils.Image;
19 import be.nikiroo.utils.MarkableFileInputStream;
20 import be.nikiroo.utils.Progress;
21 import be.nikiroo.utils.StringUtils;
22
23 /**
24 * Support class for EPUB files created with this program (as we need some
25 * metadata available in those we create).
26 *
27 * @author niki
28 */
29 class Epub extends InfoText {
30 protected MetaData meta;
31 private File tmp;
32 private String desc;
33
34 private URL fakeSource;
35 private InputStream fakeIn;
36
37 @Override
38 public String getSourceName() {
39 return "epub";
40 }
41
42 @Override
43 protected boolean supports(URL url) {
44 if (url.getPath().toLowerCase().endsWith(".epub")) {
45 return true;
46 }
47
48 return false;
49 }
50
51 @Override
52 protected MetaData getMeta(URL source, InputStream in) throws IOException {
53 return meta;
54 }
55
56 @Override
57 protected String getDesc(URL source, InputStream in) throws IOException {
58 if (desc != null) {
59 return desc;
60 }
61
62 if (fakeIn != null) {
63 fakeIn.reset();
64 return super.getDesc(fakeSource, fakeIn);
65 }
66
67 return null;
68 }
69
70 @Override
71 protected List<Entry<String, URL>> getChapters(URL source, InputStream in,
72 Progress pg) throws IOException {
73 if (fakeIn != null) {
74 fakeIn.reset();
75 return super.getChapters(fakeSource, fakeIn, pg);
76 }
77
78 return null;
79 }
80
81 @Override
82 protected String getChapterContent(URL source, InputStream in, int number,
83 Progress pg) throws IOException {
84 if (fakeIn != null) {
85 fakeIn.reset();
86 return super.getChapterContent(fakeSource, fakeIn, number, pg);
87 }
88
89 return null;
90 }
91
92 @Override
93 protected void preprocess(URL source, InputStream in) throws IOException {
94 // Note: do NOT close this stream, as it would also close "in"
95 ZipInputStream zipIn = new ZipInputStream(in);
96 tmp = File.createTempFile("fanfic-reader-parser_", ".tmp");
97 File tmpInfo = new File(tmp + ".info");
98 fakeSource = tmp.toURI().toURL();
99 Image cover = null;
100
101 String url = source.toString();
102 String title = null;
103 String author = null;
104
105 for (ZipEntry entry = zipIn.getNextEntry(); entry != null; entry = zipIn
106 .getNextEntry()) {
107 if (!entry.isDirectory()
108 && entry.getName().startsWith(getDataPrefix())) {
109 String entryLName = entry.getName().toLowerCase();
110
111 boolean imageEntry = false;
112 for (String ext : getImageExt(false)) {
113 if (entryLName.endsWith(ext)) {
114 imageEntry = true;
115 }
116 }
117
118 if (entry.getName().equals(getDataPrefix() + "version")) {
119 // Nothing to do for now ("first"
120 // version is 3.0)
121 } else if (entryLName.endsWith(".info")) {
122 // Info file
123 IOUtils.write(zipIn, tmpInfo);
124 } else if (imageEntry) {
125 // Cover
126 if (getCover()) {
127 try {
128 cover = new Image(zipIn);
129 } catch (Exception e) {
130 Instance.getTraceHandler().error(e);
131 }
132 }
133 } else if (entry.getName().equals(getDataPrefix() + "URL")) {
134 String[] descArray = StringUtils
135 .unhtml(IOUtils.readSmallStream(zipIn)).trim()
136 .split("\n");
137 if (descArray.length > 0) {
138 url = descArray[0].trim();
139 }
140 } else if (entry.getName().equals(getDataPrefix() + "SUMMARY")) {
141 String[] descArray = StringUtils
142 .unhtml(IOUtils.readSmallStream(zipIn)).trim()
143 .split("\n");
144 int skip = 0;
145 if (descArray.length > 1) {
146 title = descArray[0].trim();
147 skip = 1;
148 if (descArray.length > 2
149 && descArray[1].startsWith("©")) {
150 author = descArray[1].substring(1).trim();
151 skip = 2;
152 }
153 }
154 this.desc = "";
155 for (int i = skip; i < descArray.length; i++) {
156 this.desc += descArray[i].trim() + "\n";
157 }
158
159 this.desc = this.desc.trim();
160 } else {
161 // Hopefully the data file
162 IOUtils.write(zipIn, tmp);
163 }
164 }
165 }
166
167 if (requireInfo() && (!tmp.exists() || !tmpInfo.exists())) {
168 throw new IOException(
169 "file not supported (maybe not created with this program or corrupt)");
170 }
171
172 if (tmp.exists()) {
173 this.fakeIn = new MarkableFileInputStream(new FileInputStream(tmp));
174 }
175
176 if (tmpInfo.exists()) {
177 meta = InfoReader.readMeta(tmpInfo, true);
178 if (cover != null) {
179 meta.setCover(cover);
180 }
181 tmpInfo.delete();
182 } else {
183 if (title == null || title.isEmpty()) {
184 title = new File(source.getPath()).getName();
185 if (title.toLowerCase().endsWith(".cbz")) {
186 title = title.substring(0, title.length() - 4);
187 }
188 title = URLDecoder.decode(title, "UTF-8").trim();
189 }
190
191 meta = new MetaData();
192 meta.setLang("EN");
193 meta.setTags(new ArrayList<String>());
194 meta.setSource(getSourceName());
195 meta.setUuid(url);
196 meta.setUrl(url);
197 meta.setTitle(title);
198 meta.setAuthor(author);
199 }
200 }
201
202 @Override
203 protected void close() throws IOException {
204 if (tmp != null && tmp.exists()) {
205 if (!tmp.delete()) {
206 tmp.deleteOnExit();
207 }
208 }
209
210 tmp = null;
211
212 if (fakeIn != null) {
213 fakeIn.close();
214 }
215
216 super.close();
217 }
218
219 protected String getDataPrefix() {
220 return "DATA/";
221 }
222
223 protected boolean requireInfo() {
224 return true;
225 }
226
227 protected boolean getCover() {
228 return true;
229 }
230 }