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