1 package com.melloware.jukes.file.tag;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.Iterator;
6 import java.util.List;
7 import java.util.Locale;
8 import java.util.Map;
9
10 import javax.sound.sampled.AudioFileFormat;
11 import javax.sound.sampled.AudioSystem;
12 import javax.sound.sampled.UnsupportedAudioFileException;
13
14 import org.apache.commons.io.FilenameUtils;
15 import org.apache.commons.lang.StringUtils;
16 import org.apache.commons.lang.builder.CompareToBuilder;
17 import org.apache.commons.lang.builder.EqualsBuilder;
18 import org.apache.commons.lang.builder.HashCodeBuilder;
19 import org.apache.commons.lang.builder.ToStringBuilder;
20 import org.apache.commons.lang.builder.ToStringStyle;
21 import org.apache.commons.lang.math.NumberUtils;
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.jaudiotagger.tag.id3.valuepair.V2GenreTypes;
25 import org.jaudiotagger.tag.reference.GenreTypes;
26 import org.tritonus.share.sampled.file.TAudioFileFormat;
27
28 import com.melloware.jukes.exception.MusicTagException;
29 import com.melloware.jukes.file.FileUtil;
30 import com.melloware.jukes.gui.tool.Resources;
31 import com.melloware.jukes.gui.tool.Settings;
32 import com.melloware.jukes.util.TimeSpan;
33
34
35
36
37
38
39
40
41 @SuppressWarnings("PMD")
42 abstract public class MusicTag implements ITag, Comparable {
43
44 private static final Log LOG = LogFactory.getLog(MusicTag.class);
45 public static final String NO_TAG = "[notag]";
46
47
48
49
50 public static final String CURRENT_YEAR = "9999";
51 public static final String DEFAULT_FILE_FORMAT = "%n - %t";
52
53 protected File file;
54 protected Long bitRate = null;
55 protected long trackLength = 1;
56 protected Map header;
57 protected String artist = null;
58 protected String comment = null;
59 protected String disc = null;
60 protected String encodedBy = null;
61 protected String genre = null;
62 protected String title = null;
63 protected String track = null;
64 protected String year = null;
65
66
67
68 public static Settings settings = null;
69
70
71
72
73 public static void setSettings(Settings aSettings) {
74 settings = aSettings;
75 }
76
77
78
79
80
81
82
83 public MusicTag(File aFile) throws MusicTagException {
84 super();
85 if (aFile == null) {
86 throw new MusicTagException("File is not valid.");
87 }
88 this.file = aFile;
89
90 try {
91
92 if (!aFile.canWrite()) {
93 aFile.setReadable(true, false);
94 }
95
96
97 final AudioFileFormat format = AudioSystem.getAudioFileFormat(aFile);
98 if (format instanceof TAudioFileFormat) {
99
100 final Map props = ((TAudioFileFormat) format).properties();
101
102 this.header = FileUtil.deepCopy(props);
103 } else {
104 this.header = null;
105 }
106 } catch (UnsupportedAudioFileException ex) {
107 LOG.error(ex.getMessage(), ex);
108 throw new MusicTagException(Resources.getString("messages.UnsupportedAudioFileException")
109 + aFile.getAbsolutePath() + "\n\n" + ex.getMessage());
110 } catch (IOException ex) {
111 LOG.error(ex.getMessage(), ex);
112 throw new MusicTagException(Resources.getString("messages.IOExceptionMusicFileTag") + aFile.getAbsolutePath()
113 + "\n\n" + ex.getMessage());
114 } catch (Exception ex) {
115 LOG.error(ex.getMessage(), ex);
116 throw new MusicTagException(Resources.getString("messages.ErrorMusicFileTag") + aFile.getAbsolutePath()
117 + "\n\n" + ex.getMessage());
118 }
119 }
120
121
122
123
124
125
126 abstract public String getArtist();
127
128
129
130
131
132
133 abstract public Long getBitRate();
134
135
136
137
138
139
140 abstract public String getComment();
141
142
143
144
145
146 abstract public String getCopyrighted();
147
148
149
150
151
152
153 abstract public String getDisc();
154
155
156
157
158
159 abstract public String getEmphasis();
160
161
162
163
164
165
166 abstract public String getEncodedBy();
167
168
169
170
171
172 abstract public String getFrequency();
173
174
175
176
177
178
179 abstract public String getGenre();
180
181
182
183
184
185
186 abstract public Map getHeader();
187
188
189
190
191
192 abstract public String getLayer();
193
194
195
196
197
198 abstract public String getMode();
199
200
201
202
203
204
205 abstract public String getTitle();
206
207
208
209
210
211
212 abstract public String getTrack();
213
214
215
216
217
218
219 abstract public long getTrackLength();
220
221
222
223
224
225 abstract public String getVersion();
226
227
228
229
230
231
232 abstract public String getYear();
233
234
235
236
237
238
239 abstract public void setArtist(String aArtist);
240
241
242
243
244
245
246 abstract public void setComment(String aComment);
247
248
249
250
251
252
253 abstract public void setDisc(String aDisc);
254
255
256
257
258
259
260 abstract public void setEncodedBy(String aEncodedBy);
261
262
263
264
265
266
267 abstract public void setGenre(String aGenre);
268
269
270
271
272
273
274 abstract public void setTitle(String aTitle);
275
276
277
278
279
280
281 abstract public void setTrack(String aTrack);
282
283
284
285
286
287
288
289 abstract public void setTrack(String track, int padding);
290
291
292
293
294
295
296 abstract public void setTrackLength(long aTrackLength);
297
298
299
300
301
302
303 abstract public void setYear(String aYear);
304
305
306
307
308
309 abstract public boolean isVBR();
310
311
312
313
314
315
316 abstract public void removeTags() throws MusicTagException;
317
318
319
320
321
322
323
324
325
326
327
328
329 abstract public boolean renameFile(String aFormat);
330
331
332
333
334
335
336 abstract public void save() throws MusicTagException;
337
338
339
340
341
342
343 public static List getGenreTypes() {
344 return V2GenreTypes.getInstanceOf().getAlphabeticalValueList();
345 }
346
347
348
349
350
351
352 public static String getStandardGenreType(int genreNumber) {
353 return GenreTypes.getInstanceOf().getValueForId(genreNumber).toString();
354 }
355
356
357
358
359
360
361 public String getAbsolutePath() {
362 return this.getFile().getAbsolutePath();
363 }
364
365
366
367
368
369 public String getBitRateAsString() {
370 String rate = "0 ";
371 if (isVBR()) {
372 rate = "VBR ~" + getBitRate().toString();
373 } else {
374 rate = getBitRate().toString();
375 }
376
377 return rate + " kbps";
378 }
379
380
381
382
383
384
385 public File getFile() {
386 return this.file;
387 }
388
389
390
391
392
393
394 public String getHeaderInfo() {
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413 final StringBuffer buffer = new StringBuffer();
414 if (header != null) {
415 final Iterator it = header.keySet().iterator();
416 while (it.hasNext()) {
417 final Object key = it.next();
418 final Object value = header.get(key);
419 buffer.append(key);
420 buffer.append(" = ");
421 buffer.append(value);
422 }
423 }
424 return buffer.toString();
425 }
426
427
428
429
430
431
432 public String getHeaderValue(final String aKey) {
433 return ((String) header.get(aKey));
434 }
435
436
437
438
439
440
441 public String getTrackLengthAsString() {
442 return new TimeSpan(getTrackLength() * 1000).getMusicDuration();
443 }
444
445
446
447
448 @Override
449 public boolean equals(Object obj) {
450 if (!(obj instanceof MusicTag)) {
451 return false;
452 }
453 if (this == obj) {
454 return true;
455 }
456 final MusicTag rhs = (MusicTag) obj;
457 final EqualsBuilder builder = new EqualsBuilder();
458 builder.append(artist, rhs.artist);
459 builder.append(disc, rhs.disc);
460 builder.append(title, rhs.title);
461 builder.append(year, rhs.year);
462 builder.append(genre, rhs.genre);
463
464 return builder.isEquals();
465 }
466
467
468
469
470
471
472
473
474
475
476 public String extractTitleFromFilename() {
477 String title = "";
478
479
480 final String filename = FilenameUtils.getBaseName(file.getAbsolutePath());
481
482
483 final String[] tokens = StringUtils.split(filename);
484
485
486 for (int i = tokens.length - 1; i >= 0; i--) {
487 final String token = tokens[i];
488
489
490 if (StringUtils.equalsIgnoreCase(token, "-")) {
491 continue;
492 }
493
494
495 if ((StringUtils.isNumericSpace(token)) && (NumberUtils.toInt(token) == NumberUtils.toInt(this.getTrack()))) {
496 break;
497 }
498
499
500 title = token + " " + title;
501 }
502
503
504 if (StringUtils.isBlank(title)) {
505 title = filename;
506 }
507
508 return title;
509 }
510
511
512
513
514
515
516 public boolean fileExists() {
517 return this.file.exists();
518 }
519
520
521
522
523 @Override
524 public int hashCode() {
525 return HashCodeBuilder.reflectionHashCode(this);
526 }
527
528
529
530
531
532
533
534 public boolean renameFile() {
535 return renameFile(DEFAULT_FILE_FORMAT);
536 }
537
538
539
540
541 public void synchronize() {
542 this.setDisc(this.getDisc());
543 this.setArtist(this.getArtist());
544 this.setComment(this.getComment());
545 this.setGenre(this.getGenre());
546 this.setTitle(this.getTitle());
547 this.setTrack(this.getTrack());
548 this.setYear(this.getYear());
549 this.setTrackLength(this.getTrackLength());
550 this.setEncodedBy(this.getEncodedBy());
551 }
552
553
554
555
556 @Override
557 public int compareTo(Object o) {
558 MusicTag myClass = (MusicTag) o;
559 return new CompareToBuilder().append(this.track, myClass.track).append(this.title, myClass.title).toComparison();
560 }
561
562
563
564
565 @Override
566 public String toString() {
567 final ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE);
568 builder.append("artist", artist);
569 builder.append("disc", disc);
570 builder.append("title", title);
571 builder.append("track", track);
572 builder.append("genre", genre);
573 builder.append("year", year);
574 builder.append("comment", comment);
575 builder.append("length", trackLength);
576
577 return builder.toString();
578 }
579
580
581
582
583
584
585
586 protected String createFilenameFromFormat(String aFormat) {
587 final String oldFileName = this.file.getAbsolutePath();
588 final String directory = FilenameUtils.getFullPath(oldFileName);
589 final String extension = FilenameUtils.getExtension(oldFileName.toLowerCase(Locale.US));
590 String newFileName = aFormat;
591 newFileName = StringUtils.replace(newFileName, "%n", getTrack());
592 newFileName = StringUtils.replace(newFileName, "%t", getTitle());
593 newFileName = StringUtils.replace(newFileName, "%a", getArtist());
594 newFileName = StringUtils.replace(newFileName, "%d", getDisc());
595 newFileName = StringUtils.replace(newFileName, "%N", getTrack().toUpperCase());
596 newFileName = StringUtils.replace(newFileName, "%T", getTitle().toUpperCase());
597 newFileName = StringUtils.replace(newFileName, "%A", getArtist().toUpperCase());
598 newFileName = StringUtils.replace(newFileName, "%D", getDisc().toUpperCase());
599 newFileName = FileUtil.correctFileName(newFileName);
600 newFileName = directory + newFileName + "." + extension;
601 if (LOG.isDebugEnabled()) {
602 LOG.debug("Renaming: '" + oldFileName + "' to '" + newFileName + "'");
603 }
604 return newFileName;
605 }
606
607 }