update from master
[fanfix.git] / supported / Cbz.java
CommitLineData
08fe2e33
NR
1package be.nikiroo.fanfix.supported;
2
2aac79c7 3import java.io.File;
08fe2e33 4import java.io.IOException;
298d405a 5import java.io.InputStream;
08fe2e33
NR
6import java.net.URL;
7import java.util.ArrayList;
d3c84ac3 8import java.util.Collections;
2a25f781 9import java.util.HashMap;
d3c84ac3 10import java.util.List;
2a25f781 11import java.util.Map;
08fe2e33
NR
12import java.util.zip.ZipEntry;
13import java.util.zip.ZipInputStream;
14
15import be.nikiroo.fanfix.Instance;
45994ba5 16import be.nikiroo.fanfix.bundles.Config;
08fe2e33 17import be.nikiroo.fanfix.data.Chapter;
7445f856 18import be.nikiroo.fanfix.data.MetaData;
08fe2e33 19import be.nikiroo.fanfix.data.Paragraph;
e5a2f1b3 20import be.nikiroo.fanfix.data.Paragraph.ParagraphType;
08fe2e33 21import be.nikiroo.fanfix.data.Story;
2aac79c7 22import be.nikiroo.utils.IOUtils;
16a81ef7 23import be.nikiroo.utils.Image;
3b2b638f 24import be.nikiroo.utils.Progress;
c289a297 25import be.nikiroo.utils.streams.MarkableFileInputStream;
08fe2e33
NR
26
27/**
28 * Support class for CBZ files (works better with CBZ created with this program,
29 * as they have some metadata available).
30 *
31 * @author niki
32 */
33class Cbz extends Epub {
34 @Override
35 protected boolean supports(URL url) {
36 return url.toString().toLowerCase().endsWith(".cbz");
37 }
38
08fe2e33
NR
39 @Override
40 protected String getDataPrefix() {
41 return "";
42 }
43
44 @Override
45 protected boolean requireInfo() {
46 return false;
47 }
08fe2e33
NR
48
49 @Override
e4fa48a0
NR
50 protected boolean isImagesDocumentByDefault() {
51 return true;
08fe2e33
NR
52 }
53
68686a37 54 @Override
e4fa48a0
NR
55 protected boolean getCover() {
56 return false;
68686a37
NR
57 }
58
08fe2e33 59 @Override
9005532f 60 public Story doProcess(Progress pg) throws IOException {
92fb0719
NR
61 if (pg == null) {
62 pg = new Progress();
63 } else {
64 pg.setMinMax(0, 100);
65 }
3b039231
NR
66
67 pg.setName("Initialising");
92fb0719 68
ed08c171
NR
69 Progress pgMeta = new Progress();
70 pg.addProgress(pgMeta, 10);
7445f856
NR
71 Story story = processMeta(true, pgMeta);
72 MetaData meta = story.getMeta();
091397cb 73
2a25f781 74 pgMeta.done(); // 10%
3b039231 75
d66deb8d 76 File tmpDir = Instance.getInstance().getTempFiles().createTempDir("info-text");
2aac79c7 77 String basename = null;
08fe2e33 78
16a81ef7 79 Map<String, Image> images = new HashMap<String, Image>();
298d405a
NR
80 InputStream cbzIn = null;
81 ZipInputStream zipIn = null;
2aac79c7 82 try {
67837328 83 cbzIn = new MarkableFileInputStream(getSourceFileOriginal());
298d405a 84 zipIn = new ZipInputStream(cbzIn);
2aac79c7
NR
85 for (ZipEntry entry = zipIn.getNextEntry(); entry != null; entry = zipIn
86 .getNextEntry()) {
87 if (!entry.isDirectory()
88 && entry.getName().startsWith(getDataPrefix())) {
89 String entryLName = entry.getName().toLowerCase();
90 boolean imageEntry = false;
8d59ce07 91 for (String ext : bsImages.getImageExt(false)) {
2aac79c7
NR
92 if (entryLName.endsWith(ext)) {
93 imageEntry = true;
94 }
08fe2e33 95 }
45994ba5 96
2aac79c7
NR
97 if (imageEntry) {
98 String uuid = meta.getUuid() + "_" + entry.getName();
99 try {
002972e9
NR
100 Image img = new Image(zipIn);
101 if (img.getSize() == 0) {
102 img.close();
103 throw new IOException(
104 "Empty image not accepted");
105 }
106 images.put(uuid, img);
2aac79c7 107 } catch (Exception e) {
d66deb8d 108 Instance.getInstance().getTraceHandler().error(e);
2aac79c7
NR
109 }
110
111 if (pg.getProgress() < 85) {
112 pg.add(1);
113 }
114 } else if (entryLName.endsWith(".info")) {
115 basename = entryLName.substring(0, entryLName.length()
116 - ".info".length());
117 IOUtils.write(zipIn, new File(tmpDir, entryLName));
118 } else if (entryLName.endsWith(".txt")) {
119 IOUtils.write(zipIn, new File(tmpDir, entryLName));
08fe2e33 120 }
2aac79c7
NR
121 }
122 }
45994ba5
NR
123
124 String ext = "."
d66deb8d 125 + Instance.getInstance().getConfig().getString(Config.FILE_FORMAT_IMAGE_FORMAT_COVER).toLowerCase();
45994ba5
NR
126 String coverName = meta.getUuid() + "_" + basename + ext;
127 Image cover = images.get(coverName);
128 images.remove(coverName);
2a25f781 129
2aac79c7
NR
130 pg.setProgress(85);
131
132 // ZIP order is not correct for us
133 List<String> imagesList = new ArrayList<String>(images.keySet());
134 Collections.sort(imagesList);
135
136 pg.setProgress(90);
137
45994ba5 138 // only the description/cover is kept
298d405a
NR
139 Story origStory = getStoryFromTxt(tmpDir, basename);
140 if (origStory != null) {
27694a13
NR
141 if (origStory.getMeta().getCover() == null) {
142 origStory.getMeta().setCover(story.getMeta().getCover());
143 }
298d405a 144 story.setMeta(origStory.getMeta());
2aac79c7 145 }
45994ba5
NR
146 if (story.getMeta().getCover() == null) {
147 story.getMeta().setCover(cover);
148 }
091397cb 149 story.setChapters(new ArrayList<Chapter>());
92fb0719 150
e5a2f1b3 151 // Check if we can find non-images chapters, for hybrid-cbz support
654e27bb
NR
152 if (origStory != null) {
153 for (Chapter chap : origStory) {
154 Boolean isImages = null;
155 for (Paragraph para : chap) {
156 ParagraphType t = para.getType();
157 if (isImages == null && !t.isText(true)) {
158 isImages = true;
159 }
160 if (t.isText(false)) {
161 String line = para.getContent();
162 // Images are saved in text mode as "[image-link]"
163 if (!(line.startsWith("[") && line.endsWith("]"))) {
164 isImages = false;
165 }
e5a2f1b3
NR
166 }
167 }
e5a2f1b3 168
654e27bb
NR
169 if (isImages != null && !isImages) {
170 story.getChapters().add(chap);
171 chap.setNumber(story.getChapters().size());
172 }
e5a2f1b3
NR
173 }
174 }
175
2aac79c7 176 if (!imagesList.isEmpty()) {
75a6a3ea 177 Chapter chap = new Chapter(story.getChapters().size() + 1, "");
2aac79c7 178 story.getChapters().add(chap);
2a25f781 179
2aac79c7
NR
180 for (String uuid : imagesList) {
181 try {
182 chap.getParagraphs().add(
183 new Paragraph(images.get(uuid)));
184 } catch (Exception e) {
d66deb8d 185 Instance.getInstance().getTraceHandler().error(e);
2aac79c7
NR
186 }
187 }
188 }
d3c84ac3 189
2aac79c7
NR
190 if (meta.getCover() == null && !images.isEmpty()) {
191 meta.setCover(images.get(imagesList.get(0)));
192 meta.setFakeCover(true);
d3c84ac3 193 }
2aac79c7
NR
194 } finally {
195 IOUtils.deltree(tmpDir);
298d405a
NR
196 if (zipIn != null) {
197 zipIn.close();
198 }
199 if (cbzIn != null) {
200 cbzIn.close();
201 }
a9eb3f46
NR
202 }
203
3b039231 204 pg.done();
08fe2e33
NR
205 return story;
206 }
298d405a
NR
207
208 private Story getStoryFromTxt(File tmpDir, String basename) {
209 Story origStory = null;
210
211 File txt = new File(tmpDir, basename + ".txt");
212 if (!txt.exists()) {
213 basename = null;
214 }
215 if (basename != null) {
216 try {
217 BasicSupport support = BasicSupport.getSupport(txt.toURI()
218 .toURL());
219 origStory = support.process(null);
220 } catch (Exception e) {
221 basename = null;
222 }
223 }
224
225 return origStory;
226
227 }
08fe2e33 228}