You may have heard of a file format called MP3. It is an audio format that is small and compact and easy to share. If you don't have any MP3s, you can contact that RIAA. They seem to be pretty good at finding them. If you do have a few MP3s, you may know that some programs, like iTunes, will show you information about the MP3, like song title, artist, duration, etc. This information is stored in the MP3 file itself and is called ID3. ID3 is a format to embed information in the MP3 file itself. (For more information, see the site.) Since I have a few MP3s on my hard drive, I decided to see how hard it would be to get ColdFusion to read and parse these tags. It's been done before. Christian Cantrell released code on one of the first DRKs that did this. Since this isn't public domain though, let's start from scratch and see how hard it is.
Of course, the nice thing is that most of the work is done for us. I did a quick Google search and came across the Java ID3 Tag Library. I downloaded the JAR and copied it to $CFMX_HOME/runtime/servers/lib/. I then restarted ColdFusion. So what next? I checked the project's quick start guide and saw this Java example:
File sourceFile; MP3File mp3file = new MP3File(sourceFile);
I knew this could be translated to ColdFusion as:
<cfset mp3file = createObject("java", "xxxx")> <cfset mp3file.init(somefilepath)>
The problem was - what to use for the class name? I fumbled around a bit and found the API documentation. I looked up MP3File in the API and saw that it's path was org.farng.mp3.MP3File. I'm not sure how folks would be able to figure that out without documentation, but I was finally able to create an instance of the object using this path.
I then checked the API and looked into how it returned ID3 tag information. The code supports two versions of ID3 information, ID3v1 and ID3v2. (There are actually subversions for each of these two versions.) For a quick test, I wrote some code to examine one of my folders and grab the information from the ID3v1 tag:
<cfset dir = "g:\music\80s\"> <cfdirectory action="list" directory="#dir#" filter="*.mp3" name="music"> <cfloop query="music"> <cfoutput>filename = #name#<br></cfoutput> <cftry> <cfset mp3 = createObject("java", "org.farng.mp3.MP3File")> <cfset mp3.init(dir & name)> <cfset tag = mp3.getID3v1Tag()> <cfoutput> artist=#tag.artist#<br> album=#tag.album#<br> comment=#tag.comment#<br> genre=#tag.genre#<br> title=#tag.title#<br> year=#tag.year#<br> has v1? #mp3.hasID3v1Tag()#<br> has v2? #mp3.hasID3v2Tag()#<br> </cfoutput> <cfcatch> bad file </cfcatch> </cftry> <hr> </cfloop>
How did I know what methods and fields I could use? It all came from the API. So - not the cleanest of code, but you can see how it works. I create an instance of the MP3 code, and then fetch the ID3v1 tag information. To be safer, I should have used the convenience function, hasID3v1Tag() first. Notice the try/catch around the code. From what I could tell, there was no easy way to tell the code to check first for a valid MP3 file.
So what next? This works easily enough - but what if I switch to a different Java library? Tomorrow I'll write a ColdFusion Component and show how we can wrap this into a nicer and easier to use system. What I want to end up with is a tool that is 100% ColdFusion based. The developer using the tool should have no idea that behind the scenes I'm just using a JAR file.