package org.rr.jeborker.metadata;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.apache.commons.lang.math.NumberUtils;
import org.rr.commons.log.LoggerFactory;
import org.rr.commons.mufs.IResourceHandler;
import org.rr.commons.mufs.MimeUtils;
import org.rr.commons.utils.CommonUtils;
import org.rr.commons.utils.StringUtil;
import org.rr.jeborker.metadata.ComicBookMetadataReader.COMICBOOK_METADATA_TYPES;
import org.rr.jeborker.metadata.comicbook.ArchiveHandlerFactory;
import org.rr.jeborker.metadata.comicbook.IArchiveHandler;
public class MetadataUtils {
/**
* searches for all metadata properties matching to the given one and returns them.
* @param ref The ref to be searched. This one is in the result list in any case.
* @param allMetadata The metadata list to be searched.
* @return The list with all metadata instances matching with the given one (including the reference one).
* Never returns <code>null</code>.
*/
public static List<MetadataProperty> getSameProperties(MetadataProperty ref, List<MetadataProperty> allMetadata) {
final ArrayList<MetadataProperty> result = new ArrayList<>(3);
for (MetadataProperty metadataProperty : allMetadata) {
if(comparePropertiesForMerge(metadataProperty, ref)) {
result.add(metadataProperty);
}
}
return result;
}
/**
* Compares the metadata properties if they could be merged to one property. Properties
* can only be merged if they have the same value and size.
*
* @param metadataProperty1 The first property to be compared.
* @param metadataProperty2 The second property to be compared.
* @return <code>true</code> for merge and <code>false</code> otherwise.
*/
private static boolean comparePropertiesForMerge(final MetadataProperty metadataProperty1, MetadataProperty metadataProperty2) {
if(metadataProperty1 == metadataProperty2) {
return true;
}
// test for value
boolean result = metadataProperty2.getValues().size() == 1 && metadataProperty1.getValues().size() == 1
&& CommonUtils.compareTo(metadataProperty2.getValues().get(0), metadataProperty1.getValues().get(0)) == 0;
final String metadataProperty1Name = StringUtil.toString(metadataProperty1.getName()).toLowerCase();
final String metadataProperty2Name = StringUtil.toString(metadataProperty2.getName()).toLowerCase();
if (result && metadataProperty1Name.equals(metadataProperty2Name)) {
// name is the same
return true;
} else if(StringUtil.compareTwice(metadataProperty1Name, metadataProperty2Name, "createdate", "creationdate")) {
//merge createdate and creationdate because they have the same sense
return true;
} else if(StringUtil.compareTwice(metadataProperty1Name, metadataProperty2Name, "modifydate", "moddate")) {
//merge createdate and creationdate because they have the same sense
return true;
} else if(StringUtil.compareTwice(metadataProperty1Name, metadataProperty2Name, "calibrerating", "rating")) {
return true;
} else {
return false;
}
}
/**
* Copies the metadata from the source to target. This method only works with the same ebook types.
*/
public static void copyMetadata(IResourceHandler source, IResourceHandler target) {
if(!source.getMimeType(true).equals(target.getMimeType(true))) {
throw new IllegalArgumentException("Can't copy metadata from " + source + " to " + target);
}
IMetadataReader sourceReader = MetadataHandlerFactory.getReader(source);
List<MetadataProperty> metadata = sourceReader.readMetadata();
MetadataUtils.refreshPageNumberMetadata(sourceReader, metadata, target);
IMetadataWriter writer = MetadataHandlerFactory.getWriter(target);
writer.writeMetadata(metadata);
}
/**
* Some ebook metdata store the page number which could change after processing. This method rereads the
* ebook and corrects the metadata value if there is one present.
* @param sourceReader The reader for the ebook which page numbers should be refreshed.
* @param metadataProperties The metadata properties previously read from the given {@link IMetadataReader}.
* @param target The target ebook resource where the actual page count is read from.
*/
public static void refreshPageNumberMetadata(IMetadataReader sourceReader, List<MetadataProperty> metadataProperties, IResourceHandler target) {
if (sourceReader instanceof ComicBookMetadataReader && (MimeUtils.isCbr(target, true) || MimeUtils.isCbz(target, true))) {
IArchiveHandler archiveHandler = ArchiveHandlerFactory.getHandler(target);
try {
archiveHandler.readArchive();
} catch (IOException e) {
LoggerFactory.getLogger(MetadataUtils.class).log(Level.WARNING, "Failed to read archive " + target, e);
return;
}
for (MetadataProperty metadataProperty : metadataProperties) {
if (metadataProperty.getName().equals(COMICBOOK_METADATA_TYPES.PAGECOUNT.getName())
|| metadataProperty.getName().equals(COMICBOOK_METADATA_TYPES.COUNT.getName())) {
int actualPageCount = archiveHandler.getArchiveEntries().size();
if (NumberUtils.isNumber(metadataProperty.getValueAsString())) {
metadataProperty.setValue(String.valueOf(actualPageCount), 0);
}
}
}
}
}
}