1 | package org.farng.mp3; |
2 | |
3 | import org.farng.mp3.id3.AbstractID3v2; |
4 | import org.farng.mp3.id3.AbstractID3v2Frame; |
5 | import org.farng.mp3.id3.ID3v2_4; |
6 | |
7 | import java.io.IOException; |
8 | import java.io.RandomAccessFile; |
9 | import java.util.Iterator; |
10 | |
11 | /** |
12 | * <h2>Introduction to tags</h2> There are three types of tags found in an MP3 file found in this order: <ol> |
13 | * <li>ID3v2</li> <li><i><MP3 Data></i><mp3 data=""></mp3></li> <li>Lyrics3</li> <li>ID3v1</li> </ol> In addition, |
14 | * there are different versions for each tag: <ol> <li>ID3v2 <ul> <li>ID3v2.2 </li> <li>ID3v2.3 </li> <li>ID3v2.4 </li> |
15 | * </ul> </li> <li>Lyrics3 <ul> <li>Lyrics3v1 </li> <li>Lyrics3v2 </li> </ul> </li> <li>ID3v1 <ul> <li>ID3v1.0 </li> |
16 | * <li>ID3v1.1 </li> </ul> </li> </ol> |
17 | * <p/> |
18 | * <h2>Compiling:</h2> If you have ant, there is a build.xml. Type "ant help" for build options.<BR> If you get from |
19 | * CVS, you can use IntelliJ and read jid3lib.ipr<br> |
20 | * <p/> |
21 | * <h2>Reading:<br> </h2> |
22 | * <pre> |
23 | * File sourceFile; |
24 | * MP3File mp3file = new MP3File(sourceFile); |
25 | * </pre> |
26 | * You can also read specific tags: |
27 | * <pre> |
28 | * ID3v1_1 tag = new ID3v1_1(sourceFile); |
29 | * ID3v1 tag = new ID3v1(sourceFile); |
30 | * ID3v2_4 tag = new ID3v2_4(sourceFile); |
31 | * ID3v2_3 tag = new ID3v2_3(sourceFile); |
32 | * ID3v2_2 tag = new ID3v2_2(sourceFile); |
33 | * Lyrics3v2 tag = new Lyrics3v2(sourceFile); |
34 | * Lyrics3v1 tag = new Lyrics3v1(sourceFile); |
35 | * </pre> |
36 | * <p/> |
37 | * <h2>Creating:</h2> |
38 | * <pre> |
39 | * MP3File mp3file = new MP3File(); |
40 | * TagOptionSingleton.getInstance().setDefaultSaveMode(TagConstant.MP3_FILE_SAVE_OVERWRITE); |
41 | * <p/> |
42 | * // setup id3v1 |
43 | * id3v1.setAlbum("albumTitle"); |
44 | * <p/> |
45 | * // setup id3v2 |
46 | * AbstractID3v2Frame frame; |
47 | * AbstractID3v2FrameBody frameBody; |
48 | * frameBody = new FrameBodyTALB((byte) 0, "albumTitle"); |
49 | * frame = new ID3v2_4Frame(frameBody); |
50 | * id3v2.setFrame(frame); |
51 | * <p/> |
52 | * // setup lyrics3v2 |
53 | * Lyrics3v2Field field; |
54 | * AbstractLyrics3v2FieldBody fieldBody; |
55 | * fieldBody = new FieldBodyEAL("albumTitle"); |
56 | * field = new Lyrics3v2Field(fieldBody); |
57 | * lyrics3.setField(field); |
58 | * <p/> |
59 | * // setup filename tag |
60 | * frameBody = new FrameBodyTALB((byte) 0, "albumTitle"); |
61 | * frame = new ID3v2_4Frame(frameBody); |
62 | * filenameId3.setFrame(frame); |
63 | * TagOptionSingleton.getInstance().setFilenameTagSave(true); |
64 | * </pre> |
65 | * Things to note: <ul> <li>The default save mode is "write but do not delete." This means each field in the object will |
66 | * be saved, but existing fields in the file on disk will not be deleted. The other two are "only append" or "delete and |
67 | * write from scratch."</li> </ul> |
68 | * <p/> |
69 | * <h2>Editing Part 1:</h2> |
70 | * <p/> |
71 | * There are convience methods defined in AbstractMP3Tag to edit common data fields. Not all tags have all fields listed |
72 | * here. |
73 | * <p/> |
74 | * <pre> |
75 | * public abstract String getSongTitle(); |
76 | * public abstract String getLeadArtist(); |
77 | * public abstract String getAlbumTitle(); |
78 | * public abstract String getYearReleased(); |
79 | * public abstract String getSongComment(); |
80 | * public abstract String getSongGenre(); |
81 | * public abstract String getTrackNumberOnAlbum(); |
82 | * public abstract String getSongLyric(); |
83 | * public abstract String getAuthorComposer(); |
84 | * public abstract void setSongTitle(String songTitle); |
85 | * public abstract void setLeadArtist(String leadArtist); |
86 | * public abstract void setAlbumTitle(String albumTitle); |
87 | * public abstract void setYearReleased(String yearReleased); |
88 | * public abstract void setSongComment(String songComment); |
89 | * public abstract void setSongGenre(String songGenre); |
90 | * public abstract void setTrackNumberOnAlbum(String trackNumberOnAlbum); |
91 | * public abstract void setSongLyric(String songLyrics); |
92 | * public abstract void setAuthorComposer(String authorComposer); |
93 | * </pre> |
94 | * <p/> |
95 | * <h2>Editing Part 2:</h2> If the field you want is not listed above, you can use these methods. |
96 | * <pre> |
97 | * id3v1 = mp3file.getID3v1Tag(); |
98 | * id3v2 = mp3file.getID3v2Tag(); |
99 | * lyrics3 = mp3file.getLyrics3Tag(); |
100 | * </pre> |
101 | * ID3v1 tags have fixed fields and use accessor methods to change it's properties. <p>ID3v2 tags have multiple |
102 | * <i>frames</i>. Use this to set the title of the tag.</p> |
103 | * <pre> |
104 | * frame = id3v2.getFrame("TIT2"); |
105 | * ((FrameBodyTIT2) frame.getBody()).setText("New Title"); |
106 | * </pre> |
107 | * <p/> |
108 | * <p>Lyrics3 tags have multiple <i>fields</i>. Use this to set the title of the tag.</p> |
109 | * <pre> |
110 | * field = lyrics3.getField("ETT"); |
111 | * ((FieldBodyETT) field.getBody()).setTitle("New Title"); |
112 | * </pre> |
113 | * <p/> |
114 | * <h2>Writing: </h2> |
115 | * <pre> |
116 | * mp3file.save(); |
117 | * </pre> |
118 | * You can also save each individual tag through each tags' save() method.<br> <br> |
119 | * |
120 | * @author Eric Farng |
121 | * @version $Revision: 1.4 $ |
122 | */ |
123 | public abstract class AbstractMP3Tag extends AbstractMP3FileItem { |
124 | |
125 | /** |
126 | * Creates a new AbstractMP3Tag object. |
127 | */ |
128 | protected AbstractMP3Tag() { |
129 | super(); |
130 | } |
131 | |
132 | /** |
133 | * Creates a new AbstractMP3Tag object. |
134 | */ |
135 | protected AbstractMP3Tag(final AbstractMP3Tag copyObject) { |
136 | super(copyObject); |
137 | } |
138 | |
139 | /** |
140 | * Appends this tag to the given file. Append means any information this tag contains will be added to the file's |
141 | * corresponding tag, but it will not replace any fields that the file already has. If the file does not have this |
142 | * specific tag, a new one will be created. |
143 | * |
144 | * @param file MP3 file to append to. |
145 | * |
146 | * @throws IOException on any I/O error |
147 | * @throws TagException on any exception generated by this library. |
148 | */ |
149 | public abstract void append(RandomAccessFile file) throws IOException, TagException; |
150 | |
151 | /** |
152 | * removes the specific tag the easiest way. <BR> ID3v1 - cuts the length of the tag <BR> lyrics3 -cuts the length |
153 | * of the tag, then writes the id3v1 tag if it existed <BR> id3v2 - just overwrites the ID3 tag indicator at the |
154 | * start of the tag <BR> |
155 | * |
156 | * @param file MP3 file to append to. |
157 | * |
158 | * @throws IOException on any I/O error |
159 | */ |
160 | public abstract void delete(RandomAccessFile file) throws IOException; |
161 | |
162 | /** |
163 | * Overwrites this tag to the given file. Overwrite means any information this tag contains will replace any |
164 | * existing fields in the file's corresponding tag. If the file does not have this specific tag, a new one will be |
165 | * created. |
166 | * |
167 | * @param file MP3 file to overwrite |
168 | * |
169 | * @throws IOException on any I/O error |
170 | * @throws TagException on any exception generated by this library. |
171 | */ |
172 | public abstract void overwrite(RandomAccessFile file) throws IOException, TagException; |
173 | |
174 | /** |
175 | * Looks for this tag. returns true if found. If found, the file pointer is right after the tag start indicator i.e. |
176 | * "TAG" "LYRICSBEGIN" "ID3" + 2 |
177 | * |
178 | * @param file MP3 file to overwrite |
179 | * |
180 | * @return returns true if found, false otherwise. |
181 | * |
182 | * @throws IOException on any I/O error |
183 | */ |
184 | public abstract boolean seek(RandomAccessFile file) throws IOException; |
185 | |
186 | /** |
187 | * Returns true if this tag is a subset of the argument. Both tags are converted into ID3v2_4 tags, and then |
188 | * compared frame by frame. |
189 | * |
190 | * @param abstractMP3Tag superset tag |
191 | * |
192 | * @return true if this tag is a subset of the argument |
193 | */ |
194 | public boolean isSubsetOf(final AbstractMP3Tag abstractMP3Tag) { |
195 | final AbstractID3v2 subset = new ID3v2_4(this); |
196 | final AbstractID3v2 superset = new ID3v2_4(abstractMP3Tag); |
197 | final Iterator iterator = subset.iterator(); |
198 | while (iterator.hasNext()) { |
199 | final AbstractID3v2Frame subsetFrame = (AbstractID3v2Frame) iterator.next(); |
200 | final String identifier = subsetFrame.getIdentifier(); |
201 | final AbstractID3v2Frame supersetFrame = superset.getFrame(identifier); |
202 | if (supersetFrame == null) { |
203 | return false; |
204 | } |
205 | if (!subsetFrame.isSubsetOf(supersetFrame)) { |
206 | return false; |
207 | } |
208 | } |
209 | return true; |
210 | } |
211 | |
212 | /** |
213 | * This method does nothing, but is called by subclasses for completeness |
214 | * |
215 | * @param abstractMP3Tag tag to overwrite |
216 | */ |
217 | public abstract void append(AbstractMP3Tag abstractMP3Tag); |
218 | |
219 | /** |
220 | * Determines whether another object is equal to this tag. It just compares if they are the same class, then calls |
221 | * <code>super.equals(object)</code>. |
222 | */ |
223 | public boolean equals(final Object obj) { |
224 | return obj instanceof AbstractMP3Tag && super.equals(obj); |
225 | } |
226 | |
227 | public abstract Iterator iterator(); |
228 | |
229 | /** |
230 | * This method does nothing, but is called by subclasses for completeness |
231 | * |
232 | * @param abstractMP3Tag tag to overwrite |
233 | */ |
234 | public abstract void overwrite(AbstractMP3Tag abstractMP3Tag); |
235 | |
236 | /** |
237 | * This method does nothing, but is called by subclasses for completeness |
238 | * |
239 | * @param abstractMP3Tag tag to write to |
240 | */ |
241 | public abstract void write(AbstractMP3Tag abstractMP3Tag); |
242 | |
243 | public abstract String getSongTitle(); |
244 | |
245 | public abstract String getLeadArtist(); |
246 | |
247 | public abstract String getAlbumTitle(); |
248 | |
249 | public abstract String getYearReleased(); |
250 | |
251 | public abstract String getSongComment(); |
252 | |
253 | public abstract String getSongGenre(); |
254 | |
255 | public abstract String getTrackNumberOnAlbum(); |
256 | |
257 | public abstract String getSongLyric(); |
258 | |
259 | public abstract String getAuthorComposer(); |
260 | |
261 | public abstract void setSongTitle(String songTitle); |
262 | |
263 | public abstract void setLeadArtist(String leadArtist); |
264 | |
265 | public abstract void setAlbumTitle(String albumTitle); |
266 | |
267 | public abstract void setYearReleased(String yearReleased); |
268 | |
269 | public abstract void setSongComment(String songComment); |
270 | |
271 | public abstract void setSongGenre(String songGenre); |
272 | |
273 | public abstract void setTrackNumberOnAlbum(String trackNumberOnAlbum); |
274 | |
275 | public abstract void setSongLyric(String songLyrics); |
276 | |
277 | public abstract void setAuthorComposer(String authorComposer); |
278 | } |