/*
You may freely copy, distribute, modify and use this class as long
as the original author attribution remains intact. See message
below.
Copyright (C) 2005 Christian Pesch. All Rights Reserved.
*/
package slash.metamusic.mp3.tools;
import slash.metamusic.mp3.MP3File;
import slash.metamusic.util.Files;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
/**
* Cleans and extends the meta data for all MP3s in a file system tree.
*
* @author Christian Pesch
* @version $Id: MP3Tidy.java 956 2007-02-03 10:39:39Z cpesch $
*/
public class MP3Tidy {
/**
* Logging output
*/
protected static final Logger log = Logger.getLogger(MP3Tidy.class.getName());
private String extension = "mp3";
private boolean renamePathToTags = false, renameFileToTags = true;
private String newRoot = null;
private MP3Cleaner cleaner = new MP3Cleaner();
private MP3Extender extender = new MP3Extender();
private MP3Mover mover = new MP3Mover();
private List<Notifier> notifiers = new ArrayList<Notifier>();
private List<File> files = new ArrayList<File>();
private int fileCount, processedFileCount, failedFileCount,
modifiedFileCount, movedFileCount, renamedFileCount, extendedTagCount, cleanedTagCount;
public MP3Tidy() {
addNotifier(new LogNotifier());
}
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
public boolean addNotifier(Notifier notifier) {
return notifiers.add(notifier);
}
public boolean removeNotifier(Notifier notifier) {
return notifiers.remove(notifier);
}
public void setAddCover(boolean addCover) {
extender.setAddCover(addCover);
}
public void setAddCoverToFolder(boolean addCoverToFolder) {
extender.setAddCoverToFolder(addCoverToFolder);
}
public void setCoverDirectoryName(String coverDirectoryName) {
extender.setCoverDirectoryName(coverDirectoryName);
}
public void setAddLyrics(boolean addLyrics) {
extender.setAddLyrics(addLyrics);
}
public void setLyricsDirectoryName(String lyricsDirectoryName) {
extender.setLyricsDirectoryName(lyricsDirectoryName);
}
public void setAddMetaData(boolean addMetaData) {
extender.setAddMetaData(addMetaData);
}
public void setRemoveiTunesTags(boolean removeiTunesTags) {
cleaner.setRemoveiTunesTags(removeiTunesTags);
}
public void setRemoveMusicBrainzTags(boolean removeMusicBrainzTags) {
cleaner.setRemoveMusicBrainzTags(removeMusicBrainzTags);
}
public void setRemoveMusicMatchTags(boolean removeMusicMatchTags) {
cleaner.setRemoveMusicMatchTags(removeMusicMatchTags);
}
public boolean isRemoveWindowsMediaPlayerTags() {
return cleaner.isRemoveWindowsMediaPlayerTags();
}
public void setRemoveWindowsMediaPlayerTags(boolean removeWindowsMediaPlayerTags) {
cleaner.setRemoveWindowsMediaPlayerTags(removeWindowsMediaPlayerTags);
}
public void setUnifyTags(boolean unifyTags) {
cleaner.setUnifyTags(unifyTags);
}
public boolean isRenameFileToTags() {
return renameFileToTags;
}
public void setRenameFileToTags(boolean renameFileToTags) {
this.renameFileToTags = renameFileToTags;
}
public boolean isWriteID3v1() {
return cleaner.isWriteID3v1() && extender.isWriteID3v1();
}
public void setWriteID3v1(boolean writeID3v1) {
cleaner.setWriteID3v1(writeID3v1);
extender.setWriteID3v1(writeID3v1);
}
public boolean isWriteID3v2() {
return cleaner.isWriteID3v2() || extender.isWriteID3v2();
}
public void setWriteID3v2(boolean writeID3v2) {
cleaner.setWriteID3v2(writeID3v2);
extender.setWriteID3v2(writeID3v2);
}
public void prepare(List<File> paths) {
files.clear();
for (Notifier notifier : notifiers)
notifier.startedToPrepare();
for (File path : paths) {
List<File> collected = Files.collectFiles(path, getExtension());
files.addAll(collected);
for (Notifier notifier : notifiers)
notifier.preparing(collected.size(), path);
}
fileCount = files.size();
for (Notifier notifier : notifiers)
notifier.finishedToPrepare(fileCount);
}
public void start() {
processedFileCount = 0;
failedFileCount = 0;
modifiedFileCount = 0;
movedFileCount = 0;
renamedFileCount = 0;
cleanedTagCount = 0;
extendedTagCount = 0;
for (Notifier notifier : notifiers)
notifier.started();
}
public boolean next() {
if (processedFileCount >= fileCount) {
for (Notifier notifier : notifiers)
notifier.finished(modifiedFileCount, renamedFileCount, cleanedTagCount, extendedTagCount);
return false;
} else {
File file = null;
try {
file = files.get(processedFileCount++);
if (newRoot != null) {
File newFile = new File(newRoot, file.getName());
if (file.renameTo(newFile))
file = newFile;
}
for (Notifier notifier : notifiers)
notifier.processing(processedFileCount);
process(file);
}
catch (Throwable t) {
t.printStackTrace();
log.severe("Error while processing " + file + ": " + t.getMessage());
failedFileCount++;
for (Notifier notifier : notifiers)
notifier.failed(failedFileCount, file);
}
return true;
}
}
protected void process(File file) throws IOException {
MP3File mp3 = MP3File.readValidFile(file);
if (mp3 == null)
throw new IllegalArgumentException("No valid mp3: " + file.getAbsolutePath());
boolean extendedTags = extender.extendTags(mp3);
boolean cleanedTags = cleaner.cleanTags(mp3);
if (extendedTags)
extendedTagCount++;
if (cleanedTags)
cleanedTagCount++;
boolean changeToID3v2 = !isWriteID3v1() && mp3.isID3v1() && mp3.isID3v2();
boolean changeToID3v1 = !isWriteID3v2() && mp3.isID3v1() && mp3.isID3v2();
boolean modifiedFile = extendedTags || cleanedTags || changeToID3v2 || changeToID3v1;
if (modifiedFile) {
modifiedFileCount++;
extender.write(mp3);
}
boolean movedFile = false, renamedFile = false;
if (isRenameFileToTags()) {
if (renamePathToTags) {
if (mover.moveFileToTags(mp3)) {
movedFile = true;
movedFileCount++;
}
} else {
if (mover.renameFileToTags(mp3)) {
renamedFile = true;
renamedFileCount++;
}
}
}
if (isRemoveWindowsMediaPlayerTags())
cleaner.removeCovers(file);
for (Notifier notifier : notifiers)
notifier.processed(movedFileCount, renamedFileCount, modifiedFileCount,
cleanedTagCount, extendedTagCount,
file,
movedFile, renamedFile, modifiedFile,
cleanedTags, extendedTags);
}
public interface Notifier {
void startedToPrepare();
void preparing(int fileCount, File path);
void finishedToPrepare(int fileCount);
void started();
void processing(int processedFiles);
void failed(int failedFileCount, File file);
void processed(int movedFileCount, int renamedFileCount, int modifiedFileCount, int cleanedTagCount, int extendedTagCount,
File file, boolean movedFile, boolean renamedFile, boolean modifiedFile, boolean cleanedTags, boolean extendedTags);
void finished(int modifiedFileCount, int renamedFileCount, int cleanedTagCount, int extendedTagCount);
}
private static class LogNotifier implements Notifier {
private int fileCount = 0, processedFiles = 0;
public void startedToPrepare() {
}
public void preparing(int fileCount, File path) {
log.info("Preparing " + fileCount + " files from " + path + " to process");
}
public void finishedToPrepare(int fileCount) {
this.fileCount = fileCount;
log.info("Prepared " + fileCount + " files");
}
public void started() {
log.info("Started with " + fileCount + " files");
}
public void processing(int processedFiles) {
this.processedFiles = processedFiles;
log.info("Processing " + processedFiles + ". from " + fileCount + " files");
}
public void failed(int failedFileCount, File file) {
log.info("Failed to process " + failedFileCount + ". file: " + file);
}
public void processed(int movedFileCount, int renamedFileCount, int modifiedFileCount, int cleanedTagCount, int extendedTagCount, File file,
boolean movedFile, boolean renamedFile, boolean modifiedFile, boolean cleanedTags, boolean extendedTags) {
if (movedFile)
log.info("Moved " + movedFileCount + ". file: " + file);
if (renamedFile)
log.info("Renamed " + renamedFileCount + ". file: " + file);
if (modifiedFile)
log.info("Modified " + modifiedFileCount + ". file: " + file);
if (cleanedTags)
log.info("Cleaned tags of " + cleanedTagCount + ". file: " + file);
if (extendedTags)
log.info("Extended tags of " + extendedTagCount + ". file: " + file);
}
public void finished(int modifiedFileCount, int renamedFileCount, int cleanedTagCount, int extendedTagCount) {
log.info("Processed " + processedFiles + " out of " + fileCount + " files");
log.info("Modified " + modifiedFileCount + " out of " + processedFiles + " processed files");
log.info("Renamed " + renamedFileCount + " out of " + processedFiles + " processed files");
log.info("Cleaned tags from " + cleanedTagCount + " out of " + fileCount + " files");
log.info("Extended tags from " + extendedTagCount + " out of " + fileCount + " files");
}
}
}