1818
1919package org .comixedproject .adaptors .comicbooks ;
2020
21- import java .io .File ;
22- import java .io .FileOutputStream ;
23- import java .io .IOException ;
24- import java .io .OutputStream ;
21+ import java .awt .image .BufferedImage ;
22+ import java .io .*;
23+ import java .util .ArrayList ;
2524import java .util .List ;
25+ import java .util .Objects ;
2626import java .util .Optional ;
27+ import javax .imageio .ImageIO ;
2728import lombok .NonNull ;
2829import lombok .extern .log4j .Log4j2 ;
29- import org .apache .commons .compress .utils .FileNameUtils ;
3030import org .apache .commons .io .FileUtils ;
3131import org .apache .commons .io .FilenameUtils ;
32- import org .apache .commons .lang .StringUtils ;
32+ import org .apache .commons .lang3 .StringUtils ;
3333import org .comixedproject .adaptors .AdaptorException ;
34+ import org .comixedproject .adaptors .GenericUtilitiesAdaptor ;
3435import org .comixedproject .adaptors .archive .ArchiveAdaptor ;
3536import org .comixedproject .adaptors .archive .ArchiveAdaptorException ;
3637import org .comixedproject .adaptors .archive .model .ArchiveEntryType ;
4748import org .comixedproject .model .comicbooks .ComicBook ;
4849import org .comixedproject .model .comicbooks .ComicDetail ;
4950import org .comixedproject .model .comicpages .ComicPage ;
51+ import org .comixedproject .model .comicpages .ComicPageType ;
5052import org .springframework .beans .factory .annotation .Autowired ;
5153import org .springframework .stereotype .Component ;
5254
5860@ Component
5961@ Log4j2
6062public class ComicBookAdaptor {
63+ public static final String COMIC_INFO_XML = "ComicInfo.xml" ;
6164 @ Autowired private FileTypeAdaptor fileTypeAdaptor ;
6265 @ Autowired private ComicFileAdaptor comicFileAdaptor ;
6366 @ Autowired private ComicPageAdaptor comicPageAdaptor ;
6467 @ Autowired private ComicMetadataWriter comicMetadataWriter ;
6568 @ Autowired private FileAdaptor fileAdaptor ;
69+ @ Autowired private GenericUtilitiesAdaptor genericUtilitiesAdaptor ;
6670
6771 /**
6872 * Creates a new comic. Determines the archive type for the underlying file.
@@ -156,11 +160,6 @@ public void save(
156160 final ArchiveAdaptor destinationArchive =
157161 this .fileTypeAdaptor .getArchiveAdaptorFor (targetArchiveType );
158162
159- if (removeDeletedPages ) {
160- log .trace ("Removing deleted pages from comic book" );
161- comicBook .removeDeletedPages ();
162- }
163-
164163 log .trace ("Preparing to save comic book file" );
165164 final ArchiveReadHandle readHandle =
166165 sourceArchive .openArchiveForRead (comicBook .getComicDetail ().getFilename ());
@@ -173,28 +172,73 @@ public void save(
173172 final ArchiveWriteHandle writeHandle =
174173 destinationArchive .openArchiveForWrite (temporaryFilename );
175174
176- log .trace ("Writing comic book pages" );
177- final int length = String .valueOf (comicBook .getPages ().size ()).length ();
178- for (int index = 0 ; index < comicBook .getPages ().size (); index ++) {
179- final ComicPage page = comicBook .getPages ().get (index );
180- if (page != null ) {
181- log .trace ("Reading comic book page content: {}" , page .getFilename ());
182- final byte [] content = sourceArchive .readEntry (readHandle , page .getFilename ());
183- @ NonNull String pageFilename = page .getFilename ();
184- if (StringUtils .isNotEmpty (pageRenamingRule )) {
185- pageFilename =
186- this .comicPageAdaptor .createFilenameFromRule (page , pageRenamingRule , index , length );
175+ final List <ComicPage > oldPages = this .doRemoveOldPages (comicBook );
176+ final List <ComicArchiveEntry > sourceEntries = sourceArchive .getEntries (readHandle );
177+ final int length = String .valueOf (oldPages .size ()).length ();
178+ log .debug ("Processing source archive entries" );
179+ for (int index = 0 ; index < sourceEntries .size (); index ++) {
180+ final ComicArchiveEntry entry = sourceEntries .get (index );
181+ String entryFilename = entry .getFilename ();
182+ log .trace ("Loading entry: {}" , entryFilename );
183+ final byte [] entryContent = sourceArchive .readEntry (readHandle , entryFilename );
184+ final ContentAdaptor contentAdaptor =
185+ this .fileTypeAdaptor .getContentAdaptorFor (entryFilename , entryContent );
186+ if (contentAdaptor != null ) {
187+ log .trace ("Entry type: {}" , contentAdaptor .getArchiveEntryType ());
188+ if (contentAdaptor .getArchiveEntryType () == ArchiveEntryType .IMAGE ) {
189+ boolean includePage = true ;
190+ int entryPageNumber = comicBook .getPages ().size ();
191+
192+ final String entryHash = this .genericUtilitiesAdaptor .createHash (entryContent );
193+ final ComicPage matchingPage =
194+ this .doFindMatchingPage (oldPages , entryFilename , entryHash );
195+ ComicPageType pageType = null ;
196+
197+ if (Objects .nonNull (matchingPage )) {
198+ includePage = !matchingPage .isDeleted ();
199+ pageType = matchingPage .getPageType ();
200+ } else {
201+ log .debug ("No matching page for: {}" , entryFilename );
202+ }
203+
204+ if (includePage ) {
205+ final ComicPage comicPage = new ComicPage (comicBook , entryFilename , entryPageNumber );
206+
207+ // adjust the page filenames
208+ if (!StringUtils .isBlank (pageRenamingRule )) {
209+ final String oldEntryFilename = comicPage .getFilename ();
210+ entryFilename =
211+ this .comicPageAdaptor .createFilenameFromRule (
212+ FilenameUtils .getExtension (oldEntryFilename ),
213+ pageRenamingRule ,
214+ comicPage .getPageNumber (),
215+ length );
216+ log .debug ("Renamed page: {} => {}" , oldEntryFilename , entryFilename );
217+ comicPage .setFilename (entryFilename );
218+ }
219+ log .trace ("Writing page: {}" , entryFilename );
220+ destinationArchive .writeEntry (writeHandle , entryFilename , entryContent );
221+ final BufferedImage image = ImageIO .read (new ByteArrayInputStream (entryContent ));
222+ comicPage .setWidth (image .getWidth ());
223+ comicPage .setHeight (image .getHeight ());
224+ comicPage .setHash (entryHash );
225+ if (Objects .nonNull (pageType )) {
226+ comicPage .setPageType (pageType );
227+ }
228+ comicBook .getPages ().add (comicPage );
229+ }
230+ } else {
231+ if (!entryFilename .equalsIgnoreCase (COMIC_INFO_XML )) {
232+ log .trace ("Writing non-page entry: {}" , entryFilename );
233+ destinationArchive .writeEntry (writeHandle , entryFilename , entryContent );
234+ }
187235 }
188- log .trace ("Writing comic book page content: {}" , pageFilename );
189- destinationArchive .writeEntry (writeHandle , pageFilename , content );
190- log .trace ("Updating the page filename: {}" , pageFilename );
191- page .setFilename (pageFilename );
192236 }
193237 }
194238
195239 log .trace ("Writing comic book metadata" );
196240 destinationArchive .writeEntry (
197- writeHandle , "ComicInfo.xml" , this .comicMetadataWriter .createContent (comicBook ));
241+ writeHandle , COMIC_INFO_XML , this .comicMetadataWriter .createContent (comicBook ));
198242
199243 log .trace ("Closing archives" );
200244 sourceArchive .closeArchiveForRead (readHandle );
@@ -215,7 +259,7 @@ public void save(
215259 comicBook .getComicDetail ().getFilename (),
216260 directory
217261 + File .separator
218- + FileNameUtils . getBaseName (comicBook .getComicDetail ().getFilename ()),
262+ + FilenameUtils . removeExtension (comicBook .getComicDetail ().getFilename ()),
219263 0 ,
220264 targetArchiveType .getExtension ());
221265 log .trace ("Updating filename: {}" , newComicDetailFilename );
@@ -234,6 +278,28 @@ public void save(
234278 }
235279 }
236280
281+ private ComicPage doFindMatchingPage (
282+ final List <ComicPage > oldPages , final String entryFilename , final String entryHash ) {
283+ return oldPages .stream ()
284+ .filter (
285+ oldPage ->
286+ (oldPage .getFilename ().equals (entryFilename ))
287+ || (StringUtils .isNotEmpty (oldPage .getHash ())
288+ && oldPage .getHash ().equals (entryHash )))
289+ .findFirst ()
290+ .orElse (null );
291+ }
292+
293+ private List <ComicPage > doRemoveOldPages (final ComicBook comicBook ) {
294+ log .debug ("Removing old pages from comic book" );
295+ final List <ComicPage > result = new ArrayList <>();
296+ while (!comicBook .getPages ().isEmpty ()) {
297+ log .trace ("Removing page: {}" , comicBook .getPages ().get (0 ).getFilename ());
298+ result .add (comicBook .getPages ().remove (0 ));
299+ }
300+ return result ;
301+ }
302+
237303 /**
238304 * Writes the comic's metadata to a separate file. The file's name is based on that of the comic,
239305 * but with an extension of ".xml".
0 commit comments