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