View Javadoc

1   package com.melloware.jukes.file.tag;
2   
3   import java.io.File;
4   import java.util.Map;
5   
6   import org.apache.commons.lang.StringUtils;
7   import org.apache.commons.logging.Log;
8   import org.apache.commons.logging.LogFactory;
9   import org.jaudiotagger.audio.AudioFile;
10  import org.jaudiotagger.audio.AudioFileIO;
11  import org.jaudiotagger.audio.exceptions.CannotReadException;
12  import org.jaudiotagger.audio.exceptions.CannotWriteException;
13  import org.jaudiotagger.tag.FieldDataInvalidException;
14  
15  import com.melloware.jukes.exception.MusicTagException;
16  
17  /**
18   * MusicTag class used for editing OGG, FLAC, SPEEX, and APE file tags. The Ogg
19   * Vorbiscomment system is used as described at
20   * xiph.org/vorbis/doc/v-comment.html
21   * <p>
22   * The Entagged (http://entagged.sourceforge.net/) library is used to read these
23   * types of Tags.
24   * <p>
25   * Copyright (c) 2006 Melloware, Inc. <http://www.melloware.com>
26   * @author Emil A. Lefkof III <info@melloware.com>
27   * @version 4.0
28   */
29  public final class AudioFileTag extends MusicTag {
30  
31     private static final Log LOG = LogFactory.getLog(AudioFileTag.class);
32     private AudioFile audioFile;
33  
34     /**
35      * Contructor that accepts a file.
36      * <p>
37      * @param aFile the file to open
38      * @throws MusicTagException if any error occurs loading tag
39      */
40     public AudioFileTag(File aFile) throws MusicTagException {
41        super(aFile);
42  
43        try {
44           // create the audio file object
45           this.audioFile = AudioFileIO.read(aFile);
46  
47           // initialize all tags
48           initializeTags();
49        } catch (CannotReadException ex) {
50           LOG.error(ex.getMessage(), ex);
51           throw new MusicTagException("CannotReadException opening Music File Tag." + aFile.getAbsolutePath() + "\n\n"
52                    + ex.getMessage());
53        } catch (Exception ex) {
54           LOG.error(ex.getMessage(), ex);
55           throw new MusicTagException("Unexpected exception opening Music File Tag." + aFile.getAbsolutePath() + "\n\n"
56                    + ex.getMessage());
57        }
58  
59     }
60  
61     /*
62      * (non-Javadoc)
63      * @see com.melloware.jukes.file.tag.MusicTag#getArtist()
64      */
65     public String getArtist() {
66        if (StringUtils.isBlank(this.artist)) {
67           this.artist = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstArtist(), NO_TAG).trim();
68        }
69        return this.artist;
70     }
71  
72     /*
73      * (non-Javadoc)
74      * @see com.melloware.jukes.file.tag.MusicTag#getBitRate()
75      */
76     public Long getBitRate() {
77        if (this.bitRate == null) {
78           this.bitRate = Long.valueOf(audioFile.getAudioHeader().getBitRateAsNumber());
79        }
80  
81        return this.bitRate;
82     }
83  
84     /*
85      * (non-Javadoc)
86      * @see com.melloware.jukes.file.tag.MusicTag#getComment()
87      */
88     public String getComment() {
89        if (StringUtils.isBlank(this.comment)) {
90           this.comment = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstComment(), "").trim();
91        }
92        return this.comment;
93     }
94  
95     /*
96      * (non-Javadoc)
97      * @see com.melloware.jukes.file.tag.MusicTag#getCopyrighted()
98      */
99     public String getCopyrighted() {
100       return "No";
101    }
102 
103    /*
104     * (non-Javadoc)
105     * @see com.melloware.jukes.file.tag.MusicTag#getDisc()
106     */
107    public String getDisc() {
108       if (StringUtils.isBlank(this.disc)) {
109          this.disc = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstAlbum(), NO_TAG).trim();
110       }
111       return this.disc;
112    }
113 
114    /*
115     * (non-Javadoc)
116     * @see com.melloware.jukes.file.tag.MusicTag#getEmphasis()
117     */
118    public String getEmphasis() {
119       return "None";
120    }
121 
122    /*
123     * (non-Javadoc)
124     * @see com.melloware.jukes.file.tag.MusicTag#getEncodedBy()
125     */
126    public String getEncodedBy() {
127       if (StringUtils.isBlank(this.encodedBy)) {
128          this.encodedBy = System.getProperty("application.name");
129       }
130       return this.encodedBy;
131    }
132 
133    /*
134     * (non-Javadoc)
135     * @see com.melloware.jukes.file.tag.MusicTag#getFrequency()
136     */
137    public String getFrequency() {
138       return Integer.toString(audioFile.getAudioHeader().getSampleRateAsNumber());
139 
140    }
141 
142    /*
143     * (non-Javadoc)
144     * @see com.melloware.jukes.file.tag.MusicTag#getGenre()
145     */
146    public String getGenre() {
147       if (StringUtils.isBlank(this.genre)) {
148          this.genre = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstGenre(), "Other").trim();
149       }
150       return this.genre;
151    }
152 
153    /*
154     * (non-Javadoc)
155     * @see com.melloware.jukes.file.tag.MusicTag#getHeader()
156     */
157    public Map getHeader() {
158       return header;
159    }
160 
161    /*
162     * (non-Javadoc)
163     * @see com.melloware.jukes.file.tag.MusicTag#getLayer()
164     */
165    public String getLayer() {
166       return audioFile.getAudioHeader().getEncodingType();
167    }
168 
169    /*
170     * (non-Javadoc)
171     * @see com.melloware.jukes.file.tag.MusicTag#getMode()
172     */
173    public String getMode() {
174       return audioFile.getAudioHeader().getEncodingType();
175    }
176 
177    /*
178     * (non-Javadoc)
179     * @see com.melloware.jukes.file.tag.MusicTag#getTitle()
180     */
181    public String getTitle() {
182       if (StringUtils.isBlank(this.title)) {
183 
184          String temp = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstTitle(), NO_TAG).trim();
185 
186          // if this is the max length for a tag, or it begins with "Track"
187          // try and grab by filename it may be longer
188          if ((temp.length() == 30) || (temp.equals(NO_TAG)) || (temp.startsWith("Track"))) {
189             temp = extractTitleFromFilename();
190             LOG.debug("Filename extracted");
191          }
192 
193          // return v2 tag else if empty return the v1 tag
194          this.title = StringUtils.defaultIfEmpty(temp, NO_TAG).trim();
195       }
196       return this.title;
197    }
198 
199    /*
200     * (non-Javadoc)
201     * @see com.melloware.jukes.file.tag.MusicTag#getTrack()
202     */
203    public String getTrack() {
204       if (StringUtils.isBlank(this.track)) {
205          int trackNum = 0;
206          String tracknumber = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstTrack(), "X").trim();
207          if (StringUtils.isNumeric(tracknumber)) {
208             trackNum = Integer.parseInt(tracknumber);
209          }
210 
211          // return v2 tag else if empty return the v1 tag
212          this.track = StringUtils.leftPad(String.valueOf(trackNum), 2, "0").trim();
213 
214       }
215       return this.track;
216    }
217 
218    /*
219     * (non-Javadoc)
220     * @see com.melloware.jukes.file.tag.MusicTag#getTrackLength()
221     */
222    public long getTrackLength() {
223       if (this.trackLength > 1) {
224          return this.trackLength;
225       }
226       this.trackLength = audioFile.getAudioHeader().getTrackLength();
227       return this.trackLength;
228    }
229 
230    /*
231     * (non-Javadoc)
232     * @see com.melloware.jukes.file.tag.MusicTag#getVersion()
233     */
234    public String getVersion() {
235       return audioFile.getAudioHeader().getEncodingType();
236    }
237 
238    /*
239     * (non-Javadoc)
240     * @see com.melloware.jukes.file.tag.MusicTag#getYear()
241     */
242    public String getYear() {
243       if (StringUtils.isBlank(this.year)) {
244          this.year = StringUtils.defaultIfEmpty(audioFile.getTag().getFirstYear(), CURRENT_YEAR).trim();
245       }
246       return this.year;
247    }
248 
249    /*
250     * (non-Javadoc)
251     * @see com.melloware.jukes.file.tag.MusicTag#setArtist(java.lang.String)
252     */
253    public void setArtist(String aArtist) {
254       this.artist = StringUtils.defaultIfEmpty(aArtist, NO_TAG).trim();
255       try {
256          audioFile.getTag().setArtist(this.artist);
257       } catch (FieldDataInvalidException ex) {
258          LOG.error("FieldDataInvalidException", ex);
259       }
260 
261    }
262 
263    /*
264     * (non-Javadoc)
265     * @see com.melloware.jukes.file.tag.MusicTag#setComment(java.lang.String)
266     */
267    public void setComment(String aComment) {
268       this.comment = StringUtils.defaultIfEmpty(aComment, "").trim();
269       try {
270          audioFile.getTag().setComment(this.comment);
271       } catch (FieldDataInvalidException ex) {
272          LOG.error("FieldDataInvalidException", ex);
273       }
274    }
275 
276    /*
277     * (non-Javadoc)
278     * @see com.melloware.jukes.file.tag.MusicTag#setDisc(java.lang.String)
279     */
280    public void setDisc(String aDisc) {
281       this.disc = StringUtils.defaultIfEmpty(aDisc, NO_TAG).trim();
282       try {
283          audioFile.getTag().setAlbum(this.disc);
284       } catch (FieldDataInvalidException ex) {
285          LOG.error("FieldDataInvalidException", ex);
286       }
287 
288    }
289 
290    /*
291     * (non-Javadoc)
292     * @see com.melloware.jukes.file.tag.MusicTag#setEncodedBy(java.lang.String)
293     */
294    public void setEncodedBy(String aEncodedBy) {
295       this.encodedBy = StringUtils.defaultIfEmpty(aEncodedBy, System.getProperty("application.name")).trim();
296    }
297 
298    /*
299     * (non-Javadoc)
300     * @see com.melloware.jukes.file.tag.MusicTag#setGenre(java.lang.String)
301     */
302    public void setGenre(String aGenre) {
303       this.genre = StringUtils.defaultIfEmpty(aGenre, NO_TAG).trim();
304       try {
305          audioFile.getTag().setGenre(this.genre);
306       } catch (FieldDataInvalidException ex) {
307          LOG.error("FieldDataInvalidException", ex);
308       }
309 
310    }
311 
312    /*
313     * (non-Javadoc)
314     * @see com.melloware.jukes.file.tag.MusicTag#setTitle(java.lang.String)
315     */
316    public void setTitle(String aTitle) {
317       this.title = StringUtils.defaultIfEmpty(aTitle, NO_TAG).trim();
318 
319       try {
320          audioFile.getTag().setTitle(this.title);
321       } catch (FieldDataInvalidException ex) {
322          LOG.error("FieldDataInvalidException", ex);
323       }
324    }
325 
326    /*
327     * (non-Javadoc)
328     * @see com.melloware.jukes.file.tag.MusicTag#setTrack(java.lang.String)
329     */
330    public void setTrack(String aTrack) {
331       setTrack(aTrack, 2);
332    }
333 
334    /**
335     * Sets the track.
336     * <p>
337     * @param aTrack The track to set.
338     * @param aPadding the number of 0's to pad this track with
339     */
340    public void setTrack(final String aTrack, final int aPadding) {
341       final String current = StringUtils.defaultIfEmpty(aTrack, "0").trim();
342       this.track = StringUtils.leftPad(current, aPadding, "0").trim();
343       try {
344          audioFile.getTag().setTrack(this.track);
345       } catch (FieldDataInvalidException ex) {
346          LOG.error("FieldDataInvalidException", ex);
347       }
348    }
349 
350    /*
351     * (non-Javadoc)
352     * @see com.melloware.jukes.file.tag.MusicTag#setTrackLength(long)
353     */
354    public void setTrackLength(long aTrackLength) {
355       this.trackLength = aTrackLength;
356    }
357 
358    /*
359     * (non-Javadoc)
360     * @see com.melloware.jukes.file.tag.MusicTag#setYear(java.lang.String)
361     */
362    public void setYear(String aYear) {
363       this.year = StringUtils.defaultIfEmpty(aYear, CURRENT_YEAR).trim();
364       try {
365          audioFile.getTag().setYear(this.year);
366       } catch (FieldDataInvalidException ex) {
367          LOG.error("FieldDataInvalidException", ex);
368       }
369    }
370 
371    /*
372     * (non-Javadoc)
373     * @see com.melloware.jukes.file.tag.MusicTag#isVBR()
374     */
375    public boolean isVBR() {
376       return audioFile.getAudioHeader().isVariableBitRate();
377    }
378 
379    /*
380     * (non-Javadoc)
381     * @see com.melloware.jukes.file.tag.MusicTag#removeTags()
382     */
383    public void removeTags() throws MusicTagException {
384       if (audioFile != null) {
385          try {
386             AudioFileIO.delete(audioFile);
387          } catch (Exception e) {
388             throw new MusicTagException("Error removing AudioFile tag: " + e.getMessage(), e);
389          }
390          initializeTags();
391       }
392    }
393 
394    /**
395     * Renames this Music file based on a format from prefs. The format is in
396     * aFormat and can have values %n for track number, %t for title, %a for
397     * artist, and %d for disc. Replaces any invalid characters (\\, /, :, , *, ?, ", <, >,
398     * or |) with underscores _ to prevent any errors on file systems. Examples:
399     * %n -%t = 01 - Track.mp3 %a - %d - %n - %t = Artist - Album - 01 -
400     * Track.mp3
401     * <p>
402     * @param aFormat the string format like %n -%t to rename 01 - Track.mp3
403     * @return true if renamed, false if failure
404     */
405    public boolean renameFile(String aFormat) {
406       boolean result = false;
407       try {
408          final String newFileName = createFilenameFromFormat(aFormat);
409          final File newFile = new File(newFileName);
410          // close the audioFile
411          audioFile = null;
412 
413          result = this.file.renameTo(newFile);
414          if (result) {
415             this.file = newFile;
416             this.audioFile = AudioFileIO.read(newFile);
417             initializeTags();
418          }
419       } catch (Exception ex) {
420          LOG.error("Error renaming file", ex);
421       }
422       return result;
423    }
424 
425    /*
426     * (non-Javadoc)
427     * @see com.melloware.jukes.file.tag.MusicTag#save()
428     */
429    public void save() throws MusicTagException {
430       if (audioFile != null) {
431          try {
432             audioFile.commit();
433          } catch (CannotWriteException ex) {
434             throw new MusicTagException("Error saving AudioFile tag: " + ex.getMessage());
435          }
436 
437       }
438 
439    }
440 
441    /**
442     * Initialize the tags for this audio file.
443     */
444    private void initializeTags() {
445       // initialize private variables from tags
446       this.getDisc();
447       this.getArtist();
448       this.getComment();
449       this.getGenre();
450       this.getTitle();
451       this.getTrack();
452       this.getYear();
453       this.getTrackLength();
454       this.getEncodedBy();
455    }
456 
457 }