Java tutorial
/* * Copyright 2012 - 2016 Manuel Laggner * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.tinymediamanager.core.entities; import static org.tinymediamanager.core.Constants.BANNER; import static org.tinymediamanager.core.Constants.DATE_ADDED; import static org.tinymediamanager.core.Constants.DATE_ADDED_AS_STRING; import static org.tinymediamanager.core.Constants.FANART; import static org.tinymediamanager.core.Constants.HAS_IMAGES; import static org.tinymediamanager.core.Constants.MEDIA_FILES; import static org.tinymediamanager.core.Constants.MEDIA_INFORMATION; import static org.tinymediamanager.core.Constants.NEWLY_ADDED; import static org.tinymediamanager.core.Constants.ORIGINAL_TITLE; import static org.tinymediamanager.core.Constants.PATH; import static org.tinymediamanager.core.Constants.PLOT; import static org.tinymediamanager.core.Constants.POSTER; import static org.tinymediamanager.core.Constants.PRODUCTION_COMPANY; import static org.tinymediamanager.core.Constants.RATING; import static org.tinymediamanager.core.Constants.SCRAPED; import static org.tinymediamanager.core.Constants.THUMB; import static org.tinymediamanager.core.Constants.TITLE; import static org.tinymediamanager.core.Constants.VOTES; import static org.tinymediamanager.core.Constants.YEAR; import java.awt.Dimension; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.lang3.StringUtils; import org.tinymediamanager.core.AbstractModelObject; import org.tinymediamanager.core.Constants; import org.tinymediamanager.core.MediaFileType; import org.tinymediamanager.scraper.entities.MediaArtwork.MediaArtworkType; import com.fasterxml.jackson.annotation.JsonProperty; /** * The Class MediaEntity. The base class for all entities * * @author Manuel Laggner */ public abstract class MediaEntity extends AbstractModelObject { /** The id for the database. */ protected UUID dbId = UUID.randomUUID(); /** The ids to store the ID from several metadataproviders. */ @JsonProperty protected HashMap<String, Object> ids = new HashMap<>(0); @JsonProperty protected String title = ""; @JsonProperty protected String originalTitle = ""; @JsonProperty protected String year = ""; @JsonProperty protected String plot = ""; @JsonProperty protected float rating = 0f; @JsonProperty protected int votes = 0; @JsonProperty protected String path = ""; @JsonProperty protected Date dateAdded = new Date(); @JsonProperty protected String productionCompany = ""; @JsonProperty protected boolean scraped = false; @JsonProperty private List<MediaFile> mediaFiles = new ArrayList<>(); @JsonProperty protected Map<MediaFileType, String> artworkUrlMap = new HashMap<>(); protected boolean newlyAdded = false; protected boolean duplicate = false; protected ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public MediaEntity() { } /** * Initialize after loading from database. */ public void initializeAfterLoading() { sortMediaFiles(); } protected void sortMediaFiles() { Comparator<MediaFile> mediaFileComparator = getMediaFileComparator(); if (mediaFileComparator != null) { Collections.sort(mediaFiles, mediaFileComparator); } else { Collections.sort(mediaFiles); } } /** * get the INTERNAL ID of this object. Do not confuse it with the IDs from the metadata provider! * * @return internal id */ public UUID getDbId() { return dbId; } public void setDbId(UUID id) { this.dbId = id; } public HashMap<String, Object> getIds() { return ids; } public String getTitle() { return title; } public String getOriginalTitle() { return originalTitle; } public String getPlot() { return plot; } /** * @deprecated use getPathNIO() */ @Deprecated public String getPath() { return path; } public Path getPathNIO() { return Paths.get(path).toAbsolutePath(); } /** * Gets the dimension of the (first) artwork of the given type * * @param type * the artwork type * @return the dimension of the artwork or a zero dimension if no artwork has been found */ public Dimension getArtworkDimension(MediaFileType type) { List<MediaFile> mediaFiles = getMediaFiles(type); if (mediaFiles.size() > 0) { MediaFile mediaFile = mediaFiles.get(0); return new Dimension(mediaFile.getVideoWidth(), mediaFile.getVideoHeight()); } return new Dimension(0, 0); } /** * Gets the file name of the (first) artwork of the given type * * @param type * the artwork type * @return the file name of the artwork or an empty string if nothing has been found */ public String getArtworkFilename(MediaFileType type) { List<MediaFile> thumbs = getMediaFiles(type); if (thumbs.size() > 0) { return thumbs.get(0).getFile().getPath(); } return ""; } public float getRating() { return rating; } public String getYear() { return year; } public void setIds(Map<String, Object> ids) { for (Entry<String, Object> entry : ids.entrySet()) { if (StringUtils.isNotBlank(entry.getKey()) && entry.getValue() != null) { setId(entry.getKey(), entry.getValue()); firePropertyChange(entry.getKey(), null, entry.getValue()); } } } public void setTitle(String newValue) { String oldValue = title; title = newValue == null ? "" : newValue.trim(); firePropertyChange(TITLE, oldValue, newValue); } public void setOriginalTitle(String newValue) { String oldValue = originalTitle; originalTitle = newValue == null ? "" : newValue.trim(); firePropertyChange(ORIGINAL_TITLE, oldValue, newValue); } public void setPlot(String newValue) { String oldValue = plot; plot = newValue == null ? "" : newValue.trim(); firePropertyChange(PLOT, oldValue, newValue); } public void setPath(String newValue) { String oldValue = path; path = newValue; firePropertyChange(PATH, oldValue, newValue); } public void setRating(float newValue) { float oldValue = rating; rating = newValue; firePropertyChange(RATING, oldValue, newValue); } public int getVotes() { return votes; } public void setVotes(int newValue) { int oldValue = this.votes; this.votes = newValue; firePropertyChange(VOTES, oldValue, newValue); } public void setYear(String newValue) { String oldValue = year; year = newValue == null ? "" : newValue.trim(); firePropertyChange(YEAR, oldValue, newValue); } public void setArtworkUrl(String url, MediaFileType type) { String oldValue = getArtworkFilename(type); switch (type) { case POSTER: case FANART: case BANNER: case THUMB: case CLEARART: case DISCART: case LOGO: case CLEARLOGO: artworkUrlMap.put(type, url); break; default: return; } firePropertyChange(type.name().toLowerCase(Locale.ROOT) + "Url", oldValue, url); } /** * get the artwork url for the desired type * * @param type * the artwork type * @return the url to the artwork type or an empty string */ public String getArtworkUrl(MediaFileType type) { String url = artworkUrlMap.get(type); return url == null ? "" : url; } /** * get all artwork urls * * @return a map containing all urls */ public Map<MediaFileType, String> getArtworkUrls() { return artworkUrlMap; } public void setArtwork(Path file, MediaFileType type) { List<MediaFile> images = getMediaFiles(type); MediaFile mediaFile = null; if (images.size() > 0) { mediaFile = images.get(0); mediaFile.setFile(file); mediaFile.gatherMediaInformation(true); } else { mediaFile = new MediaFile(file, type); mediaFile.gatherMediaInformation(); addToMediaFiles(mediaFile); } firePropertyChange(MEDIA_INFORMATION, false, true); } /** * Get a map of all primary artworks. If there are multiple media files for one artwork type, only the first is returned in the map * * @return a map of all found artworks */ public Map<MediaFileType, MediaFile> getArtworkMap() { Map<MediaFileType, MediaFile> artworkMap = new HashMap<>(); List<MediaFile> mediaFiles = getMediaFiles(); for (MediaFile mf : mediaFiles) { if (!mf.isGraphic()) { continue; } if (!artworkMap.containsKey(mf.getType())) { artworkMap.put(mf.getType(), mf); } } return artworkMap; } public Date getDateAdded() { return dateAdded; } public String getDateAddedAsString() { if (dateAdded == null) { return ""; } return SimpleDateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.getDefault()) .format(dateAdded); } public void setDateAdded(Date newValue) { Date oldValue = this.dateAdded; this.dateAdded = newValue; firePropertyChange(DATE_ADDED, oldValue, newValue); firePropertyChange(DATE_ADDED_AS_STRING, oldValue, newValue); } public void setDateAddedFromMediaFile(MediaFile mf) { try { BasicFileAttributes view = Files.readAttributes(mf.getFileAsPath(), BasicFileAttributes.class); Date creDat = new Date(view.creationTime().toMillis()); Date modDat = new Date(view.lastModifiedTime().toMillis()); if (creDat.compareTo(dateAdded) < 0) { setDateAdded(creDat); } if (modDat.compareTo(dateAdded) < 0) { setDateAdded(modDat); } } catch (Exception e) { } } public String getProductionCompany() { return productionCompany; } public void setProductionCompany(String newValue) { String oldValue = this.productionCompany; this.productionCompany = newValue; firePropertyChange(PRODUCTION_COMPANY, oldValue, newValue); } protected void setScraped(boolean newValue) { this.scraped = newValue; firePropertyChange(SCRAPED, false, newValue); } public boolean isScraped() { return scraped; } public void setDuplicate() { this.duplicate = true; } public void clearDuplicate() { this.duplicate = false; } public boolean isDuplicate() { return this.duplicate; } public void setId(String key, Object value) { ids.put(key, value); firePropertyChange(key, null, value); // fire special events for our well known IDs if (Constants.TMDB.equals(key) || Constants.IMDB.equals(key) || Constants.TVDB.equals(key) || Constants.TRAKT.equals(key)) { firePropertyChange(key + "Id", null, value); } } public void removeId(String key) { Object obj = ids.remove(key); if (obj != null) { firePropertyChange(key, obj, null); } } public Object getId(String key) { return ids.get(key); } /** * any ID as String or empty */ public String getIdAsString(String key) { Object obj = ids.get(key); if (obj == null) { return ""; } return String.valueOf(obj); } /** * any ID as int or 0 */ public int getIdAsInt(String key) { int id = 0; try { id = Integer.parseInt(String.valueOf(ids.get(key))); } catch (Exception e) { return 0; } return id; } public void addToMediaFiles(MediaFile mediaFile) { readWriteLock.writeLock().lock(); // only store the MF if it is not in the list or if the type has been changed if (mediaFiles.contains(mediaFile)) { int i = mediaFiles.indexOf(mediaFile); if (i >= 0) { MediaFile oldMf = mediaFiles.get(i); if (oldMf.getType() != mediaFile.getType()) { mediaFiles.remove(i); } } } if (!mediaFiles.contains(mediaFile)) { mediaFiles.add(mediaFile); sortMediaFiles(); } readWriteLock.writeLock().unlock(); firePropertyChange(MEDIA_FILES, null, mediaFiles); fireAddedEventForMediaFile(mediaFile); } public void addToMediaFiles(List<MediaFile> mediaFiles) { for (MediaFile mediaFile : mediaFiles) { addToMediaFiles(mediaFile); } } private void fireAddedEventForMediaFile(MediaFile mediaFile) { switch (mediaFile.getType()) { case FANART: firePropertyChange(FANART, null, mediaFile.getFile().getPath()); firePropertyChange(HAS_IMAGES, false, true); break; case POSTER: firePropertyChange(POSTER, null, mediaFile.getFile().getPath()); firePropertyChange(HAS_IMAGES, false, true); break; case BANNER: firePropertyChange(BANNER, null, mediaFile.getFile().getPath()); firePropertyChange(HAS_IMAGES, false, true); break; case THUMB: firePropertyChange(THUMB, null, mediaFile.getFile().getPath()); firePropertyChange(HAS_IMAGES, false, true); break; default: break; } } private void fireRemoveEventForMediaFile(MediaFile mediaFile) { switch (mediaFile.getType()) { case FANART: firePropertyChange(FANART, null, ""); firePropertyChange(HAS_IMAGES, true, false); break; case POSTER: firePropertyChange(POSTER, null, ""); firePropertyChange(HAS_IMAGES, true, false); break; case BANNER: firePropertyChange(BANNER, null, ""); firePropertyChange(HAS_IMAGES, true, false); break; case THUMB: firePropertyChange(THUMB, null, ""); firePropertyChange(HAS_IMAGES, true, false); break; default: break; } } public List<MediaFile> getMediaFiles() { List<MediaFile> mf = new ArrayList<>(); readWriteLock.readLock().lock(); try { mf.addAll(mediaFiles); } finally { readWriteLock.readLock().unlock(); } return mf; } /** * gets all MediaFiles from specific type<br> * <b>Can be one or multiple types!</b> * * @param types * 1-N types * @return list of MF (may be empty, but never null) */ public List<MediaFile> getMediaFiles(MediaFileType... types) { List<MediaFile> mf = new ArrayList<>(); readWriteLock.readLock().lock(); for (MediaFile mediaFile : mediaFiles) { boolean match = false; for (MediaFileType type : types) { if (mediaFile.getType().equals(type)) { match = true; } } if (match) { mf.add(mediaFile); } } readWriteLock.readLock().unlock(); return mf; } /** * gets the BIGGEST MediaFile of type(s)<br> * useful for getting the right MF for displaying mediaInformation * * @return biggest MF */ public MediaFile getBiggestMediaFile(MediaFileType... types) { MediaFile mf = null; readWriteLock.readLock().lock(); for (MediaFile mediaFile : mediaFiles) { for (MediaFileType type : types) { if (mediaFile.getType().equals(type)) { if (mf == null || mediaFile.getFilesize() >= mf.getFilesize()) { mf = mediaFile; } } } } readWriteLock.readLock().unlock(); return mf; } /** * From all MediaFiles of specified type, get the newest one (according to MI filedate) * * @param type * the MediaFileType to get the MediaFile for * @return NULL or MF */ public MediaFile getNewestMediaFilesOfType(MediaFileType... types) { MediaFile mf = null; readWriteLock.readLock().lock(); for (MediaFile mediaFile : mediaFiles) { for (MediaFileType type : types) { if (mediaFile.getType().equals(type)) { if (mf == null || mediaFile.getFiledate() >= mf.getFiledate()) { // get the latter one mf = new MediaFile(mediaFile); } } } } readWriteLock.readLock().unlock(); return mf; } /** * gets all MediaFiles EXCEPT from specific type<br> * <b>Can be one or multiple types!</b> * * @param types * 1-N types * @return list of MF (may be empty, but never null) */ public List<MediaFile> getMediaFilesExceptType(MediaFileType... types) { List<MediaFile> mf = new ArrayList<>(); readWriteLock.readLock().lock(); for (MediaFile mediaFile : mediaFiles) { boolean match = false; for (MediaFileType type : types) { if (mediaFile.getType().equals(type)) { match = true; } } if (!match) { mf.add(mediaFile); } } readWriteLock.readLock().unlock(); return mf; } public void removeAllMediaFiles() { List<MediaFile> changedMediafiles = new ArrayList<>(mediaFiles); readWriteLock.writeLock().lock(); for (int i = mediaFiles.size() - 1; i >= 0; i--) { mediaFiles.remove(i); } readWriteLock.writeLock().unlock(); for (MediaFile mediaFile : changedMediafiles) { fireRemoveEventForMediaFile(mediaFile); } } public void removeFromMediaFiles(MediaFile mediaFile) { readWriteLock.writeLock().lock(); try { mediaFiles.remove(mediaFile); } finally { readWriteLock.writeLock().unlock(); } firePropertyChange(MEDIA_FILES, null, mediaFiles); fireRemoveEventForMediaFile(mediaFile); } public void removeAllMediaFilesExceptType(MediaFileType type) { List<MediaFile> changedMediafiles = new ArrayList<>(); readWriteLock.writeLock().lock(); for (int i = mediaFiles.size() - 1; i >= 0; i--) { MediaFile mediaFile = mediaFiles.get(i); if (!mediaFile.getType().equals(type)) { mediaFiles.remove(i); changedMediafiles.add(mediaFile); } } readWriteLock.writeLock().unlock(); for (MediaFile mediaFile : changedMediafiles) { fireRemoveEventForMediaFile(mediaFile); } } public void removeAllMediaFiles(MediaFileType type) { List<MediaFile> changedMediafiles = new ArrayList<>(); readWriteLock.writeLock().lock(); for (int i = mediaFiles.size() - 1; i >= 0; i--) { MediaFile mediaFile = mediaFiles.get(i); if (mediaFile.getType().equals(type)) { mediaFiles.remove(i); changedMediafiles.add(mediaFile); } } readWriteLock.writeLock().unlock(); for (MediaFile mediaFile : changedMediafiles) { fireRemoveEventForMediaFile(mediaFile); } } public void updateMediaFilePath(Path oldPath, Path newPath) { readWriteLock.readLock().lock(); List<MediaFile> mfs = new ArrayList<>(this.mediaFiles); readWriteLock.readLock().unlock(); for (MediaFile mf : mfs) { mf.replacePathForRenamedFolder(oldPath, newPath); } } public void gatherMediaFileInformation(boolean force) { readWriteLock.readLock().lock(); List<MediaFile> mediaFiles = new ArrayList<>(this.mediaFiles); readWriteLock.readLock().unlock(); for (MediaFile mediaFile : mediaFiles) { mediaFile.gatherMediaInformation(force); } firePropertyChange(MEDIA_INFORMATION, false, true); } public void fireEventForChangedMediaInformation() { firePropertyChange(MEDIA_INFORMATION, false, true); } public boolean isNewlyAdded() { return this.newlyAdded; } public void setNewlyAdded(boolean newValue) { boolean oldValue = this.newlyAdded; this.newlyAdded = newValue; firePropertyChange(NEWLY_ADDED, oldValue, newValue); } abstract public void saveToDb(); abstract public void deleteFromDb(); abstract public void callbackForWrittenArtwork(MediaArtworkType type); abstract protected Comparator<MediaFile> getMediaFileComparator(); }