macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Unify and Synchronize Your iTunes Libraries
Pages: 1, 2

A Simple Script to Get You Going

The following Python script computes the differences between two iTunes Music Library.xml files. Copy it into a file named "diffMusicLibs.py" or download it here; invoke it from a terminal by typing python diffMusicLibs.py <file2> <file1>.

import re
import sys
from sets import Set

#removes the part of the string up until the actual artist name.
#returns string of form 'artist/album/filename'
def parseOutSong(s):
    lst = s.split('/')
    return '%s/%s/%s' % (lst[-3],lst[-2],lst[-1])

def main():
    #the pattern to match in 'iTunes Music Library.xml'. 
    pattern='\<key\>Location\<\/key\>\<string\>file:\/\/localhost\/Users\/(.*)\/Music\/iTunes\/iTunes%20Music\/(.*)\<\/string\>'

    #store the contents of each iTunes library given on the command line to a variable
    lib0 = open(sys.argv[1], 'r').read()
    lib1 = open(sys.argv[2], 'r').read()

    #populate lists that contain the songs in each library
    lib_files0 = []
    m = re.search(pattern, lib0)
    while m != None:
        lib_files0.append(parseOutSong(m.group(2)))
        lib0 = lib0[m.span()[1]:]
        m = re.search(pattern, lib0)

    lib_files1 = []
    m = re.search(pattern, lib1)
    while m != None:
        lib_files1.append(parseOutSong(m.group(2)))
        lib1 = lib1[m.span()[1]:]
        m = re.search(pattern, lib1)

    #turn the lists into sets
    set0 = Set(lib_files0)
    set1 = Set(lib_files1)

    #compute the differences between the sets
    diff_01 = set0.difference(set1)
    diff_10 = set1.difference(set0)

    #display results
    header = 'Differences between %s and %s\n' % (sys.argv[1], sys.argv[2])
    print header
    print '-'*len(header)
    for i in diff_01:
        print '  %s' % (i)

    header = '\nDifferences between %s and %s\n' % (sys.argv[2], sys.argv[1])
    print header
    print '-'*len(header)
    for i in diff_10:
        print '  %s' % (i)


    #when you're ready, you might also choose to  build the directories that you'll need
    #to transfer in this script. one way is to wrap a normal copy command inside a 
    #system call like so:
    #import os
    #os.system('cp source destination')
    
if __name__ == '__main__':
    main()

Hopefully, the inline commenting makes this script easy to follow. It simply searches out lines that contain the files in your library, creates sets out of them, and then computes the differences between the sets. Computing the differences between libraries is really more than half the battle, because the rest of the work involved is rather boring: packaging up copies of the songs that need to be imported into another library, performing the copies, and then importing the songs.

Manual Clean Up

Our script relies on the same hierarchical structure that iTunes uses for storing tracks (Artist/Album/Tracks), so the results it produces are only as good as how iTunes categorized your music. Clearly, if tracks are named differently or categorized differently between iTunes installations (for whatever reason) you'll want to do some preprocessing and work those details out before the script above can be of much help (see Figure 2).

For example, the first time that I ran it, I noticed that several songs were tagged as being out of sync because they were labeled as belonging to a compilation in one library, while in another library they were labeled according to their original album. In other cases, there were tracks that were categorized into an "Unknown" folder in one library but not in another. Fortunately, the iTunes interface provides a pretty friendly way to work out these sorts of kinks.

cleanup
Figure 2. Use iTunes and scripts to do any initial clean up for tracks that may have been categorized incorrectly.

One way to systematically work through these issues is to run the Python script, use its output to correct a couple of albums, and then repeat the process until you're finished. Storing the output of the script as two separate files and viewing it through vimdiff may turn out to be useful as you work though this process (see Figure 3). Although not guaranteed to buy you anything, the way it highlights differences between lines is likely to save you some eye strain and increase your efficiency as you work through any manual clean up. At least you only have to do it once.

vimdiff
Figure 3. Tools like vimdiff may help you to expedite some of the initial clean up.

Depending on your circumstances, there are likely a variety of scripts out there that can be of further help with any preprocessing that you need to do. Doug's AppleScripts for iTunes is always a good place to start. In particular, the File Renamer script there can save you a lot of time if you need to standardize any track names for a particular album. (Here is a slightly modified version of the "File Renamer" script that fixed a minor annoyance where iTunes was not updating track names in its display.) Another option is to consider using any ID3 data in tracks (if present) to help you with the initial standardization.

Clearly, there's a lot of further customization you might choose to implement once you're ready to actually start the synchronization. For example, maybe you don't want to duplicate copies of particular albums or television shows on all of your machines for some reason. That's not a problem; simply filter through the results and handle these types of situations with a dose of conditional logic. A little bit goes a long way.

Packaging, Copying, etc.

Assuming you have manually worked out any strange anomalies between your two libraries with the preprocessing tips above, you're now ready to wrap things up. In particular, the final obstacles include: 1) getting all of your iTunes Music Library.xml files to a single location for comparison with the Python script and 2) distributing the "missing" files back out to wherever they need to go. Try using scp to accomplish these details, although another simple option would be to mount network shares containing the music you need and doing a simple copy.

You can read the all about scp by typing man scp in a terminal, but for our purposes, a command of the form scp user@hostname:'~/Music/iTunes/iTunes\ Music\ Library' /tmp/hostname_tunes should do the job for obtaining local copies of files. When you're ready to distribute songs back out, something like scp -r directoryOfSongs user@hostname:/tmp/ should work fine, although you might also choose to tar them up and perform the copy as a single file. Once you've performed the copy and gotten all of the goods into place, all that is left to do is to open iTunes and drag the folder of "missing" songs onto its main interface.

Wrapping Up

The three methods we identified for keeping your iTunes music libraries synchronized varied in involvedness, and hopefully one of them will work well with your particular situation. The master/slave approach offers a simple methodology for keeping things under wraps when there's not much complexity involved and is especially applicable for folks who are the sole users of a couple of machines. For slightly more complex situations, syncOtunes can get the job done by calculating differences between libraries and performing copies of the songs for you. Finally, we laid the foundation with some custom scripting for those of you who prefer to work up a more tailored approach. Extending the functionality of this base script to do more complex tasks should not be too difficult.

Matthew Russell is a computer scientist from middle Tennessee; and serves Digital Reasoning Systems as the Director of Advanced Technology. Hacking and writing are two activities essential to his renaissance man regimen.


Return to the Mac DevCenter.