aboutsummaryrefslogtreecommitdiff
path: root/subsonic-main/src/main/java/net/sourceforge/subsonic/service/MediaFileService.java
diff options
context:
space:
mode:
Diffstat (limited to 'subsonic-main/src/main/java/net/sourceforge/subsonic/service/MediaFileService.java')
-rw-r--r--subsonic-main/src/main/java/net/sourceforge/subsonic/service/MediaFileService.java614
1 files changed, 0 insertions, 614 deletions
diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/service/MediaFileService.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/service/MediaFileService.java
deleted file mode 100644
index bc575714..00000000
--- a/subsonic-main/src/main/java/net/sourceforge/subsonic/service/MediaFileService.java
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-package net.sourceforge.subsonic.service;
-
-import net.sf.ehcache.Ehcache;
-import net.sf.ehcache.Element;
-import net.sourceforge.subsonic.Logger;
-import net.sourceforge.subsonic.dao.AlbumDao;
-import net.sourceforge.subsonic.dao.MediaFileDao;
-import net.sourceforge.subsonic.domain.Album;
-import net.sourceforge.subsonic.domain.MediaFile;
-import net.sourceforge.subsonic.domain.MediaFileComparator;
-import net.sourceforge.subsonic.domain.MusicFolder;
-import net.sourceforge.subsonic.service.metadata.JaudiotaggerParser;
-import net.sourceforge.subsonic.service.metadata.MetaData;
-import net.sourceforge.subsonic.service.metadata.MetaDataParser;
-import net.sourceforge.subsonic.service.metadata.MetaDataParserFactory;
-import net.sourceforge.subsonic.util.FileUtil;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang.StringUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import static net.sourceforge.subsonic.domain.MediaFile.MediaType.*;
-
-/**
- * Provides services for instantiating and caching media files and cover art.
- *
- * @author Sindre Mehus
- */
-public class MediaFileService {
-
- private static final Logger LOG = Logger.getLogger(MediaFileService.class);
-
- private Ehcache mediaFileMemoryCache;
-
- private SecurityService securityService;
- private SettingsService settingsService;
- private MediaFileDao mediaFileDao;
- private AlbumDao albumDao;
- private MetaDataParserFactory metaDataParserFactory;
-
- /**
- * Returns a media file instance for the given file. If possible, a cached value is returned.
- *
- * @param file A file on the local file system.
- * @return A media file instance, or null if not found.
- * @throws SecurityException If access is denied to the given file.
- */
- public MediaFile getMediaFile(File file) {
- return getMediaFile(file, settingsService.isFastCacheEnabled());
- }
-
- /**
- * Returns a media file instance for the given file. If possible, a cached value is returned.
- *
- * @param file A file on the local file system.
- * @return A media file instance, or null if not found.
- * @throws SecurityException If access is denied to the given file.
- */
- public MediaFile getMediaFile(File file, boolean useFastCache) {
-
- // Look in fast memory cache first.
- Element element = mediaFileMemoryCache.get(file);
- MediaFile result = element == null ? null : (MediaFile) element.getObjectValue();
- if (result != null) {
- return result;
- }
-
- if (!securityService.isReadAllowed(file)) {
- throw new SecurityException("Access denied to file " + file);
- }
-
- // Secondly, look in database.
- result = mediaFileDao.getMediaFile(file.getPath());
- if (result != null) {
- result = checkLastModified(result, useFastCache);
- mediaFileMemoryCache.put(new Element(file, result));
- return result;
- }
-
- if (!FileUtil.exists(file)) {
- return null;
- }
- // Not found in database, must read from disk.
- result = createMediaFile(file);
-
- // Put in cache and database.
- mediaFileMemoryCache.put(new Element(file, result));
- mediaFileDao.createOrUpdateMediaFile(result);
-
- return result;
- }
-
- private MediaFile checkLastModified(MediaFile mediaFile, boolean useFastCache) {
- if (useFastCache || mediaFile.getChanged().getTime() >= FileUtil.lastModified(mediaFile.getFile())) {
- return mediaFile;
- }
- mediaFile = createMediaFile(mediaFile.getFile());
- mediaFileDao.createOrUpdateMediaFile(mediaFile);
- return mediaFile;
- }
-
- /**
- * Returns a media file instance for the given path name. If possible, a cached value is returned.
- *
- * @param pathName A path name for a file on the local file system.
- * @return A media file instance.
- * @throws SecurityException If access is denied to the given file.
- */
- public MediaFile getMediaFile(String pathName) {
- return getMediaFile(new File(pathName));
- }
-
- // TODO: Optimize with memory caching.
- public MediaFile getMediaFile(int id) {
- MediaFile mediaFile = mediaFileDao.getMediaFile(id);
- if (mediaFile == null) {
- return null;
- }
-
- if (!securityService.isReadAllowed(mediaFile.getFile())) {
- throw new SecurityException("Access denied to file " + mediaFile);
- }
-
- return checkLastModified(mediaFile, settingsService.isFastCacheEnabled());
- }
-
- public MediaFile getParentOf(MediaFile mediaFile) {
- if (mediaFile.getParentPath() == null) {
- return null;
- }
- return getMediaFile(mediaFile.getParentPath());
- }
-
- public List<MediaFile> getChildrenOf(String parentPath, boolean includeFiles, boolean includeDirectories, boolean sort) {
- return getChildrenOf(new File(parentPath), includeFiles, includeDirectories, sort);
- }
-
- public List<MediaFile> getChildrenOf(File parent, boolean includeFiles, boolean includeDirectories, boolean sort) {
- return getChildrenOf(getMediaFile(parent), includeFiles, includeDirectories, sort);
- }
-
- /**
- * Returns all media files that are children of a given media file.
- *
- * @param includeFiles Whether files should be included in the result.
- * @param includeDirectories Whether directories should be included in the result.
- * @param sort Whether to sort files in the same directory.
- * @return All children media files.
- */
- public List<MediaFile> getChildrenOf(MediaFile parent, boolean includeFiles, boolean includeDirectories, boolean sort) {
- return getChildrenOf(parent, includeFiles, includeDirectories, sort, settingsService.isFastCacheEnabled());
- }
-
- /**
- * Returns all media files that are children of a given media file.
- *
- * @param includeFiles Whether files should be included in the result.
- * @param includeDirectories Whether directories should be included in the result.
- * @param sort Whether to sort files in the same directory.
- * @return All children media files.
- */
- public List<MediaFile> getChildrenOf(MediaFile parent, boolean includeFiles, boolean includeDirectories, boolean sort, boolean useFastCache) {
-
- if (!parent.isDirectory()) {
- return Collections.emptyList();
- }
-
- // Make sure children are stored and up-to-date in the database.
- if (!useFastCache) {
- updateChildren(parent);
- }
-
- List<MediaFile> result = new ArrayList<MediaFile>();
- for (MediaFile child : mediaFileDao.getChildrenOf(parent.getPath())) {
- child = checkLastModified(child, useFastCache);
- if (child.isDirectory() && includeDirectories) {
- result.add(child);
- }
- if (child.isFile() && includeFiles) {
- result.add(child);
- }
- }
-
- if (sort) {
- Comparator<MediaFile> comparator = new MediaFileComparator(settingsService.isSortAlbumsByYear());
- // Note: Intentionally not using Collections.sort() since it can be problematic on Java 7.
- // http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#jdk7
- Set<MediaFile> set = new TreeSet<MediaFile>(comparator);
- set.addAll(result);
- result = new ArrayList<MediaFile>(set);
- }
-
- return result;
- }
-
- /**
- * Returns whether the given file is the root of a media folder.
- *
- * @see MusicFolder
- */
- public boolean isRoot(MediaFile mediaFile) {
- for (MusicFolder musicFolder : settingsService.getAllMusicFolders(false, true)) {
- if (mediaFile.getPath().equals(musicFolder.getPath().getPath())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns all genres in the music collection.
- *
- * @return Sorted list of genres.
- */
- public List<String> getGenres() {
- return mediaFileDao.getGenres();
- }
-
- /**
- * Returns the most frequently played albums.
- *
- * @param offset Number of albums to skip.
- * @param count Maximum number of albums to return.
- * @return The most frequently played albums.
- */
- public List<MediaFile> getMostFrequentlyPlayedAlbums(int offset, int count) {
- return mediaFileDao.getMostFrequentlyPlayedAlbums(offset, count);
- }
-
- /**
- * Returns the most recently played albums.
- *
- * @param offset Number of albums to skip.
- * @param count Maximum number of albums to return.
- * @return The most recently played albums.
- */
- public List<MediaFile> getMostRecentlyPlayedAlbums(int offset, int count) {
- return mediaFileDao.getMostRecentlyPlayedAlbums(offset, count);
- }
-
- /**
- * Returns the most recently added albums.
- *
- * @param offset Number of albums to skip.
- * @param count Maximum number of albums to return.
- * @return The most recently added albums.
- */
- public List<MediaFile> getNewestAlbums(int offset, int count) {
- return mediaFileDao.getNewestAlbums(offset, count);
- }
-
- /**
- * Returns the most recently starred albums.
- *
- * @param offset Number of albums to skip.
- * @param count Maximum number of albums to return.
- * @param username Returns albums starred by this user.
- * @return The most recently starred albums for this user.
- */
- public List<MediaFile> getStarredAlbums(int offset, int count, String username) {
- return mediaFileDao.getStarredAlbums(offset, count, username);
- }
-
- /**
- * Returns albums in alphabetial order.
- *
- *
- * @param offset Number of albums to skip.
- * @param count Maximum number of albums to return.
- * @param byArtist Whether to sort by artist name
- * @return Albums in alphabetical order.
- */
- public List<MediaFile> getAlphabetialAlbums(int offset, int count, boolean byArtist) {
- return mediaFileDao.getAlphabetialAlbums(offset, count, byArtist);
- }
-
- public Date getMediaFileStarredDate(int id, String username) {
- return mediaFileDao.getMediaFileStarredDate(id, username);
- }
-
- public void populateStarredDate(List<MediaFile> mediaFiles, String username) {
- for (MediaFile mediaFile : mediaFiles) {
- populateStarredDate(mediaFile, username);
- }
- }
-
- public void populateStarredDate(MediaFile mediaFile, String username) {
- Date starredDate = mediaFileDao.getMediaFileStarredDate(mediaFile.getId(), username);
- mediaFile.setStarredDate(starredDate);
- }
-
- private void updateChildren(MediaFile parent) {
-
- // Check timestamps.
- if (parent.getChildrenLastUpdated().getTime() >= parent.getChanged().getTime()) {
- return;
- }
-
- List<MediaFile> storedChildren = mediaFileDao.getChildrenOf(parent.getPath());
- Map<String, MediaFile> storedChildrenMap = new HashMap<String, MediaFile>();
- for (MediaFile child : storedChildren) {
- storedChildrenMap.put(child.getPath(), child);
- }
-
- List<File> children = filterMediaFiles(FileUtil.listFiles(parent.getFile()));
- for (File child : children) {
- if (storedChildrenMap.remove(child.getPath()) == null) {
- // Add children that are not already stored.
- mediaFileDao.createOrUpdateMediaFile(createMediaFile(child));
- }
- }
-
- // Delete children that no longer exist on disk.
- for (String path : storedChildrenMap.keySet()) {
- mediaFileDao.deleteMediaFile(path);
- }
-
- // Update timestamp in parent.
- parent.setChildrenLastUpdated(parent.getChanged());
- parent.setPresent(true);
- mediaFileDao.createOrUpdateMediaFile(parent);
- }
-
- private List<File> filterMediaFiles(File[] candidates) {
- List<File> result = new ArrayList<File>();
- for (File candidate : candidates) {
- String suffix = FilenameUtils.getExtension(candidate.getName()).toLowerCase();
- if (!isExcluded(candidate) && (FileUtil.isDirectory(candidate) || isAudioFile(suffix) || isVideoFile(suffix))) {
- result.add(candidate);
- }
- }
- return result;
- }
-
- private boolean isAudioFile(String suffix) {
- for (String s : settingsService.getMusicFileTypesAsArray()) {
- if (suffix.equals(s.toLowerCase())) {
- return true;
- }
- }
- return false;
- }
-
- private boolean isVideoFile(String suffix) {
- for (String s : settingsService.getVideoFileTypesAsArray()) {
- if (suffix.equals(s.toLowerCase())) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns whether the given file is excluded.
- *
- * @param file The child file in question.
- * @return Whether the child file is excluded.
- */
- private boolean isExcluded(File file) {
-
- // Exclude all hidden files starting with a "." or "@eaDir" (thumbnail dir created on Synology devices).
- String name = file.getName();
- return name.startsWith(".") || name.startsWith("@eaDir") || name.equals("Thumbs.db");
- }
-
- private MediaFile createMediaFile(File file) {
- MediaFile mediaFile = new MediaFile();
- Date lastModified = new Date(FileUtil.lastModified(file));
- mediaFile.setPath(file.getPath());
- mediaFile.setFolder(securityService.getRootFolderForFile(file));
- mediaFile.setParentPath(file.getParent());
- mediaFile.setChanged(lastModified);
- mediaFile.setLastScanned(new Date());
- mediaFile.setPlayCount(0);
- mediaFile.setChildrenLastUpdated(new Date(0));
- mediaFile.setCreated(lastModified);
- mediaFile.setMediaType(DIRECTORY);
- mediaFile.setPresent(true);
-
- if (file.isFile()) {
-
- MetaDataParser parser = metaDataParserFactory.getParser(file);
- if (parser != null) {
- MetaData metaData = parser.getMetaData(file);
- mediaFile.setArtist(metaData.getArtist());
- mediaFile.setAlbumArtist(metaData.getArtist());
- mediaFile.setAlbumName(metaData.getAlbumName());
- mediaFile.setTitle(metaData.getTitle());
- mediaFile.setDiscNumber(metaData.getDiscNumber());
- mediaFile.setTrackNumber(metaData.getTrackNumber());
- mediaFile.setGenre(metaData.getGenre());
- mediaFile.setYear(metaData.getYear());
- mediaFile.setDurationSeconds(metaData.getDurationSeconds());
- mediaFile.setBitRate(metaData.getBitRate());
- mediaFile.setVariableBitRate(metaData.getVariableBitRate());
- mediaFile.setHeight(metaData.getHeight());
- mediaFile.setWidth(metaData.getWidth());
- }
- String format = StringUtils.trimToNull(StringUtils.lowerCase(FilenameUtils.getExtension(mediaFile.getPath())));
- mediaFile.setFormat(format);
- mediaFile.setFileSize(FileUtil.length(file));
- mediaFile.setMediaType(getMediaType(mediaFile));
-
- } else {
-
- // Is this an album?
- if (!isRoot(mediaFile)) {
- File[] children = FileUtil.listFiles(file);
- File firstChild = null;
- for (File child : filterMediaFiles(children)) {
- if (FileUtil.isFile(child)) {
- firstChild = child;
- break;
- }
- }
-
- if (firstChild != null) {
- mediaFile.setMediaType(ALBUM);
-
- // Guess artist/album name and year.
- MetaDataParser parser = metaDataParserFactory.getParser(firstChild);
- if (parser != null) {
- MetaData metaData = parser.getMetaData(firstChild);
- mediaFile.setArtist(metaData.getArtist());
- mediaFile.setAlbumName(metaData.getAlbumName());
- mediaFile.setYear(metaData.getYear());
- }
-
- // Look for cover art.
- try {
- File coverArt = findCoverArt(children);
- if (coverArt != null) {
- mediaFile.setCoverArtPath(coverArt.getPath());
- }
- } catch (IOException x) {
- LOG.error("Failed to find cover art.", x);
- }
-
- } else {
- mediaFile.setArtist(file.getName());
- }
- }
- }
-
- return mediaFile;
- }
-
- private MediaFile.MediaType getMediaType(MediaFile mediaFile) {
- if (isVideoFile(mediaFile.getFormat())) {
- return VIDEO;
- }
- String path = mediaFile.getPath().toLowerCase();
- String genre = StringUtils.trimToEmpty(mediaFile.getGenre()).toLowerCase();
- if (path.contains("podcast") || genre.contains("podcast")) {
- return PODCAST;
- }
- if (path.contains("audiobook") || genre.contains("audiobook") || path.contains("audio book") || genre.contains("audio book")) {
- return AUDIOBOOK;
- }
- return MUSIC;
- }
-
- public void refreshMediaFile(MediaFile mediaFile) {
- mediaFile = createMediaFile(mediaFile.getFile());
- mediaFileDao.createOrUpdateMediaFile(mediaFile);
- mediaFileMemoryCache.remove(mediaFile.getFile());
- }
-
- /**
- * Returns a cover art image for the given media file.
- */
- public File getCoverArt(MediaFile mediaFile) {
- if (mediaFile.getCoverArtFile() != null) {
- return mediaFile.getCoverArtFile();
- }
- MediaFile parent = getParentOf(mediaFile);
- return parent == null ? null : parent.getCoverArtFile();
- }
-
- /**
- * Finds a cover art image for the given directory, by looking for it on the disk.
- */
- private File findCoverArt(File[] candidates) throws IOException {
- for (String mask : settingsService.getCoverArtFileTypesAsArray()) {
- for (File candidate : candidates) {
- if (candidate.isFile() && candidate.getName().toUpperCase().endsWith(mask.toUpperCase()) && !candidate.getName().startsWith(".")) {
- return candidate;
- }
- }
- }
-
- // Look for embedded images in audiofiles. (Only check first audio file encountered).
- JaudiotaggerParser parser = new JaudiotaggerParser();
- for (File candidate : candidates) {
- if (parser.isApplicable(candidate)) {
- if (parser.isImageAvailable(getMediaFile(candidate))) {
- return candidate;
- } else {
- return null;
- }
- }
- }
- return null;
- }
-
- public void setSecurityService(SecurityService securityService) {
- this.securityService = securityService;
- }
-
- public void setSettingsService(SettingsService settingsService) {
- this.settingsService = settingsService;
- }
-
- public void setMediaFileMemoryCache(Ehcache mediaFileMemoryCache) {
- this.mediaFileMemoryCache = mediaFileMemoryCache;
- }
-
- public void setMediaFileDao(MediaFileDao mediaFileDao) {
- this.mediaFileDao = mediaFileDao;
- }
-
- /**
- * Returns all media files that are children, grand-children etc of a given media file.
- * Directories are not included in the result.
- *
- * @param sort Whether to sort files in the same directory.
- * @return All descendant music files.
- */
- public List<MediaFile> getDescendantsOf(MediaFile ancestor, boolean sort) {
-
- if (ancestor.isFile()) {
- return Arrays.asList(ancestor);
- }
-
- List<MediaFile> result = new ArrayList<MediaFile>();
-
- for (MediaFile child : getChildrenOf(ancestor, true, true, sort)) {
- if (child.isDirectory()) {
- result.addAll(getDescendantsOf(child, sort));
- } else {
- result.add(child);
- }
- }
- return result;
- }
-
- public void setMetaDataParserFactory(MetaDataParserFactory metaDataParserFactory) {
- this.metaDataParserFactory = metaDataParserFactory;
- }
-
- public void updateMediaFile(MediaFile mediaFile) {
- mediaFileDao.createOrUpdateMediaFile(mediaFile);
- }
-
- /**
- * Increments the play count and last played date for the given media file and its
- * directory and album.
- */
- public void incrementPlayCount(MediaFile file) {
- Date now = new Date();
- file.setLastPlayed(now);
- file.setPlayCount(file.getPlayCount() + 1);
- updateMediaFile(file);
-
- MediaFile parent = getParentOf(file);
- if (!isRoot(parent)) {
- parent.setLastPlayed(now);
- parent.setPlayCount(parent.getPlayCount() + 1);
- updateMediaFile(parent);
- }
-
- Album album = albumDao.getAlbum(file.getAlbumArtist(), file.getAlbumName());
- if (album != null) {
- album.setLastPlayed(now);
- album.setPlayCount(album.getPlayCount() + 1);
- albumDao.createOrUpdateAlbum(album);
- }
- }
-
- public void setAlbumDao(AlbumDao albumDao) {
- this.albumDao = albumDao;
- }
-
-}