#!/usr/bin/env python # -*- coding: utf-8 -*- # # Martin Tournoij # Use this code as you see fit. There are no restrictions. # import cgi import codecs import operator import os import re import subprocess import sys import time from collections import OrderedDict from mutagen.mp3 import MP3 from mutagen.flac import FLAC # Header for the HTML page head = u''' Martin's Music
[To top] | [Hide all] | [Show all] | [Generator source]

Clicking on an artist or album title will get you to the corresponding MusicBrainz page.
Note that most release dates are the release date of this specific release, not the original release date of the album.

''' # Used once at the top of each artist hdr = u''' ''' # Used for each album item = u''' ''' # Used once at the bottom of each artist ftr = u''' ''' # Used once at the bottom of the HTML page footer = u'''
[+] %(artist)s (Permalink | Wikipedia | Waffle)
%(album)s %(year)s %(type)s, %(status)s %(bitrate)s
''' def GetTags(musicfile): if musicfile[-4:] == '.mp3': f = MP3(musicfile) info = { 'bitrate': f.info.bitrate / 1000, 'artist': cgi.escape(f.tags.get('TPE1')[0]), 'name': cgi.escape(f.tags.get('TALB')[0]), 'year': '9999', 'type': None, 'status': None, 'albumid': None, 'artistid': None, } for t in f.tags.getall('TXXX'): if t.desc == 'MusicBrainz Album Type': info['type'] = t.text[0] elif t.desc == 'MusicBrainz Album Status': info['status'] = t.text[0] elif t.desc == 'MusicBrainz Album Id': info['albumid'] = t.text[0] elif t.desc == 'MusicBrainz Album Artist Id': info['artistid'] = t.text[0] if f.tags.get('TDOR'): info['year'] = f.tags.get('TDOR').__str__()[:4] elif f.tags.get('TDRL'): info['year'] = f.tags.get('TDRL').__str__()[:4] elif f.tags.get('TDRC'): info['year'] = f.tags.get('TDRC').__str__()[:4] elif musicfile[-5:] == '.flac': f = FLAC(musicfile) info = { 'bitrate': 'FLAC', 'artist': cgi.escape(f.tags.get('artist')[0]), 'name': cgi.escape(f.tags.get('album')[0]), 'year': '9999', 'type': None, 'status': None, 'albumid': None, 'artistid': None, } if f.tags.get('date'): info['year'] = f.tags.get('date')[0].__str__()[:4] if f.tags.get('releasetype'): info['type'] = f.tags.get('releasetype')[0] if f.tags.get('releasestatus'): info['status'] = f.tags.get('releasestatus')[0] if f.tags.get('musicbrainz_albumid'): info['albumid'] = f.tags.get('musicbrainz_albumid')[0] if f.tags.get('musicbrainz_artistid'): info['artistid'] = f.tags.get('musicbrainz_artistid')[0] # XXX hack if info['albumid'] == '95b6db4a-8ce8-43a6-918c-d3b540179c0f': info['artist'] = 'Biosphere & Deathprod' return info def GetAlbums(tld = u'.'): tracks_find = subprocess.Popen( [u'find', tld, u'-name', u'01*\.mp3', u'-or', u'-name', u'01*\.flac'], stdout = subprocess.PIPE) tracks_sort = subprocess.Popen([u'sort', u'--ignore-case'], stdin = tracks_find.stdout, stdout = subprocess.PIPE) tracks = unicode(tracks_sort.communicate()[0], 'utf-8') tracks = tracks.strip().split(u'\n') tracks = [ d.split(u'/') for d in tracks ] return tracks def MakeId(s): # Make valid HTML id= attribute replace = { '': '[^a-zA-Z0-9_-]', 'one-': '1', 'two-': '2', 'three-': '3', 'four-': '4', 'five-': '5', 'six-': '6', 'seven-': '7', 'eight-': '8', 'nine-': '9', 'zero-': '0', '-': '--' } idlink = s.lower() idlink = idlink.replace(' ', '-').strip('-') for (subst, repl) in replace.iteritems(): idlink = re.sub(repl, subst, idlink) return idlink if __name__ == '__main__': tracks = GetAlbums() music = OrderedDict() for row in tracks: track = row[-1:][0] album = row[-2:-1][0] artist = row[-3:-2][0] if not music.get(artist): music[artist] = [ ] try: # XXX commandline switch #print >> sys.stdout, u'Fetching tags for %s/%s/%s' % (artist, album, track) music[artist].append(GetTags(u'%s/%s/%s' % (artist, album, track))) except: print >> sys.stderr, ' Error, skipping %s/%s/%s' % (artist, album, track) print >> sys.stderr, sys.exc_info()[1] continue #if len(music) == 10: break #music.sort() fp = codecs.open(sys.argv[1], 'w', 'utf-8') fp.write(head % ({ 'now': time.strftime('%d %b %Y'), 'artistcount': 0, #artistcount, 'albumcount': 0, #albumcount, 'trackcount': 0, #trackcount, 'avg': 0, #float(albumcount / artistcount), 'totalsize': 0, #totalsize, })) # Make sure we don't have invalid characters in the ID attribute. for (artist, albums) in music.iteritems(): idlink = MakeId(artist) wplink = 'http://en.wikipedia.org/wiki/%s' % artist mblink = 'http://musicbrainz.org/artist/%s' % albums[0]['artistid'] waffle = 'https://www.waffles.fm/browse.php?q=artist%%3A%%22%s%%22' % artist fp.write(hdr % ({ 'idlink': idlink, 'wplink': wplink, 'artist': artist, 'artistid': artist, 'mblink': mblink, 'waffle': waffle, })) for album in albums: mblink = 'http://musicbrainz.org/release/%s.html' % album['albumid'] if album['bitrate'] < 128: clss = ' red' elif album['bitrate'] < 180: clss = ' yellow' elif album['bitrate'] == 'FLAC': clss = ' green' else: clss = '' if album['bitrate'] != 'FLAC': album['bitrate'] = album['bitrate'].__str__() + ' Kbps' if album['year'] == '9999': album['year'] = 'None' fp.write(item % ({ 'album': album['name'], 'year': album['year'], 'bitrate': album['bitrate'], 'type': album['type'], 'status': album['status'], 'mblink': mblink, 'albumid': album['albumid'], 'class': clss, })) fp.write(ftr % ({ 'idlink': idlink, })) fp.write(footer + u'\n') fp.close()