# -*- Mode: Python ; tab-width: 4 -*- import string import re import time import hashlib import os import stat import cPickle import calendar import pprint import pyItunes bg_color = "#FFFBEC" itunesdb = "itunes.xml" cachedb = "itunes.pkl" def loadArtistData(dbFile=itunesdb): return loadData()[0] def loadAlbumData(dbFile=itunesdb): return loadData()[1] def loadData(dbFile=itunesdb): if (dbFile == itunesdb and os.path.exists(cachedb) and (os.stat(itunesdb)[stat.ST_MTIME] < os.stat(cachedb)[stat.ST_MTIME])): f = open(cachedb) (artists, albums) = cPickle.load(f) f.close() return (artists, albums) artists = {} # { artist_name : Artist } albums = {} # { album_name : Album } parser = pyItunes.XMLLibraryParser( dbFile ) for d in parser.dictionary.values(): if not d.has_key("Location") or d["Location"][:7] != "file://": continue song = Song( d ) if artists.has_key( song.artist_name ): artist = artists[song.artist_name] else: artist = Artist( song.artist_name ) artists[song.artist_name] = artist artist.addSong( song ) if albums.has_key( song.album_name ): album = albums[song.album_name] else: album = Album( song.album_name ) albums[song.album_name] = album album.addSong( song ) f = open(cachedb, "w") cPickle.dump((artists, albums), f) f.close() return (artists, albums) class Song: disc_pats = [ re.compile( "(.*)\s*\(\d+ of \d+\)$", re.I ), re.compile( "(.*)\s*\[Dis[ck]\s*\d+\]$", re.I ), re.compile( "(.*)\s*\[CD\s*\d+\]$", re.I ), re.compile( "(.*)\s*\(Dis[ck]\s*\d+\)$", re.I ), re.compile( "(.*)\s*\(CD\s*\d+\)$", re.I ), re.compile( "(.*)\s*[,-:]\s*Dis[ck]\s*\d+$", re.I), re.compile( "(.*)\s*[,-:]\s*CD\s*\d+$", re.I), ] def __init__( self, d ): self.name = d["Name"] self.artist = None self.artist_name = d.get( "Artist", "Unknown" ) self.album = None self.album_name = self.deDisc( d.get( "Album", "Unknown" ) ) self.duration = int( round( int( d["Total Time"] ) / 1000.0 ) ) # Total Time is in milliseconds. self.track = d.get("Track Number") if self.track: self.track = int( self.track ) else: self.track = -1 self.last_played = d.get( "Play Date UTC" ) # 2011-02-24T22:20:53Z if self.last_played: self.last_played = calendar.timegm( time.strptime(self.last_played, "%Y-%m-%dT%H:%M:%SZ") ) else: self.last_played = 0 self.play_count = d.get( "Play Count" ) if self.play_count: self.play_count = int( self.play_count ) else: self.play_count = 0 def deDisc( self, album_name ): for pat in self.disc_pats: match = pat.search( album_name ) if match: album_name = match.group( 1 ) break return album_name class Artist: def __init__( self, name ): self.name = name self.songs = [] self.count = 0 self.duration = 0 self.last_played = 0 self.play_count = 0 def addSong( self, song ): self.songs.append( song ) song.artist = self self.count = self.count + 1 self.duration = self.duration + song.duration self.last_played = max( self.last_played, song.last_played ) self.play_count = self.play_count + song.play_count def getLink( self ): return "%s" % (self.getPage(), self.name) def getPage( self ): return "%s.html" % (getAnchorName( self.__class__.__name__ + "/" + self.name )) class Album( Artist ): def addSong( self, song ): self.songs.append( song ) song.album = self self.count = self.count + 1 self.duration = self.duration + song.duration self.last_played = max( self.last_played, song.last_played ) self.play_count = self.play_count + song.play_count def formatDuration( duration ): hours = duration / (60*60) minutes = (duration - (hours * 60*60)) / 60 seconds = (duration - (hours * 60*60) - (minutes * 60)) if hours: return "%d:%02d:%02d" % (hours, minutes, seconds) else: return "%02d:%02d" % (minutes, seconds) def formatPlayDate( last_played ): if last_played: t_str = time.strftime( "%m/%d/%y, %I:%M%p", time.localtime(last_played) ) else: t_str = "--" return t_str def getHeader( title, subtitle=None, currentTab=None ): s = """ %s""" % (title) if subtitle: s = s + " - %s" % (subtitle) s = s + """

%s

\n""" % (bg_color, title) s = s + "

" + getTabs( currentTab ) + "

" if subtitle: s = s + "

%s

\n" % (subtitle) s = s + """

\n""" return s def getFooter( page_name=None ): if page_name: crumb = "Playlist:%s" % (page_name) else: crumb = "Playlist" s = """


Chez Zeus:%s

©%d Dr. Zeus.
Last modified: %s
\n""" % (crumb, time.localtime(time.time())[0], time.ctime(time.time())) return s def getTabs( current=None ): if (current == "artists"): return "Artists | Albums | Songs" elif (current == "albums"): return "Artists | Albums | Songs" elif (current == "songs"): return "Artists | Albums | Songs" else: return "Artists | Albums | Songs" def getAnchorName( name ): return hashlib.sha1( name ).hexdigest() def plural( count, plur="s", sing="" ): if (count > 1): return plur else: return sing