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