package model;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import logging.LogUtil;
import manager.AudioManager;
import manager.CollectorManager;
import model.audio.Genres;
import model.audio.interfaces.IAudioFile;
import model.collector.interfaces.ICoverArtCollector;
import model.collector.interfaces.IID3DataCollector;
import model.collector.interfaces.ILyricsCollector;
import model.exception.AudioFileException;
import model.exception.CollectorException;
import model.progressbar.interfaces.IProgressBar;
import model.structure.FieldReplacerData;
import model.structure.ID3ImageData;
import model.structure.ID3LyricsData;
import model.structure.ID3TagData;
import model.table.ID3TagTableModel;
import model.util.Commons;
import model.util.FileUtil;
import model.util.Graphics;
import com.cf.structures.DataDouble;
import com.mpatric.mp3agic.NotSupportedException;
import config.Config;
public class ID3TagModel {
/**
* the logger
*/
private final Logger logger = Logger.getLogger(this.getClass().getName());
/**
* the loaded audio files
*/
private List<IAudioFile> audioFiles;
/**
* all paths of loaded files
*/
private Set<String> readPaths;
/**
* index of the currently chosen file
*/
private int currIndex;
/**
* process of all loaded custom audio players
*/
private List<Process> audioPlayers;
/**
* the stop flag, if set to true all operations should stop
*/
private boolean stopFlag;
/**
* Constructor
*/
public ID3TagModel() {
audioFiles = new ArrayList<>();
readPaths = new HashSet<>();
currIndex = -1;
audioPlayers = new ArrayList<>();
stopFlag = false;
}
/**
* sets the stop flag and stops all operations
*
* @param set
* ture if stop, else false
*/
public void setStopFlag(boolean set) {
logger.log(Level.FINER, "set stop flag: " + set);
this.stopFlag = set;
}
/**
* adds the given audio file
*
* @param path
* path to audio file
*
* @return true if added successfully, else false
*/
public boolean addAudioFile(String path) throws AudioFileException {
logger.log(Level.FINER, "adding audio file: " + path + " already read: " + readPaths.contains(path));
if (stopFlag)
return false;
if (readPaths.contains(path))
return false;
if (!Commons.isValidExtension(FileUtil.getFileExtension(path)))
return false;
audioFiles.add(AudioManager.getInstance().getAudioFile(path, Config.getInstance().isDeleteID3v1Tag(), Config.getInstance().isSetID3v1Tag()));
readPaths.add(path);
return true;
}
/**
* reads the audio files in the given folder
*
* @param path
* path to the folder
* @param recursive
* read all subfolders recursively
*
* @return true if added successfully, else false
*/
public boolean addAudioFiles(String path, boolean recursive, IProgressBar bp) throws AudioFileException {
logger.log(Level.FINER, "reading all audio files from: " + path + " recursive: " + recursive);
if (stopFlag)
return false;
List<String> files = FileUtil.getFilesFromFolder(path, true);
for (String file : files) {
if (stopFlag)
return false;
logger.log(Level.FINER, "analyse file: " + file);
// its an audioFiles
if (Commons.isValidExtension(FileUtil.getFileExtension(file))) {
addAudioFile(file);
if (bp != null)
bp.nextStep();
}
// check if it is a folder, if so
else if (recursive && new File(file).isDirectory()) {
addAudioFiles(file, recursive, bp);
}
}
return true;
}
/**
* deletes the audio file at the given index
*
* @param index
* given index
*
* @return true if deleted successfully, else false
*/
private boolean deleteAudioFile(int index) {
logger.log(Level.FINER, "delete audio file with index " + index + " exists: " + (index < this.audioFiles.size()));
if (index >= this.audioFiles.size())
return false;
String path = this.audioFiles.get(index).getFilePath();
this.audioFiles.remove(index);
boolean delP = this.readPaths.remove(path);
logger.log(Level.FINER, "audioFile deleted completely: " + delP);
return true;
}
/**
* deletes the audio files at the given indices
*
* @param indices
* given indices
*
* @return true if deleted successfully, else false
*/
public boolean deleteAudioFiles(int[] indices) {
Integer[] tmp = new Integer[indices.length];
for (int i = 0; i < indices.length; i++)
tmp[i] = indices[i];
List<Integer> ints = Arrays.asList(tmp);
Collections.sort(ints);
int offset = 0;
for (Integer i : ints) {
deleteAudioFile(i - offset);
offset++;
}
return true;
}
/**
* deletes all audio files
*
* @return true if deleted successfully, else false
*/
public boolean clearAudioFiles() {
this.audioFiles.clear();
this.readPaths.clear();
return true;
}
/**
* starts the custom player with the given file
*
* @param path
* path to the given file
*
* @throws IOException
* thrown if player couldn't be loaded
*/
public void startCustomPlayer(String path) throws IOException {
logger.log(Level.FINER, "starting custom player cmd: " + Config.getInstance().getCustomPlayerCmd() + " \"" + path + "\"");
Process p = Runtime.getRuntime().exec(Config.getInstance().getCustomPlayerCmd() + " \"" + path + "\"");
this.audioPlayers.add(p);
}
/**
* stops all custom players
*/
public void stopPlayer() {
logger.log(Level.FINER, "Stop players: " + this.audioPlayers.size());
for (Process p : this.audioPlayers)
p.destroy();
this.audioPlayers.clear();
}
/**
* gets the table model for all loaded mps
*
* @return the table model
*/
public ID3TagTableModel getTableModel() {
return new ID3TagTableModel(this.audioFiles);
}
/**
* gets the audio file at index i
*
* @param i
* index
*
* @return the audio file
*/
public IAudioFile getAudioFile(int i) {
return this.audioFiles.get(i);
}
/**
* writes the current selected audio files cover to the given file path
*
* @param filePath
* given filepath
*
* @throws IllegalArgumentException
* thrown if no album image is available
* @throws IOException
* thrown if the album image couldn't be written
*/
public void writeID3TagImage(String filePath) throws IllegalArgumentException, IOException {
this.audioFiles.get(this.currIndex).writeImage(filePath, true);
}
/**
* sets the image from the given path to the current audio file
*
* @param path
* path to the given image
*
* @throws IOException
* thrown if image couldn't be read
*/
public void setAudioFileImageFromPath(String path) throws IOException {
this.audioFiles.get(this.currIndex).setImage(path);
}
/**
* deletes the image of the current selected audio file
*/
public void deleteAudioFileImage() {
this.audioFiles.get(this.currIndex).setImage(null, null);
}
/**
* sets the image from the given bytes with the given extension to the
* current audioFiles
*
* @param imgBytes
* given image in bytes
* @param extension
* given image extension, e.g. png
*/
public void setAudioFileImageFromBytes(byte[] imgBytes, String extension) {
this.audioFiles.get(this.currIndex).setImage(imgBytes, extension);
}
/**
* sets the given lyrics as lyrics for the current audioFiles
*
* @param lyrics
* given lyrics
*/
public void setLyrics(String lyrics) {
this.audioFiles.get(this.currIndex).setLyrics(lyrics);
}
/**
* sets the new current index of the selected audio file
*
* @param i
* given index
*/
public void setCurrIndex(int i) {
this.currIndex = i;
}
/**
* deletes the the file with the given index from the list and from the HDD
*
* @param index
* given index
*
* @return true if deleted, else false
*/
public boolean deleteFileFromHDD(int index) {
boolean del = new File(this.audioFiles.get(index).getFilePath()).delete();
if (del)
this.audioFiles.remove(index);
return del;
}
/**
* gets the index of the current selected audio file
*
* @return current index
*/
public int getCurrIndex() {
return this.currIndex;
}
/**
* gets the current selected audioFiles
*
* @return current audioFiles
*/
public IAudioFile getCurrAudioFile() {
return this.audioFiles.get(this.currIndex);
}
/**
* compares the current selected audio file with the given ID3Tag data, if
* something is different it will be updated in the current audio file
*
* @param data
* given ID3Tag data
*
* @return true if something is changed, else false
*/
public boolean makeChanges(ID3TagData data) {
return makeChanges(data, currIndex);
}
/**
* compares the current selected audio file with the given ID3Tag data, if
* something is different it will be updated in the current audio file
*
* @param data
* given ID3Tag data
* @param index
* index of the audio file
*
* @return true if something is changed, else false
*/
public boolean makeChanges(ID3TagData data, int index) {
if (currIndex == -1)
return false;
boolean changed = false;
logger.log(Level.FINEST,
"Title: data: " + data.getTitle() + " audio file: " + audioFiles.get(index).getTitle() + " equal: " + data.getTitle().equals(this.audioFiles.get(index).getTitle()));
if (!data.getTitle().equals(this.audioFiles.get(index).getTitle())) {
this.audioFiles.get(index).setTitle(data.getTitle());
changed = true;
}
logger.log(
Level.FINEST,
"Artist: data: " + data.getArtist() + " audio file: " + this.audioFiles.get(index).getArtist() + " equal: "
+ data.getArtist().equals(this.audioFiles.get(index).getArtist()));
if (!data.getArtist().equals(this.audioFiles.get(index).getArtist())) {
this.audioFiles.get(index).setArtist(data.getArtist());
changed = true;
}
logger.log(Level.FINEST, "AlbumArtist: data: " + data.getAlbumArtist() + " audio file: " + this.audioFiles.get(index).getAlbumArtist() + " equal: "
+ data.getAlbumArtist().equals(this.audioFiles.get(index).getAlbumArtist()));
if (!data.getAlbumArtist().equals(this.audioFiles.get(index).getAlbumArtist())) {
this.audioFiles.get(index).setAlbumArtist(data.getAlbumArtist());
changed = true;
}
logger.log(
Level.FINEST,
"Album: data: " + data.getAlbum() + " audio file: " + this.audioFiles.get(index).getAlbum() + " equal: "
+ data.getAlbum().equals(this.audioFiles.get(index).getAlbum()));
if (!data.getAlbum().equals(this.audioFiles.get(index).getAlbum())) {
this.audioFiles.get(index).setAlbum(data.getAlbum());
changed = true;
}
logger.log(Level.FINEST,
"Year: data: " + data.getYear() + " audio file: " + this.audioFiles.get(index).getYear() + " equal: " + data.getYear().equals(this.audioFiles.get(index).getYear()));
if (!data.getYear().equals(this.audioFiles.get(index).getYear())) {
this.audioFiles.get(index).setYear(data.getYear());
changed = true;
}
logger.log(
Level.FINEST,
"CurrTrack: data: " + data.getCurrTrack() + " audio file: " + this.audioFiles.get(index).getCurrTrack() + " equal: "
+ data.getCurrTrack().equals(this.audioFiles.get(index).getCurrTrack()));
if (!data.getCurrTrack().equals(this.audioFiles.get(index).getCurrTrack())) {
this.audioFiles.get(index).setCurrTrack(data.getCurrTrack());
changed = true;
}
logger.log(
Level.FINEST,
"MaxTrack: data: " + data.getMaxTrack() + " audio file: " + this.audioFiles.get(index).getMaxTrack() + " equal: "
+ data.getMaxTrack().equals(this.audioFiles.get(index).getMaxTrack()));
if (!data.getMaxTrack().equals(this.audioFiles.get(index).getMaxTrack())) {
this.audioFiles.get(index).setMaxTrack(data.getMaxTrack());
changed = true;
}
logger.log(
Level.FINEST,
"CurrCD: data: " + data.getCurrCD() + " audio file: " + this.audioFiles.get(index).getCurrCD() + " equal: "
+ data.getCurrCD().equals(this.audioFiles.get(index).getCurrCD()));
if (!data.getCurrCD().equals(this.audioFiles.get(index).getCurrCD())) {
this.audioFiles.get(index).setCurrCD(data.getCurrCD());
changed = true;
}
logger.log(
Level.FINEST,
"MaxCD: data: " + data.getMaxCD() + " audio file: " + this.audioFiles.get(index).getMaxCD() + " equal: "
+ data.getMaxCD().equals(this.audioFiles.get(index).getMaxCD()));
if (!data.getMaxCD().equals(this.audioFiles.get(index).getMaxCD())) {
this.audioFiles.get(index).setMaxCD(data.getMaxCD());
changed = true;
}
logger.log(Level.FINEST, "Genre: data: " + data.getGenre() + " audio file: " + this.audioFiles.get(index).getGenre() + " equal: "
+ (data.getGenre() == this.audioFiles.get(index).getGenre()));
if (data.getGenre() != this.audioFiles.get(index).getGenre()) {
this.audioFiles.get(index).setGenre(data.getGenre());
changed = true;
}
logger.log(
Level.FINEST,
"Comment: data: " + data.getComment() + " audio file: " + this.audioFiles.get(index).getComment() + " equal: "
+ data.getComment().equals(this.audioFiles.get(index).getComment()));
if (!data.getComment().equals(this.audioFiles.get(index).getComment())) {
this.audioFiles.get(index).setComment(data.getComment());
changed = true;
}
logger.log(
Level.FINEST,
"publisher: data: " + data.getPublisher() + " audio file: " + this.audioFiles.get(index).getPublisher() + " equal: "
+ data.getPublisher().equals(this.audioFiles.get(index).getPublisher()));
if (!data.getPublisher().equals(this.audioFiles.get(index).getPublisher())) {
this.audioFiles.get(index).setPublisher(data.getPublisher());
changed = true;
}
logger.log(
Level.FINEST,
"Composer: data: " + data.getComposer() + " audio file: " + this.audioFiles.get(index).getComposer() + " equal: "
+ data.getComposer().equals(this.audioFiles.get(index).getComposer()));
if (!data.getComposer().equals(this.audioFiles.get(index).getComposer())) {
this.audioFiles.get(index).setComposer(data.getComposer());
changed = true;
}
logger.log(Level.FINEST, "OrigArtist: data: " + data.getOrigArtist() + " audio file: " + this.audioFiles.get(index).getOriginalArtist() + " equal: "
+ data.getOrigArtist().equals(this.audioFiles.get(index).getOriginalArtist()));
if (!data.getOrigArtist().equals(this.audioFiles.get(index).getOriginalArtist())) {
this.audioFiles.get(index).setOriginalArtist(data.getOrigArtist());
changed = true;
}
logger.log(
Level.FINEST,
"Copyright: data: " + data.getCopyright() + " audio file: " + this.audioFiles.get(index).getCopyright() + " equal: "
+ data.getCopyright().equals(this.audioFiles.get(index).getCopyright()));
if (!data.getCopyright().equals(this.audioFiles.get(index).getCopyright())) {
this.audioFiles.get(index).setCopyright(data.getCopyright());
changed = true;
}
logger.log(Level.FINEST,
"URL: data: " + data.getUrl() + " audio file: " + this.audioFiles.get(index).getURL() + " equal: " + data.getUrl().equals(this.audioFiles.get(index).getURL()));
if (!data.getUrl().equals(this.audioFiles.get(index).getURL())) {
this.audioFiles.get(index).setURL(data.getUrl());
changed = true;
}
logger.log(
Level.FINEST,
"Encoder: data: " + data.getEncoder() + " audio file: " + this.audioFiles.get(index).getEncoder() + " equal: "
+ data.getEncoder().equals(this.audioFiles.get(index).getEncoder()));
if (!data.getEncoder().equals(this.audioFiles.get(index).getEncoder())) {
this.audioFiles.get(index).setEncoder(data.getEncoder());
changed = true;
}
logger.log(
Level.FINEST,
"Lyrics: data: " + data.getLyrics() + " audio file: " + this.audioFiles.get(index).getLyrics() + " equal: "
+ data.getLyrics().equals(this.audioFiles.get(index).getLyrics()));
if (!data.getLyrics().equals(this.audioFiles.get(index).getLyrics())) {
this.audioFiles.get(index).setLyrics(data.getLyrics());
changed = true;
}
return changed;
}
/**
* changes the given audio file id3tag data depending on the given action
* command and the given value
*
* @param actionCmd
* given action command
* @param value
* given value
* @param indices
* given audioFiless
*/
public void changeAudioFileComponent(String actionCmd, Object value, int[] indices) {
logger.log(Level.FINER, "change audio file component. actionCmd: " + actionCmd + " value: " + value + " indices: " + indices.length);
int index;
int trackNr = -1;
if (actionCmd.equals("trackRB"))
trackNr = (int) value;
for (int i = 0; i < indices.length; i++) {
index = indices[i];
switch (actionCmd) {
case "titleRB": {
logger.log(Level.FINEST, "change Title for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getTitle()))
audioFiles.get(index).setTitle(((String) value));
break;
}
case "artistRB": {
logger.log(Level.FINEST, "change Artist for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getArtist()))
audioFiles.get(index).setArtist(((String) value));
break;
}
case "albumArtistRB": {
logger.log(Level.FINEST, "change Album Artist for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getAlbumArtist()))
audioFiles.get(index).setAlbumArtist(((String) value));
break;
}
case "albumRB": {
logger.log(Level.FINEST, "change Album for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getAlbum()))
audioFiles.get(index).setAlbum(((String) value));
break;
}
case "yearRB": {
logger.log(Level.FINEST, "change Year for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getYear()))
audioFiles.get(index).setYear(((String) value));
break;
}
case "trackRB": {
logger.log(Level.FINEST, "change current Track for audio file " + index + " to " + trackNr);
if (trackNr != Integer.parseInt(this.audioFiles.get(index).getCurrTrack()))
audioFiles.get(index).setCurrTrack(Integer.toString(trackNr));
trackNr++;
break;
}
case "maxTracksRB": {
logger.log(Level.FINEST, "change max tracks for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getMaxTrack()))
audioFiles.get(index).setMaxTrack(((String) value));
break;
}
case "cdRB": {
logger.log(Level.FINEST, "change CD for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getCurrCD()))
audioFiles.get(index).setCurrCD(((String) value));
break;
}
case "maxCDRB": {
logger.log(Level.FINEST, "change max CD for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getMaxCD()))
audioFiles.get(index).setMaxCD(((String) value));
break;
}
case "genreRB": {
logger.log(Level.FINEST, "change Genre for audio file " + index + " to " + ((String) value));
if (Integer.parseInt((String) value) != this.audioFiles.get(index).getGenre())
audioFiles.get(index).setGenre((Integer.parseInt((String) value)));
break;
}
case "publisherRB": {
logger.log(Level.FINEST, "change publisher for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getPublisher()))
audioFiles.get(index).setPublisher(((String) value));
break;
}
case "commentRB": {
logger.log(Level.FINEST, "change Comment for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getComment()))
audioFiles.get(index).setComment(((String) value));
break;
}
case "composerRB": {
logger.log(Level.FINEST, "change Composer for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getComposer()))
audioFiles.get(index).setComposer(((String) value));
break;
}
case "origArtistRB": {
logger.log(Level.FINEST, "change Orig. Artist for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getOriginalArtist()))
audioFiles.get(index).setOriginalArtist(((String) value));
break;
}
case "copyrightRB": {
logger.log(Level.FINEST, "change Copyright for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getCopyright()))
audioFiles.get(index).setCopyright(((String) value));
break;
}
case "urlRB": {
logger.log(Level.FINEST, "change URL for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getURL()))
audioFiles.get(index).setURL(((String) value));
break;
}
case "encodedByRB": {
logger.log(Level.FINEST, "change Encoder for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getEncoder()))
audioFiles.get(index).setEncoder(((String) value));
break;
}
case "imageAllRB": {
logger.log(Level.FINEST, "change Albumcover for audio file " + index + " to Albumcover from " + currIndex);
audioFiles.get(index).setImage(getCurrAudioFile().getAlbumImage(), getCurrAudioFile().getAlbumImageFormat());
break;
}
case "lyricsRB": {
logger.log(Level.FINEST, "change lyrics for audio file " + index + " to " + ((String) value));
if (!((String) value).equals(this.audioFiles.get(index).getLyrics()))
audioFiles.get(index).setLyrics(((String) value));
break;
}
}
}
}
/**
* deletes the tag of the current selected audio file
*/
public void deleteTags() {
deleteTags(this.currIndex);
}
/**
* deletes the tags of the given audio file
*
* @param indices
* given indices of the audio file
*/
public void deleteTags(int[] indices) {
int index;
for (int i = 0; i < indices.length; i++) {
index = indices[i];
deleteTags(index);
}
}
/**
* delete all tags for audio file from the given index
*
* @param i
* given index
*/
private void deleteTags(int i) {
this.audioFiles.get(i).setTitle(null);
this.audioFiles.get(i).setArtist(null);
this.audioFiles.get(i).setAlbumArtist(null);
this.audioFiles.get(i).setAlbum(null);
this.audioFiles.get(i).setYear(null);
this.audioFiles.get(i).setTrack(null);
this.audioFiles.get(i).setCD(null);
this.audioFiles.get(i).setGenre(13);
this.audioFiles.get(i).setComment(null);
this.audioFiles.get(i).setComposer(null);
this.audioFiles.get(i).setOriginalArtist(null);
this.audioFiles.get(i).setCopyright(null);
this.audioFiles.get(i).setURL(null);
this.audioFiles.get(i).setEncoder(null);
this.audioFiles.get(i).setLyrics(null);
this.audioFiles.get(i).setImage(null, null);
}
/**
* undo the changes of the audio file of the given index
*
* @param index
* given index
*
* @throws AudioFileException
* thrown if audio file couldn't be reloaded
*/
public void undoChanges(int index) throws AudioFileException {
if (stopFlag)
return;
this.audioFiles.get(index).resetAudioFile();
}
/**
* gets the number of how many audio file of the given indices got changed
*
* @param indices
* given indices
*
* @return number of changed audio file
*/
public int getChangedNumber(int[] indices) {
// get changed audioFiless
int changed = 0;
for (int i = 0; i < indices.length; i++) {
if (audioFiles.get(indices[i]).hasChanged())
changed++;
}
return changed;
}
/**
* writes the given audio file to the harddisk
*
* @param indices
* given audio file
* @param pb
* the progressbar which will be updated for each changed audio
* file
*
* @throws NotSupportedException
* thrown if ID3Tag couldn't be generated
* @throws IOException
* thrown if new audio file couldn't be written
* @throws AudioFileException
* thrown if new audio file couldn't be reread
*/
public void writeAudioFiles(int[] indices, IProgressBar pb) throws NotSupportedException, IOException, AudioFileException {
for (int i = 0; i < indices.length; i++) {
if (this.stopFlag)
return;
logger.log(Level.FINER, "analyse audioFiles: " + indices[i] + " changed: " + audioFiles.get(indices[i]).hasChanged());
if (audioFiles.get(indices[i]).hasChanged()) {
if (!audioFiles.get(indices[i]).isWriteable())
throw new IOException("Couldn't write file: " + audioFiles.get(indices[i]).getFilePath());
audioFiles.get(indices[i]).save();
audioFiles.get(indices[i]).resetAudioFile();
pb.nextStep();
}
}
}
/**
* gets the number of all audio file
*
* @return number of all audio file
*/
public int getNumOfAudioFiles() {
return this.audioFiles.size();
}
/**
* changes the audio file with the given id3tag data
*
* @param audioFiles
* given audio file
*/
public void makesChanges(List<ID3TagData> audioFiles) {
for (ID3TagData tag : audioFiles) {
makeChanges(tag, tag.getIndex());
}
}
/**
* replaces the fields of the given audio file with the data
*
* @param indices
* given audio file
* @param data
* field replacer data
*/
public void replaceFields(int[] indices, FieldReplacerData data) {
int index;
for (int i = 0; i < indices.length; i++) {
index = indices[i];
String result = data.changeField(FieldReplacerData.TITLE, this.audioFiles.get(index).getTitle());
if (!result.equals(this.audioFiles.get(index).getTitle()))
this.audioFiles.get(index).setTitle(result);
result = data.changeField(FieldReplacerData.ARTIST, this.audioFiles.get(index).getArtist());
if (!result.equals(this.audioFiles.get(index).getArtist()))
this.audioFiles.get(index).setArtist(result);
result = data.changeField(FieldReplacerData.ALBUMARTIST, this.audioFiles.get(index).getAlbumArtist());
if (!result.equals(this.audioFiles.get(index).getAlbumArtist()))
this.audioFiles.get(index).setAlbumArtist(result);
result = data.changeField(FieldReplacerData.ALBUM, this.audioFiles.get(index).getAlbum());
if (!result.equals(this.audioFiles.get(index).getAlbum()))
this.audioFiles.get(index).setAlbum(result);
result = data.changeField(FieldReplacerData.YEAR, this.audioFiles.get(index).getYear());
if (!result.equals(this.audioFiles.get(index).getYear()))
this.audioFiles.get(index).setYear(result);
result = data.changeField(FieldReplacerData.TRACK, this.audioFiles.get(index).getTrack());
if (!result.equals(this.audioFiles.get(index).getTrack()))
this.audioFiles.get(index).setTrack(result);
result = data.changeField(FieldReplacerData.MAXTRACKS, this.audioFiles.get(index).getMaxTrack());
if (!result.equals(this.audioFiles.get(index).getMaxTrack()))
this.audioFiles.get(index).setMaxTrack(result);
result = data.changeField(FieldReplacerData.CD, this.audioFiles.get(index).getCD());
if (!result.equals(this.audioFiles.get(index).getCD()))
this.audioFiles.get(index).setCD(result);
result = data.changeField(FieldReplacerData.MAXCD, this.audioFiles.get(index).getMaxCD());
if (!result.equals(this.audioFiles.get(index).getMaxCD()))
this.audioFiles.get(index).setMaxCD(result);
result = data.changeField(FieldReplacerData.COMMENT, this.audioFiles.get(index).getComment());
if (!result.equals(this.audioFiles.get(index).getComment()))
this.audioFiles.get(index).setComment(result);
result = data.changeField(FieldReplacerData.COMPOSER, this.audioFiles.get(index).getComposer());
if (!result.equals(this.audioFiles.get(index).getComposer()))
this.audioFiles.get(index).setComposer(result);
result = data.changeField(FieldReplacerData.ORIGARTIST, this.audioFiles.get(index).getOriginalArtist());
if (!result.equals(this.audioFiles.get(index).getOriginalArtist()))
this.audioFiles.get(index).setOriginalArtist(result);
result = data.changeField(FieldReplacerData.COPYRIGHT, this.audioFiles.get(index).getCopyright());
if (!result.equals(this.audioFiles.get(index).getCopyright()))
this.audioFiles.get(index).setCopyright(result);
result = data.changeField(FieldReplacerData.URL, this.audioFiles.get(index).getURL());
if (!result.equals(this.audioFiles.get(index).getURL()))
this.audioFiles.get(index).setURL(result);
result = data.changeField(FieldReplacerData.ENCODEDBY, this.audioFiles.get(index).getEncoder());
if (!result.equals(this.audioFiles.get(index).getEncoder()))
this.audioFiles.get(index).setEncoder(result);
result = data.changeField(FieldReplacerData.LYRICS, this.audioFiles.get(index).getLyrics());
if (!result.equals(this.audioFiles.get(index).getLyrics()))
this.audioFiles.get(index).setLyrics(result);
}
}
/**
* gets a List containg a tuple with 2 ID3Tags. The first one is the current
* audioFiles data, the 2nd one is the changed data
*
* @param indices
* given indices
*
* @param regex
* given ID3TagRegex to get the neccessary id3tag data
*
* @return the list
*/
public List<DataDouble<ID3TagData, ID3TagData>> getChangesAudioFileList(int[] indices, ID3TagRegex regex) {
List<DataDouble<ID3TagData, ID3TagData>> result = new ArrayList<DataDouble<ID3TagData, ID3TagData>>();
int index;
for (int i = 0; i < indices.length; i++) {
index = indices[i];
String name = FileUtil.getFileNameWithoutExtension(this.audioFiles.get(index).getFilePath());
ID3TagData curr = new ID3TagData();
curr.setAudioFile(this.audioFiles.get(index), index);
ID3TagData newTag = new ID3TagData();
newTag.setIndex(index);
newTag.setTitle(regex.getTag(ID3TagRegex.TITLE, name));
newTag.setArtist(regex.getTag(ID3TagRegex.ARTIST, name));
newTag.setAlbumArtist(regex.getTag(ID3TagRegex.ALBUMARTIST, name));
newTag.setAlbum(regex.getTag(ID3TagRegex.ALBUM, name));
newTag.setYear(regex.getTag(ID3TagRegex.YEAR, name));
newTag.setCurrTrack(regex.getTag(ID3TagRegex.TRACK, name));
newTag.setMaxTrack(regex.getTag(ID3TagRegex.MAXTRACKS, name));
newTag.setCurrCD(regex.getTag(ID3TagRegex.CD, name));
newTag.setMaxCD(regex.getTag(ID3TagRegex.MAXCD, name));
newTag.setGenre(Genres.getGenreLoose(regex.getTag(ID3TagRegex.GENRE, name)));
newTag.setComment(regex.getTag(ID3TagRegex.COMMENT, name));
newTag.setComposer(regex.getTag(ID3TagRegex.COMPOSER, name));
newTag.setOrigArtist(regex.getTag(ID3TagRegex.ORIGARTIST, name));
newTag.setCopyright(regex.getTag(ID3TagRegex.COPYRIGHT, name));
newTag.setUrl(regex.getTag(ID3TagRegex.URL, name));
newTag.setEncoder(regex.getTag(ID3TagRegex.ENCODEDBY, name));
newTag.setChanged(regex.getContainsTags());
result.add(new DataDouble<ID3TagData, ID3TagData>(curr, newTag));
}
return result;
}
/**
* updates the given audio file using the enabled collector. Returns a List
* with DataDouble containing the current id3 data und the new id3 data
*
* @param indices
* given audio file
* @param pb
* the progressbar. Each audio file adds one value to the
* progressbar
*
* @return the data double list
*/
public List<DataDouble<ID3TagData, ID3TagData>> getID3DataAudioFileUpdate(int[] indices, IProgressBar pb) {
List<DataDouble<ID3TagData, ID3TagData>> result = new ArrayList<>();
int index;
pb.nextStep();
for (int i = 0; i < indices.length; i++) {
if (stopFlag)
break;
if (pb != null)
pb.nextStep();
index = indices[i];
ID3TagData currData = new ID3TagData();
currData.setAudioFile(this.audioFiles.get(index), index);
ID3TagData newData = new ID3TagData();
newData.setIndex(index);
// get all collectors
List<IID3DataCollector> collectors = CollectorManager.getInstance().getID3DataCollectors();
// create id3 data for collector, title, artist and album
ID3TagData searchData = new ID3TagData();
searchData.setTitle(this.audioFiles.get(index).getTitle());
searchData.setArtist(this.audioFiles.get(index).getArtist());
searchData.setAlbum(this.audioFiles.get(index).getAlbum());
logger.log(Level.FINER, "getting ID3 tag data for artist: " + searchData.getArtist() + " title: " + searchData.getTitle() + " album: " + searchData.getAlbum());
IID3DataCollector collector = null;
// try if one found data, if so its fine, if not try next one
for (IID3DataCollector c : collectors) {
logger.log(Level.FINER, "try using collector: " + c.getCollectorName());
collector = c;
collector.setData(searchData);
try {
collector.init();
} catch (CollectorException e) {
logger.log(Level.SEVERE, "Error while getting id3 tag data:\n" + LogUtil.getStackTrace(e), e);
continue;
}
logger.log(Level.FINER, "found using collector " + collector.getCollectorName() + " found: " + collector.isDataFound());
if (collector.isDataFound())
break;
}
String track = collector.getTrack();
String title = collector.getTitle();
String artist = collector.getArtist();
String albumArtist = collector.getAlbumArtist();
String album = collector.getAlbum();
String year = collector.getYear();
String maxTracks = collector.getMaxTracks();
String cd = collector.getCD();
String maxCD = collector.getMaxCD();
int genre = collector.getGenre();
String comment = collector.getComment();
String composer = collector.getComposer();
String origArtist = collector.getOrigArtist();
String copyright = collector.getCopyright();
String url = collector.getURL();
String encoder = collector.getEncoder();
logger.log(Level.FINER, "update audio files title: " + title + " artist: " + artist + " Album Artist: " + albumArtist + " album: " + album + " year: " + year
+ " track: " + track + " maxTrack: " + maxTracks + " cd: " + cd + " maxCD: " + maxCD + " genre: " + genre + " comment: " + comment + " composer: " + composer
+ " origArtist: " + origArtist + " copyright: " + copyright + " url: " + url + " encoder: " + encoder);
newData.setTitle((title != null && title.trim().length() != 0) ? title : "");
newData.setArtist((artist != null && artist.trim().length() != 0) ? artist : "");
newData.setAlbumArtist((albumArtist != null && albumArtist.trim().length() != 0) ? albumArtist : "");
newData.setAlbum((album != null && album.trim().length() != 0) ? album : "");
newData.setYear((year != null && year.trim().length() != 0) ? year : "");
newData.setCurrTrack((track != null && track.trim().length() != 0) ? track : "");
newData.setMaxTrack((maxTracks != null && maxTracks.trim().length() != 0) ? maxTracks : "");
newData.setCurrCD((cd != null && cd.trim().length() != 0) ? cd : "");
newData.setMaxCD((maxCD != null && maxCD.trim().length() != 0) ? maxCD : "");
newData.setGenre(genre);
newData.setComment((comment != null && comment.trim().length() != 0) ? comment : "");
newData.setComposer((composer != null && composer.trim().length() != 0) ? composer : "");
newData.setOrigArtist((origArtist != null && origArtist.trim().length() != 0) ? origArtist : "");
newData.setCopyright((copyright != null && copyright.trim().length() != 0) ? copyright : "");
newData.setUrl((url != null && url.trim().length() != 0) ? url : "");
newData.setEncoder((encoder != null && encoder.trim().length() != 0) ? encoder : "");
// set album tracks if found by the parser
newData.setAlbumTracks(collector.getAllAlbumTracks());
boolean[] changed = new boolean[] { (title != null && title.trim().length() != 0), (artist != null && artist.trim().length() != 0),
(albumArtist != null && albumArtist.trim().length() != 0), (album != null && album.trim().length() != 0), (year != null && year.trim().length() != 0),
(track != null && track.trim().length() != 0), (maxTracks != null && maxTracks.trim().length() != 0), (cd != null && cd.trim().length() != 0),
(maxCD != null && maxCD.trim().length() != 0), true, (comment != null && comment.trim().length() != 0), (composer != null && composer.trim().length() != 0),
(origArtist != null && origArtist.trim().length() != 0), (copyright != null && copyright.trim().length() != 0), (url != null && url.trim().length() != 0),
(encoder != null && encoder.trim().length() != 0) };
newData.setChanged(changed);
result.add(new DataDouble<ID3TagData, ID3TagData>(currData, newData));
}
return result;
}
/**
* updates the given audio file using the enabled collector. Returns a List
* with DataDouble containing the current image und the new image data
*
* @param indices
* given audio file
* @param pb
* the progressbar. Each audio file adds one value to the
* progressbar
*
* @return the data double list
*/
public List<DataDouble<ID3ImageData, ID3ImageData>> getCoverArtUpdate(int[] indices, IProgressBar pb) {
List<DataDouble<ID3ImageData, ID3ImageData>> result = new ArrayList<>();
int index;
pb.nextStep();
for (int i = 0; i < indices.length; i++) {
if (stopFlag)
break;
if (pb != null)
pb.nextStep();
index = indices[i];
ID3ImageData currData = new ID3ImageData(index);
currData.setImage(this.audioFiles.get(index).getAlbumImage());
currData.setExtension(this.audioFiles.get(index).getAlbumImageFormat());
currData.setArtist(this.audioFiles.get(index).getArtist());
currData.setAlbum(this.audioFiles.get(index).getAlbum());
ID3ImageData newData = new ID3ImageData(index);
// get all collectors
List<ICoverArtCollector> collectors = CollectorManager.getInstance().getCoverArtCollectors();
// create id3 data for collector, title and album
ID3TagData searchData = new ID3TagData();
searchData.setArtist(this.audioFiles.get(index).getArtist());
searchData.setAlbum(this.audioFiles.get(index).getAlbum());
logger.log(Level.FINER, "getting cover image for artist: " + searchData.getArtist() + " album: " + searchData.getAlbum());
ICoverArtCollector collector = null;
for (ICoverArtCollector c : collectors) {
logger.log(Level.FINER, "try using collector: " + c.getCollectorName());
collector = c;
collector.setData(searchData);
try {
collector.init();
} catch (CollectorException e) {
logger.log(Level.SEVERE, "Error while getting cover image:\n" + LogUtil.getStackTrace(e), e);
continue;
}
logger.log(Level.FINER, "found using collector " + collector.getCollectorName() + " found: " + collector.isDataFound());
if (collector.isDataFound())
break;
}
BufferedImage img = collector.getImage();
if (img != null) {
// if max image length is set
if (Config.getInstance().isUseMaxImageLength()) {
// if image is more than max size -> scale it
if (img.getWidth() > Config.getInstance().getMaxImageLength() && img.getWidth() >= img.getHeight()) {
img = Graphics.scale(img, ((double) Config.getInstance().getMaxImageLength()) / ((double) img.getWidth()));
} else if (img.getHeight() > Config.getInstance().getMaxImageLength() && img.getHeight() >= img.getWidth()) {
img = Graphics.scale(img, ((double) Config.getInstance().getMaxImageLength()) / ((double) img.getHeight()));
}
}
// convert to jpeg if extension isnt jpeg
if (!collector.getExtension().equalsIgnoreCase("jpeg") && !collector.getExtension().equalsIgnoreCase("jpg")) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(img, "jpeg", baos);
baos.flush();
newData.setImage(baos.toByteArray());
baos.close();
newData.setExtension("jpeg");
} catch (IOException e) {
e.printStackTrace();
}
} else {
newData.setImage(collector.getImageAsBytes());
newData.setExtension("jpeg");
}
}
newData.setArtist(this.audioFiles.get(index).getArtist());
newData.setAlbum(this.audioFiles.get(index).getAlbum());
newData.setChanged(collector.getImageAsBytes() != null);
result.add(new DataDouble<ID3ImageData, ID3ImageData>(currData, newData));
}
return result;
}
/**
* updates the given audio file using the enabled collector. Returns a List
* with DataDouble containing the current lyrics and the new lyrics data
*
* @param indices
* given audio file
* @param pb
* the progressbar. Each audio file adds one value to the
* progressbar
*
* @return the data double list
*/
public List<DataDouble<ID3LyricsData, ID3LyricsData>> getLyricsAudioFileUpdate(int[] indices, IProgressBar pb) {
List<DataDouble<ID3LyricsData, ID3LyricsData>> result = new ArrayList<>();
int index;
if (pb != null)
pb.nextStep();
for (int i = 0; i < indices.length; i++) {
if (stopFlag)
break;
if (pb != null)
pb.nextStep();
index = indices[i];
ID3LyricsData currData = new ID3LyricsData(index);
currData.setLyrics(this.audioFiles.get(index).getLyrics());
currData.setArtist(this.audioFiles.get(index).getArtist());
currData.setTitle(this.audioFiles.get(index).getTitle());
ID3LyricsData newData = new ID3LyricsData(index);
// get all collectors
List<ILyricsCollector> collectors = CollectorManager.getInstance().getLyricsCollectors();
// create id3 data for collector, title and album
ID3TagData searchData = new ID3TagData();
searchData.setArtist(this.audioFiles.get(index).getArtist());
searchData.setTitle(this.audioFiles.get(index).getTitle());
logger.log(Level.FINER, "getting lyrics for artist: " + searchData.getArtist() + " title: " + searchData.getTitle());
ILyricsCollector collector = null;
for (ILyricsCollector c : collectors) {
logger.log(Level.FINER, "try using collector: " + c.getCollectorName());
collector = c;
collector.setData(searchData);
try {
collector.init();
} catch (CollectorException e) {
logger.log(Level.SEVERE, "Error while getting lyrics:\n" + LogUtil.getStackTrace(e), e);
continue;
}
logger.log(Level.FINER, "found using collector " + collector.getCollectorName() + " found: " + collector.isDataFound());
if (collector.isDataFound())
break;
}
newData.setLyrics(collector.getLyrics());
newData.setArtist(this.audioFiles.get(index).getArtist());
newData.setTitle(this.audioFiles.get(index).getTitle());
result.add(new DataDouble<ID3LyricsData, ID3LyricsData>(currData, newData));
}
return result;
}
/**
* sets the covers of all audio files of the given image data list
*
* @param data
* data list
*/
public void setCoverArt(List<ID3ImageData> data) {
logger.log(Level.FINER, "set Cover art");
int index;
for (ID3ImageData img : data) {
logger.log(Level.FINER, "set image for id: " + img.getIndex() + " with " + img.getImage().length + " bytes extension: " + img.getExtension());
index = img.getIndex();
this.audioFiles.get(index).setImage(img.getImage(), img.getExtension());
}
}
/**
* sets the lyrics of all audio files of the given lyrics data list
*
* @param data
* data list
*/
public void setLyrics(List<ID3LyricsData> data) {
logger.log(Level.FINER, "set Lyrics.");
int index;
for (ID3LyricsData l : data) {
logger.log(Level.FINER, "set lyrics for id: " + l.getIndex() + " empty: " + (l.getLyrics().trim().length() == 0));
index = l.getIndex();
if (l != null && l.getLyrics().trim().length() != 0)
this.audioFiles.get(index).setLyrics(l.getLyrics());
}
}
/**
* rescales an image to the given width and height
*
* @param width
* given width
* @param height
* given height
*
* @throws IOException
* thrown if image couldn't be set
*/
public void rescaleImage(int width, int height) throws IOException {
byte[] bytes = getCurrAudioFile().getAlbumImage();
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage img = ImageIO.read(in);
in.close();
if (img.getWidth() == width && img.getHeight() == height)
return;
img = Graphics.scale(img, width, height);
logger.log(Level.FINER, "scaled image to width: " + img.getWidth() + " height: " + img.getHeight());
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(img, "jpeg", out);
getCurrAudioFile().setImage(out.toByteArray(), "jpeg");
out.close();
}
}