/*
This file is part of Libresonic.
Libresonic 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.
Libresonic 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 Libresonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 (C) Libresonic Authors
Based upon Subsonic, Copyright 2009 (C) Sindre Mehus
*/
package org.libresonic.player.service.metadata;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.libresonic.player.domain.MediaFile;
import org.libresonic.player.domain.MusicFolder;
import org.libresonic.player.service.ServiceLocator;
import org.libresonic.player.service.SettingsService;
import java.io.File;
import java.util.List;
/**
* Parses meta data from media files.
*
* @author Sindre Mehus
*/
public abstract class MetaDataParser {
/**
* Parses meta data for the given file.
*
* @param file The file to parse.
* @return Meta data for the file, never null.
*/
public MetaData getMetaData(File file) {
MetaData metaData = getRawMetaData(file);
String artist = metaData.getArtist();
String albumArtist = metaData.getAlbumArtist();
String album = metaData.getAlbumName();
String title = metaData.getTitle();
if (artist == null) {
artist = guessArtist(file);
}
if (albumArtist == null) {
albumArtist = guessArtist(file);
}
if (album == null) {
album = guessAlbum(file, artist);
}
if (title == null) {
title = guessTitle(file);
}
title = removeTrackNumberFromTitle(title, metaData.getTrackNumber());
metaData.setArtist(artist);
metaData.setAlbumArtist(albumArtist);
metaData.setAlbumName(album);
metaData.setTitle(title);
return metaData;
}
/**
* Parses meta data for the given file. No guessing or reformatting is done.
*
*
* @param file The file to parse.
* @return Meta data for the file.
*/
public abstract MetaData getRawMetaData(File file);
/**
* Updates the given file with the given meta data.
*
* @param file The file to update.
* @param metaData The new meta data.
*/
public abstract void setMetaData(MediaFile file, MetaData metaData);
/**
* Returns whether this parser is applicable to the given file.
*
* @param file The file in question.
* @return Whether this parser is applicable to the given file.
*/
public abstract boolean isApplicable(File file);
/**
* Returns whether this parser supports tag editing (using the {@link #setMetaData} method).
*
* @return Whether tag editing is supported.
*/
public abstract boolean isEditingSupported();
/**
* Guesses the artist for the given file.
*/
public String guessArtist(File file) {
File parent = file.getParentFile();
if (isRoot(parent)) {
return null;
}
File grandParent = parent.getParentFile();
return isRoot(grandParent) ? null : grandParent.getName();
}
/**
* Guesses the album for the given file.
*/
public String guessAlbum(File file, String artist) {
File parent = file.getParentFile();
String album = isRoot(parent) ? null : parent.getName();
if (artist != null && album != null) {
album = album.replace(artist + " - ", "");
}
return album;
}
/**
* Guesses the title for the given file.
*/
public String guessTitle(File file) {
return StringUtils.trim(FilenameUtils.getBaseName(file.getPath()));
}
private boolean isRoot(File file) {
SettingsService settings = ServiceLocator.getSettingsService();
List<MusicFolder> folders = settings.getAllMusicFolders(false, true);
for (MusicFolder folder : folders) {
if (file.equals(folder.getPath())) {
return true;
}
}
return false;
}
/**
* Removes any prefixed track number from the given title string.
*
* @param title The title with or without a prefixed track number, e.g., "02 - Back In Black".
* @param trackNumber If specified, this is the "true" track number.
* @return The title with the track number removed, e.g., "Back In Black".
*/
protected String removeTrackNumberFromTitle(String title, Integer trackNumber) {
title = title.trim();
// Don't remove numbers if true track number is missing, or if title does not start with it.
if (trackNumber == null || !title.matches("0?" + trackNumber + "[\\.\\- ].*")) {
return title;
}
String result = title.replaceFirst("^\\d{2}[\\.\\- ]+", "");
return result.length() == 0 ? title : result;
}
}