Converting Your iTunes Library To Html
1. Introduction
Warning:
CCTunes has been changing. Not all of this documentation may correspond to the
way CCTunes is working right now. It will be updated in the near future to reflect
those changes.
|
iTunes is keeping track of all the information of your music library, in a proprietary
database file and does not provide any
interface to manipulate that. You have to go through AppleScript to get or set information
in it. This is sometimes nice, some people have nice websites of all sorts of AppleScripts
to do whatever they felt useful to do, but I have not found much information on how to
publish your whole library in html-format. Therefore I went to search the internet, and
found some links which set me on my way to get my own solution.
It might not be perfect, it might not even be nice, but it could do for you. Anyway, it did for me. As of
lately, I've bundled everything together in a nice little application which you can
find here.
You can see a list of similar packages at the end of this document. Some of them are
payware, some of them are freeware. All of them have advantages and disadvantages, and
you might well find that mine is not the package that best suits your needs. However, you
will find that mine comes with a full explanation of what it does. As a matter of fact, it
actually grew out of this documentation and has not had a purpose so far but illustrating
this text. That might change in the future, but as for now, it's better to still consider
it like that. If you have some success or ideas with the package, I'd be glad to hear!
2. About the XML file
The XML file resides in your home directory, at ~/Music/iTunes/iTunes Music Library.xml.
It has been described as braindead and, agreed, it does not look like one would expect an xml file
for a music library would look like. It is track based, and every track has an ID and most of the
information one would expect to find there, except for some, like the images. There does not seem to be
a logical way in which the Track IDs are assigned and they tend to change when f.i. you reencode
songs. Where one would expect the name of the tag
has information about the information contained in the tag, the XML file just has key tags followed
by value tags, like a dictionary streamed out. This is the typical plist approach of Apple, and
it's just another example of how not to use XML, imho.
When you are playing tracks in your iTunes application, iTunes seems to update both a private
proprietary database file and the xml file. The proprietary database, ~/Music/iTunes/iTunes 4
Music Library, is the master file. Whatever you change in the xml file, if the database
file is not updated, the next time you play something in iTunes, the XML file will be updated
again. Very annoying.
3. Prerequisites
Organizing The Library
First of all, it was my aim to make a nice list of all the albums I posess in my iTunes library.
I am in the ongoing process of converting my whole CD collection, some couple of hundred CDs, to
MP3, and while doing so, I try to keep a list. I used to do this by updating some spreadsheet
file in GNumeric, which is still a viable approach, but this is nicer. However, I use certain
rules to tag my MP3s:
- I don't keep track of Genres. They are never accurate anyway.
- I try to keep the Artwork of the tracks to just contain the Album cover art, not
any other artwork, like singles cover art or logos.
- I try to keep the disk numbers up to date. They are often ignored but I want albums
consisting of multiple CDs to be treated as one album.
You do not have to organize your library like I do, but just in order for all of
this to work and look nicely, I recommend this approach. I recommend this approach
anyway, I think it should be forced by law to organize your library like this ;-).
Installing the software used
In earlier versions I used perl modules like MP3::Info to
extract the images and ImageMagick command line tools to
generate the thumbnails. However, things are much simpler
now: I've made a self contained package which is downloadable
and has everything you will need.
4. Converting the XML file
Forcing the XML file to make sense
Well, we want a decent xml file to start with, not that plisty file that is not like
we would make it ourselves. Luckily there are people that helped me on the way to
do this. Searching google
gave me a nice little link, http://www.xmldatabases.org/WK/blog/1086?t=item
which explained it all. Now that was very useful. Step one finished.
Code listing 4.1: makeProperXml.xsl file makes a nicer XML file |
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xsl:version="1.0">
<xsl:template match="/">
<songlist>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="plist/dict/dict/dict"/>
</songlist>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="dict">
<song>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="key"/>
<xsl:text>
</xsl:text>
</song>
</xsl:template>
<xsl:template match="key">
<xsl:element name="{translate(text(), ' ', '_')}">
<xsl:value-of select="following-sibling::node()[1]"/>
</xsl:element>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
|
To now actually do the conversion, we use xsltproc, which is a
tool that comes with the libxml2 library. If you haven't downloaded the
package you must install it using fink or compile it from sources yourself.
To generate the nicer XML file, we execute
Code listing 4.2: xsltproc command to generate proper XML from plist file |
xsltproc --novalid makeProperXml.xsl "~/Music/iTunes/iTunes Music Library.xml" > properiTunes.xml
|
Sorting the XML file per Album
This was the next thing to do, so I started reading XSLT specs
and experimenting, and googling. In the end, it turned out
pretty easy to do, and a stylesheet was the result. I am
still struggling a bit with the fact that if I have a
compilation album, I want it to be listed as "Various
Artists". The xml value for this id3 tag is a key which is
either present or not in the iTunes xml file, instead of a
bool as one would expect. This is a bit confusing,
since I have found no way yet to check whether a node is null
or not in the XSLT spec. It's probably possible to do this in
a more elegant way, but my approach works too. So, I came up
with another XSLT file.
Code listing 4.3: makeMainXml.xsl file creates the main XML file |
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xsl:version="1.0">
<xsl:template match="songlist">
<xmlLibrary>
<xsl:for-each select="song[ not(Album = preceding-sibling::song/Album and Artist = preceding-sibling::song/Artist) ]">
<xsl:sort select="Compilation"/>
<xsl:sort select="Artist"/>
<xsl:sort select="Album"/>
<xsl:variable name="albumname" select="Album"/>
<xsl:variable name="artistname" select="Artist"/>
<xsl:variable name="albumid" select="position()"/>
<xsl:if test="$artistname!='' and $albumname!=''">
<includeXml><xsl:value-of select="$albumid"/></includeXml>
<xsl:text>
</xsl:text>
<xsl:document href="{$destinationDir}/{$albumid}.xml">
<AlbumItem>
<xsl:text>
</xsl:text>
<Artist>
<xsl:variable name="compilationval" select="count(child::Compilation)"/>
<xsl:choose>
<xsl:when test="$compilationval=1">
<xsl:text>Various Artists</xsl:text>
</xsl:when>
<xsl:when test="$compilationval=0">
<xsl:value-of select="Artist"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>????</xsl:text>
</xsl:otherwise>
</xsl:choose>
</Artist>
<xsl:text>
</xsl:text>
<Album>
<xsl:value-of select="Album"/>
</Album>
<xsl:text>
</xsl:text>
<AlbumID/>
<xsl:text>
</xsl:text>
<Picture>
<xsl:text>
</xsl:text>
<PictureURL><xsl:value-of
select="Location" /></PictureURL>
<xsl:text>
</xsl:text>
</Picture>
<xsl:text>
</xsl:text>
<TrackList>
<xsl:variable name="currentArtist" select="Artist"/>
<xsl:variable name="currentAlbum" select="Album"/>
<xsl:for-each select="parent::node()[1]/song[Album=$currentAlbum and Artist=$currentArtist]">
<xsl:sort select="Disk_Number" data-type="text"/>
<xsl:sort select="Track_Number" data-type="number"/>
<xsl:text>
</xsl:text>
<Track>
<xsl:text>
</xsl:text>
<Number><xsl:value-of select="Track_Number"/></Number>
<xsl:text>
</xsl:text>
<Name><xsl:value-of select="Name"/></Name>
<xsl:text>
</xsl:text>
<TotalTime><xsl:value-of select="Total_Time"/></TotalTime>
<xsl:text>
</xsl:text>
<DiscNumber><xsl:value-of select="Disc_Number"/></DiscNumber>
<xsl:text>
</xsl:text>
<DateAdded><xsl:value-of select="Date_Added"/></DateAdded>
<xsl:text>
</xsl:text>
<Year><xsl:value-of select="Year"/></Year>
<xsl:text>
</xsl:text>
<PlayCount><xsl:value-of select="Play_Count"/></PlayCount>
<xsl:text>
</xsl:text>
</Track>
</xsl:for-each>
<xsl:text>
</xsl:text>
</TrackList>
<xsl:text>
</xsl:text>
</AlbumItem>
</xsl:document>
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:for-each>
</xmlLibrary>
</xsl:template>
</xsl:stylesheet>
|
The main magic in this XSL file is where the preceding-sibling does it's
work to create a unique sorting on the Albums. Some other magic is where the
comments are generated to get the images out of the mp3 file. But that is
explained in the next chapter. The conversion is again done using xsltproc
just like we did before.
Code listing 4.4: Making main XML file using xsltproc |
xsltproc --novalid makeMainXml.xsl properiTunes.xml > masterXml.xml
|
5. Getting the images out of the mp3 files
The trickiest part of the job was getting the images. Since
the images are not in the XML file we need to get them out
of the mp3 files themselves. iTunes uses the correct mp3 v2
tag to store the image. Now, initially I wrote a perl
script to extract the images based on a perl module. But,
you need to install the perl modules MP3::Info and URI::URL
in order for this to work. This is not too hard to do, but
is still some effort. I could have packaged the perl
modules I guess, but I found it easier to create a little
Cocoa command line tool that does the same based on
libid3,
the library that is distributed by http://www.id3.org.
Both approaches are
still explained however.
Using perl to get the images out of the mp3 files
Warning: This section is outdated with respect to CCTunes. Read on for the
current approach.
|
A link that got me on the way was on the ever interesting
macosxhints website,
http://www.macosxhints.com/article.php?story=20030429003250559,
in which one of the comments describes almost perfectly what needs to be
done. Almost, but for the fact on how to get to open a file based on the
url. Of course, this is not hard to do, using some parsing, and I have
my "Perl in a Nutshell" book on my desktop, but getting used to this perl
thing I thought there must be a module already out there that does this
for me. Now, that's the URI::URL module we've installed, and it was
mentioned in the book.
There we have our perl script, which takes as argument a unix file path
and a filename to write the png file to. If this script does not find
the corresponding tag, it just creates a link to a nopic.png file instead
of the destination file, so that we can put in a nice icon when the image
is missing in the mp3.
Code listing 5.1: The getPicture script gets the image from the mp3 file |
#!/usr/bin/perl
no strict 'refs';
use Getopt::Long;
use IO::File;
use MP3::Info;
use URI::URL;
$url1 = new URI::URL shift;
$unixpath = $url1->unix_path();
$e = $ARGV[0];
if ( -e $e || -l $e ) {
system("/bin/rm " . $e);
}
if (my $mp3tag_id3v2 = get_mp3tag($unixpath, 2, 1)) {
my $tag = "PIC";
my $result = $mp3tag_id3v2->{$tag};
$result =~ s/^(.....).//;
if (length($result) > 0)
{
open $f, "> $e";
print $f $result;
}
else
{
system("/bin/ln -s ./nopic.png " . $e);
}
}
else
{
system("/bin/ln -s ./nopic.png " . $e);
}
|
To invoke the correct sequence of calls to this perl command, we need a little
hack. If you take a closer look at the XML file we used to sort the original
cleaned up XML file per album, you will see that we generated some output in
XML comments, which invokes the getPicture script in a way to generate
the png file we want in the images directory. So now, with a simple bash
command we can invoke the whole set of getPicture's that will generate us
the total directory of images:
Code listing 5.2: Bash command to generate directory of images |
bash-2.05a$ cat mymusic.xml | grep getPicture | /bin/bash
|
I have understood that a Microsoft implementation of the XSLT parsing implements
something like callbacks, in which you can call a script from within your
XSL file. That's a good idea, nice, but since it isn't in the XSLT specification
it is not very compatible to depend upon it. But if you do, you might want
to check that out.
Using a custom command line tool to get the image out of the mp3 file
Another approach is taken in the downloadable package however. The getPicure
command is not a perl command, but a compiled tool, based on id3v2 which already
uses the libid3 library and has a great set of functionalities, except... extracting
images.
Adapting the sources to eliminate all we don't need and adding the extra little bit
of functionality to extract the image was easy however, since we basically know
how to do this in perl already. In order to compile it you will need to have the
libid3 headers in place and have a libid3 library that you can link to. The commands
needed to compile it with the statically linked library are included in comments
in the source code.
Code listing 5.3: Source code to getPicture command line tool |
/**
* Based on id3v2 ... compile something like
*
* g++ -I/usr/local/include/ -O3 -c -o getpic.o getpic.cpp
* c++ -L/usr/local/lib/ -O3 -pedantic -Wall -framework CoreFoundation -lz -liconv
* -g -o id3v2 getpic.o ./libid3.a
*
* Part of CCTunes, distributed under the GPL.
* details at http://www.coin-c.com/CCTunes/
*/
#include <CoreFoundation/CoreFoundation.h>
#include <id3/misc_support.h>
#include <id3/tag.h>
#include "frametable.h"
#include "genre.h"
int main( int argc, char *argv[]);
int main( int argc, char *argv[])
{
CFURLRef theSourceUrl = CFURLCreateWithBytes(kCFAllocatorDefault,
(unsigned char*)argv[1],
strlen(argv[1]),
kCFStringEncodingUTF8,
NULL);
unsigned char sourceFilePath[500];
if (CFURLGetFileSystemRepresentation(theSourceUrl,true,sourceFilePath,500))
{
bool tags = false;
ID3_Tag myTag;
myTag.Link((char*)sourceFilePath, ID3TT_ID3V2);
const ID3_Frame * myFrame = 0;
const ID3_Tag myTagConstRef = myTag;
ID3_Tag::ConstIterator *Iter = myTagConstRef.CreateIterator();
for (size_t nFrames = 0; nFrames < myTag.NumFrames(); nFrames++)
{
myFrame = Iter->GetNext();
if (NULL != myFrame && myFrame->GetID() == ID3FID_PICTURE)
{
myFrame->Field(ID3FN_DATA).ToFile(argv[2]);
tags = true;
break;
}
}
if(!tags)
std::cout << (unsigned char*)argv[1] << ": No ID3 tag" << std::endl;
}
}
|
Generating Thumbnails
This might be all you need if you are on your own private server, have lots of
disk space and don't really care on how fast your collection loads in the browser.
Since I have been using this, I found that the size of the images tends to be too
big to view all of the images for all of the albums at once, so it would be
nice to generate thumbnails for the overview.
If you have a utility like GraphicConverter, which came for free with my laptop,
you can easily generate 60 by 60 thumbnails from the images by using the batch
mode to set the Max Size. Also ImageMagick
can do things like this. You will need to install it using fink or compile
it yourself, both should be easy and with a simple set of commands on the prompt
you convert all images like this:
Code listing 5.4: Generating thumbnails with ImageMagick convert |
mv images images_high
mkdir images
cd images_high; find . -type f -exec convert -resize 60x60 {} ../images/{} \;
cd -
|
However, for your ease of use, the currently downloadable package comes with a little
command line tool programmed in cocoa and based on
pdf2png by Evan Jones which does all of this for you. It simply takes an image
and draws it in an offline buffer of the specified size and saves that as a png
file. I must say however, you will see that the quality is not good. It is
the same quality you can see if you use iPhoto to look at the images you've
taken with your digital camera. Uuuugly. I must provide some feedback to Apple on that
someday.
Code listing 5.5: Little Cocoa command line tool to resize images, based on pdf2png |
// A tiny program that resizes images to PNG images with certain dimensions.
// based on pdf2png by Evan Jones, http://evanjones.ca/pdf2png.m
// modified by Kristof Van Landschoot, Coin-C to fit the purpose of resizing.
//
// gcc --std=c99 -g -o resize resize.m -framework Cocoa
//
// Written originally by Evan Jones <ejones@uwaterloo.ca> Februrary, 2004
// http://www.eng.uwaterloo.ca/~ejones/
//
// Released under the GNU Public License
#include <Cocoa/Cocoa.h>
int main( int argc, char* argv[] )
{
int destinationSize = 36; // in DPI
int page = 1;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Package all arguments as NSStrings in an NSArray
NSMutableArray* args = [NSMutableArray arrayWithCapacity: argc - 1];
for ( int i = 1; i < argc; ++ i )
{
[args addObject: [NSString stringWithCString: argv[i]] ];
}
// If we have a "--dpi" along with a corresponding argument ...
unsigned int index = NSNotFound;
if ( (index = [args indexOfObject: @"--dpi"]) != NSNotFound && index + 1 < [args count] )
{
// Parse it as an integer
destinationSize = [[args objectAtIndex: index + 1] intValue];
[args removeObjectAtIndex: index + 1];
[args removeObjectAtIndex: index];
}
if ( [args count] != 2 || [args indexOfObject: @"--help"] != NSNotFound || destinationSize <= 0 )
{
fprintf( stderr, "resizePicture [options] file\n" );
fprintf( stderr, "\t--dpi dpi\tSpecifies the destination size of the image in pixels\n" );
fprintf( stderr, "\t--help\tPrint this help message\n" );
return 1;
}
NSString* sourcePath = [args objectAtIndex: 0];
NSImage* source = [ [NSImage alloc] initWithContentsOfFile: sourcePath ];
[source setScalesWhenResized: YES];
// Tip from http://www.omnigroup.com/mailman/archive/macosx-dev/2002-February/023366.html
// Allows setCurrentPage to do anything
[source setDataRetained: YES];
if ( source == nil )
{
fprintf( stderr, "Source image '%s' could not be loaded\n", argv[1] );
return 2;
}
// The output file name
NSString* outputFilePath = [args objectAtIndex: 1];
NSSize sourceSize = [source size];
NSSize size = NSMakeSize( destinationSize, destinationSize );
[NSApplication sharedApplication];
[[NSGraphicsContext currentContext] setImageInterpolation: NSImageInterpolationHigh];
[source setSize: size];
NSRect destinationRect = NSMakeRect( 0, 0, size.width, size.height );
NSImage* image = [[NSImage alloc] initWithSize:size];
[image lockFocus];
NSEraseRect( destinationRect );
[source drawInRect: destinationRect
fromRect: destinationRect
operation: NSCompositeCopy fraction: 1.0];
NSBitmapImageRep* bitmap = [ [NSBitmapImageRep alloc]
initWithFocusedViewRect: destinationRect ];
NSData* data = [bitmap representationUsingType:NSPNGFileType properties:nil];
[bitmap release];
[[NSFileManager defaultManager]
createFileAtPath: outputFilePath
contents: data
attributes: nil ];
[image unlockFocus];
[image release];
[pool release];
}
|
6. Making nice XHTML layout
One little stage is still left, and that
is formatting the XML files so that they make nice XHTML files that we can render
in a browser. We will generate an HTML document per album that shows the bigger
image and a track listing, and have a small scrollable DIV-frame with all of the
thumbnails as an overview of the album database.
Code listing 6.1: makeFinalXHtml.xsl makes final XHTML file |
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xsl:version="1.0">
<xsl:template match="xmlLibrary">
<html>
<head>
<title>Xml Library - Exported from iTunes</title>
<meta name="GENERATOR" content="CCTunes"/>
<meta name="DESCRIPTION" content="Music Library published with CCTunes. Find out all about CCTunes at
http://www.coin-c.com/CCTunes/"/>
<link rel="stylesheet" href="default.css"/>
</head>
<body bgcolor="#000000"
style="background-color: rgb(0, 0, 0); color: rgb(153, 153, 153);">
<xsl:variable name="librarywidth" select="count(AlbumItem) * 64"/>
<table style="width: 100%; height: 100%; text-align: left; margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="height: 100px; vertical-align: top;" class="albumTitle"><br/>
CCTunes Exported Library.
</td>
<td style="width: 360px; height: 100px;">
<div style="position: relative; left: 0px; width: 355px; top: 0px; height: 90px; overflow: auto; background-color: rgb(0, 0, 0);">
<div style="position: relative; top: 0px; left: 0px; height: 60px; width: {$librarywidth}px;">
<xsl:for-each select="AlbumItem">
<xsl:sort select="Artist"/>
<xsl:sort select="Album"/>
<xsl:variable name="albumname" select="Album"/>
<xsl:variable name="artistname" select="Artist"/>
<xsl:variable name="albumid" select="AlbumID"/>
<xsl:if test="$artistname!='' and $albumname!=''">
<xsl:text disable-output-escaping="yes"><a href="</xsl:text>
<xsl:value-of select="$albumid"/>
<xsl:text disable-output-escaping="yes">.html" target="inlineframe">
<IMG WIDTH="60" HEIGHT="60" border="0"
SRC="</xsl:text>
<xsl:value-of select="AlbumID"/>
<xsl:text disable-output-escaping="yes">-low.png"</xsl:text>
<xsl:text>ALT="</xsl:text>
<xsl:value-of select="$artistname"/><xsl:text> -- </xsl:text><xsl:value-of select="$albumname"/>
<xsl:text disable-output-escaping="yes">" TITLE="</xsl:text>
<xsl:value-of select="$artistname"/><xsl:text> -- </xsl:text><xsl:value-of select="$albumname"/>
<xsl:text disable-output-escaping="yes">"/></xsl:text>
<xsl:text disable-output-escaping="yes"></a></xsl:text>
</xsl:if>
</xsl:for-each>
</div>
</div>
</td>
</tr>
<tr>
<td colspan="2"> <iframe height="100%" width="100%"
scrolling="auto" src="" frameborder="1"
name="inlineframe"></iframe> <br/>
</td>
</tr>
<tr>
<td align="right" height="15" colspan="2" class="cctunesLink">
Published Using
<a class="cctunesLink" href="http://www.coin-c.com/CCTunes/">CCTunes</a>
</td>
</tr>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
|
7. One Simple Package to Rule Them All
To have an easy to use interface, I've linked everything together in a package. To create
a package that triggers a bash script that executes everything we use a little AppleScript.
This AppleScript we compile as a package and then we add the bash script and all the
binaries in it.
To provide for some interactivity with the user, a nice little application is used that
gives a wide variety of dialogs to be called from the command line, CocoaDialog.
The final bash script that does everything is not so simple anymore as it used to be,
but I think it's still readable enough to include here:
Code listing 7.1: generate.sh bash script to do it all |
#!/bin/bash
if [ "${1}" ]; then
musicXmlFile="$1"
else
musicXmlFile=~/Music/iTunes/iTunes\ Music\ Library.xml
fi
export set WORKINGDIR=`dirname "$0"`
export set destinationDir=$2
export set destinationDirUrl=`"${WORKINGDIR}/urlencode.sh" "$2"`
"${WORKINGDIR}/xml" tr "${WORKINGDIR}/../xml/makeProperXml.xsl" \
"$musicXmlFile" \
> /tmp/mymusic$$.xml
"${WORKINGDIR}/xml" tr "${WORKINGDIR}/../xml/makeMainXml.xsl" \
-s "destinationDir=$destinationDirUrl" \
/tmp/mymusic$$.xml > /tmp/mymusic2$$.xml
OLDIDS=`"${WORKINGDIR}/xml" sel -T -t -m xmlLibrary/includeXml -v "concat(node(),' ')" /tmp/mymusic2$$.xml`
echo "<?xml version=\"1.0\"?>" > "${destinationDir}/mymusic.xml"
echo "<xmlLibrary xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> "${destinationDir}/mymusic.xml"
for oldit in $OLDIDS; do
file="${oldit}.xml"
PICTUREURL=`"${WORKINGDIR}/../bin/xml" sel -T -t -v /AlbumItem/Picture/PictureURL "${destinationDir}/${file}"`
NEWID=`"${WORKINGDIR}/createId.command" "${destinationDir}/$file"`
"${WORKINGDIR}/getPicture" "${PICTUREURL}" "${destinationDir}/${NEWID}-high"
"${WORKINGDIR}/resizePicture" --dpi 60 "${destinationDir}/${NEWID}-high" "${destinationDir}/${NEWID}-low.png"
"${WORKINGDIR}/xml" ed -u /AlbumItem/AlbumID -v "$NEWID" "${destinationDir}/$file" > "${destinationDir}/${NEWID}.xml"
rm -f "${destinationDir}/$file"
"${WORKINGDIR}/xml" tr --xinclude "${WORKINGDIR}/../../Resources/English.lproj/makeFinalXHtmlDetail.xsl" \
"${destinationDir}/${NEWID}.xml" > "${destinationDir}/${NEWID}.html"
echo "<xi:include href=\"${NEWID}.xml\" />" >> "${destinationDir}/mymusic.xml"
done
echo "</xmlLibrary>" >> "${destinationDir}/mymusic.xml"
# for every xml file, apply stylesheet to obtain corresponding html file
# for mymusic.xml file, apply main stylesheet to obtain index file
"${WORKINGDIR}/xml" tr --xinclude "${WORKINGDIR}/../../Resources/English.lproj/makeFinalXHtml.xsl" \
"${destinationDir}/mymusic.xml" > "${destinationDir}/mymusic.html"
cp "${WORKINGDIR}/../../Resources/default.css" "${destinationDir}/default.css"
open "${destinationDir}/mymusic.html"
rm /tmp/mymusic$$.xml
rm /tmp/mymusic2$$.xml
|
8. Conclusion
So, if you want to do a quick XHTML list of your mp3 collection, you need not do
much. If you want, there is a package that
you can download, and hopefully with the explanations given here you
are even able to adapt everything to your needs.
9. Future Wishlist and Todo
In the beginning I was doing this to get to know something about XSLT and about
perl scripting etc... However, things seem to be evolving towards Cocoa and I think
in the near future I will try and make everything simply one Cocoa application. The
basis for the whole application are here, I don't think much will change about that,
at least not in the forseeable future.
A short list of the things I want to do however:
- A way to show the play count, which is usually a good measure on how much I like
an album I bought. Related to this, a way to merge the xml files, since I listen
to albums both at work as home.
- You still need the iTunes xml file. It would be nice if it could take extra information
from this XML file, but get the main information from the mp3 files itself.
- Nicer layout of the html by means of css.
- A speedup with Muenchian Sorting
- One XSL template to do the whole transformation.
- Make everything into a nice little Cocoa Application with a nice GUI.
- Probably even more...
And a short list of the things I need to do:
- Update documentation to reflect the current state of CCTunes.
- Make sure versioning is in place.
- Provide older versions online.
10. Resources
Downloading all the scripts
These scripts can be found in the package of the application at
http://www.coin-c.com/downloads/CCTunes.dmg.gz.
Surely you could copy and paste everything from this file, but downloading and untarring is a
bit safer, since sometimes the whitespace is important.
Resources used in this article
Other Resources
|
Name
|
Link
|
Description
|
|
mp3report
|
http://mp3report.sourceforge.net/
|
Suppose you have no iTunes XML file, mp3report could be used to generate one. It runs over
your collection of mp3 files and does about the same as all these scripts.
|
|
AudioHiJack
|
http://www.rogueamoeba.com/audiohijack/
|
Very good application to record online radio with. Shareware at a nice
price.
|
|
Doug's AppleScript for iTunes
|
http://www.malcolmadams.com/itunes/index.php
|
Ultimate resource for everything AppleScriptable in iTunes.
|
|
ImageMagick
|
http://www.imagemagick.org/
|
Whatever you need to convert images if GraphicConverter does not seem
to do the trick. Available in a weird license, which I think is as free
as possible for an image manipulation program that supports a wide range
of formats like this one.
|
|
Clutter
|
http://www.sprote.com/clutter/
|
Nice application to get the Artwork in your iTunes. It has not been updated
for a while however.
|
|
iCatalog
|
http://www.kavasoft.com/iTunesCatalog/
|
Shareware application that does the same as the scripts in this article. Except,
without paying you only get albums from artists starting with letters A-E. Easy
workaround: put an A-E in front of all your artists or so? Naaah, just pay or
use the scripts here.
|
|
iPlaylist
|
http://iplaylist.knownworld.net/index.html
|
Donationware application to publicize your library on a web page that looks like
you're in iTunes itself. Does not extract images at all.
|
|
itunes2html
|
http://disobey.com/detergent/code/itunes2html.txt
|
Somebody took the perl script approach for converting iTunes playlists to HTML.
iPlaylist is based on this.
|
Document Layout
This document was made with the excellent guide style sheet also
used to make the gentoo
documentation, with some minor adaptations done by myself.
The XSLT file to generate all of this, is at http://dev.gentoo.org/~swift/local/guide.xsl.
This work is licensed under a Creative Commons License.
|
|
 |
|
Updated $LastChangedDate: 2004-11-18 23:41:16 +0100 (Thu, 18 Nov 2004) $ |
 |
Kristof Van Landschoot
Author
|
 |
|
Summary:
This is a short description of the things I did to get my library published from the XML file
that iTunes keeps to a simple HTML file, album based.
|
 |
| Multi-page Version |
|