package org.rr.jeborker.metadata; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_CBR; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_CBZ; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_EPUB; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_HTML; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_PDF; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_MOBI; import static org.rr.jeborker.app.JeboorkerConstants.SUPPORTED_MIMES.MIME_AZW; import java.util.Collections; import java.util.List; import org.rr.commons.collection.TransformValueList; import org.rr.commons.mufs.IResourceHandler; import org.rr.commons.utils.ListUtils; import org.rr.jeborker.db.item.EbookPropertyItem; public class MetadataHandlerFactory { private static IMetadataReader latestReader = null; /** * Gets a reader which supports multiple ebook resources. * @param items The items to be handled by the result {@link IMetadataReader}. * @return The desired {@link IMetadataReader} instance. */ public static IMetadataReader getReaderForEbookPropertyItems(final List<EbookPropertyItem> items) { return getReaderForIResourceHandlers(new TransformValueList<EbookPropertyItem, IResourceHandler>(items) { @Override public IResourceHandler transform(EbookPropertyItem source) { return source.getResourceHandler(); } }); } /** * Gets a reader which supports multiple ebook resources. * @param resources The resources to be handled by the result {@link IMetadataReader}. * @return The desired {@link IMetadataReader} instance. */ public static IMetadataReader getReaderForIResourceHandlers(final List<IResourceHandler> resources) { IMetadataReader cachedReader = null; if((cachedReader = getCachedReader(resources)) != null) { return cachedReader; } if(resources.size() == 1) { return latestReader = getReader(resources.get(0)); } else { return latestReader = new MultiMetadataHandler(resources); } } /** * Get a meta data reader for the given {@link IResourceHandler}. * @param resource The resource for which a meta data reader should be fetched for. * @return The desired {@link IMetadataWriter} instance or <code>null</code> if no reader is available * for the given {@link IResourceHandler}. */ public static IMetadataReader getReader(final IResourceHandler resource) { IMetadataReader cachedReader = null; if((cachedReader = getCachedReader(Collections.singletonList(resource))) != null) { return cachedReader; } final String mimeType = resource.getMimeType(true); if (mimeType != null) { latestReader = null; if(resource.getMimeType(true).equals(MIME_EPUB.getMime())) { return latestReader = new EPubLibMetadataReader(resource); } else if(resource.getMimeType(true).equals(MIME_PDF.getMime())) { return latestReader = new PDFCommonMetadataReader(resource); } else if(resource.getMimeType(true).equals(MIME_CBZ.getMime()) || resource.getMimeType(true).equals(MIME_CBR.getMime())) { return latestReader = new ComicBookMetadataReader(resource); } else if(resource.getMimeType(true).equals(MIME_HTML.getMime())) { return latestReader = new HTMLMetadataReader(resource); } else if(resource.getMimeType(true).equals(MIME_MOBI.getMime()) || resource.getMimeType(true).equals(MIME_AZW.getMime())) { return latestReader = new MobiMetadataReader(resource); } } return latestReader = new EmptyMetadataReader(resource); } /** * Get a meta data writer for the given {@link IResourceHandler}. * @param resources The resources for which a meta data writer should be fetched for. * @return The desired {@link IMetadataWriter} instance or <code>null</code> if no writer is available * for the given {@link IResourceHandler}. */ public static IMetadataWriter getWriter(final List<IResourceHandler> resources) { if(resources.size() == 1) { return getWriter(resources.get(0)); } else { return wrap(new MultiMetadataHandler(resources)); } } /** * Get a meta data writer for the given {@link IResourceHandler}. * @param resource The resource for which a meta data writer should be fetched for. * @return The desired {@link IMetadataWriter} instance or <code>null</code> if no writer is available * for the given {@link IResourceHandler}. */ public static IMetadataWriter getWriter(final IResourceHandler resource) { final String mimeType = resource.getMimeType(true); if(mimeType!=null) { if(resource.getMimeType(true).equals(MIME_EPUB.getMime())) { return wrap(new EPubLibMetadataWriter(resource)); } else if(resource.getMimeType(true).equals(MIME_PDF.getMime())) { return wrap(new PDFCommonMetadataWriter(resource)); } else if(resource.getMimeType(true).equals(MIME_CBZ.getMime()) || resource.getMimeType(true).equals(MIME_CBR.getMime())) { return wrap(new ComicBookMetadataWriter(resource)); } else if(resource.getMimeType(true).equals(MIME_MOBI.getMime()) || resource.getMimeType(true).equals(MIME_AZW.getMime())) { return wrap(new MobiMetadataWriter(resource)); } } return null; } /** * Tells if there is writer support for at least one of the given {@link IResourceHandler}. */ public static boolean hasWriterSupport(final List<IResourceHandler> resources) { for(int i = 0; i < resources.size(); i++) { final IResourceHandler resource = resources.get(i); if(getWriter(resource) != null) { return true; } } return false; } /** * Tells if there is cover writer support for the given resource. * @param resource The resource to be tested for support. * @return <code>true</code> if writer support is available and <code>false</code> otherwise. */ public static boolean hasCoverWriterSupport(final IResourceHandler resource) { final String mimeType = resource.getMimeType(true); if(mimeType != null) { if(resource.getMimeType(true).equals(MIME_EPUB.getMime())) { return true; } else if(resource.getMimeType(true).equals(MIME_PDF.getMime())) { return true; } else if(resource.getMimeType(true).equals(MIME_MOBI.getMime()) || resource.getMimeType(true).equals(MIME_AZW.getMime())) { return true; } } return false; } /** * Tells if there is cover writer support for the given resource. * @param resourceHandler The resource to be tested for support. * @return <code>true</code> if writer support is available and <code>false</code> otherwise. */ public static boolean hasPlainMetadataSupport(final IResourceHandler resourceHandler) { final String mimeType = resourceHandler.getMimeType(true); if(mimeType!=null) { if(resourceHandler.getMimeType(true).equals(MIME_EPUB.getMime())) { return true; } else if(resourceHandler.getMimeType(true).equals(MIME_PDF.getMime())) { return true; } else if(resourceHandler.getMimeType(true).equals(MIME_CBZ.getMime()) || resourceHandler.getMimeType(true).equals(MIME_CBR.getMime())) { return true; } else if(resourceHandler.getMimeType(true).equals(MIME_HTML.getMime())) { return true; } } return false; } /** * The latest {@link IMetadataReader} instance is cached and always this one is delivered if it's already usable. * @param resourceHandler The {@link IResourceHandler} for the requested {@link IMetadataReader} instance. * @return The cached {@link IMetadataReader} or <code>null</code> if the latest {@link IMetadataReader} is no longer usable. */ private static IMetadataReader getCachedReader(final List<IResourceHandler> resourceHandler) { if(latestReader != null && latestReader.getEbookResource() != null) { if(resourceHandler.size() > 1 && resourceHandler.size() == latestReader.getEbookResource().size()) { List<IResourceHandler> ebookResource = latestReader.getEbookResource(); List<IResourceHandler> difference = ListUtils.difference(ebookResource, resourceHandler); if(difference.isEmpty()) { return latestReader; } } else if(latestReader.getEbookResource().size() == 1 && resourceHandler.size() == 1 && resourceHandler.get(0).equals(latestReader.getEbookResource().get(0))) { return latestReader; } } return null; } /** * Wrap the given {@link IMetadataWriter} with the {@link MetadataWriterWrapper}. * @param writer The writer instance to be wrapped. * @return The MetadataWriterWrapper wrapping the given {@link IMetadataWriter} instance. */ private static IMetadataWriter wrap(final IMetadataWriter writer) { return new MetadataWriterWrapper(writer); } /** * Wrapper for all {@link IMetadataWriter}. It's needed for resetting the cached {@link IMetadataReader} instance * because the reader data are out of date after a writer does it's write. */ private static class MetadataWriterWrapper implements IMetadataWriter { private IMetadataWriter writer; MetadataWriterWrapper(IMetadataWriter writer) { this.writer = writer; } @Override public void writeMetadata(List<MetadataProperty> props) { writer.writeMetadata(props); latestReader = null; } @Override public void storePlainMetadata(byte[] plainMetadata) { writer.storePlainMetadata(plainMetadata); latestReader = null; } } }