#!/usr/bin/python import os import sys import fileinput import re import sha import base64 import subprocess import musicbrainz2.webservice as ws import musicbrainz2 import logging import glob import urllib2 import MusicBrainzHelper ########################################################################## ## flac helper code ## ########################################################################## class FlacHelper(): def __init__(self, filename): self.filename = filename # run metaflac and return the output as an array of strings def metaflac(self, args): for i in range(0, len(args)): if (type(args[i]) == str): args[i] = args[i].decode('cp1252') if (type(args[i]) == unicode): args[i] = args[i].encode('cp1252') commandline = subprocess.list2cmdline(args) mflac = subprocess.Popen(args, shell=False, executable="d:/util/bin/metaflac.exe", bufsize=1024, stdout=subprocess.PIPE).stdout output = mflac.readlines() mflac.close() # removing trailing newlines output = [ line.decode('cp437') for line in output ] output = [ line.rstrip("\r\n") for line in output ] return output # get the flac cuesheet from a flac file def readFlacCuesheet(self): args = [ 'metaflac.exe', '--export-cuesheet-to=-', self.filename ] return self.metaflac(args) # get the EAC cuesheet from a flac file. This is expected to live under # a tag called "cuesheet" def readEacCuesheet(self): args = [ 'metaflac.exe', '--show-tag=cuesheet', self.filename ] return self.metaflac(args) def getMusicBrainzId(self): args = [ 'metaflac.exe', '--show-tag=DISC_MUSICBRAINZ_ID', self.filename ] mbid = self.metaflac(args) if len(mbid) > 0: return mbid[0].partition("=")[2] else: return None def setMusicBrainzId(self, id): args = [ 'metaflac.exe', '--remove-tag=DISC_MUSICBRAINZ_ID', self.filename ] self.metaflac(args) args = [ 'metaflac.exe', '--set-tag=DISC_MUSICBRAINZ_ID=' + id, self.filename ] self.metaflac(args) # get the artist and title from our flac file def getArtistAndTitle(self): cuesheet = self.readEacCuesheet() artist = '' title = '' artistRegex = re.compile(r'^PERFORMER "(?P[^"]*)') titleRegex = re.compile(r'^TITLE "(?P[^"]*)') for line in cuesheet: artistMatch = artistRegex.search(line) if artistMatch: artist = artistMatch.group('performer') continue titleMatch = titleRegex.search(line) if titleMatch: title = titleMatch.group('title') continue if artist == '' and title == '': # this could be an matt-style flac with no EAC cuesheet args = [ 'metaflac.exe', '--show-tag=DISC_PERFORMER', self.filename ] artist = self.metaflac(args) args = [ 'metaflac.exe', '--show-tag=DISC_TITLE', self.filename ] title = self.metaflac(args) artist = artist[0].partition("=")[2] title = title[0].partition("=")[2] return [ artist, title ] # generate a musicbrainz DiscId from a flac cuesheet def getDiscIdAndTrackCount(self): cuesheet = self.readFlacCuesheet() FRAMES_PER_SECOND = 75 SAMPLES_PER_SECOND = 44100 SAMPLES_PER_FRAME = SAMPLES_PER_SECOND // FRAMES_PER_SECOND pregap = 0 currentTrackFrame = 0 pregapRegex = re.compile(r'PREGAP (?P<min>\d+):(?P<sec>\d\d):(?P<frame>\d\d)') startTrackRegex = re.compile(r'INDEX 01 (?P<min>\d+):(?P<sec>\d\d):(?P<frame>\d\d)') leadInRegex = re.compile(r'REM FLAC__lead-in (?P<sample>\d+)') leadOutRegex = re.compile(r'REM FLAC__lead-out 170 (?P<sample>\d+)') raw_framelist = list() numTracks = 0 for line in cuesheet: pregapMatch = pregapRegex.search(line) if pregapMatch: pregap = (int((pregapMatch.group('min')) * 60) + int(pregapMatch.group('sec'))) * FRAMES_PER_SECOND + int(pregapMatch.group('frame')) continue startTrackMatch = startTrackRegex.search(line) if startTrackMatch: numTracks += 1 currentTrackFrame = ((int(startTrackMatch.group('min')) * 60) + int(startTrackMatch.group('sec'))) * FRAMES_PER_SECOND + int(startTrackMatch.group('frame')) raw_framelist.append(currentTrackFrame) continue leadInMatch = leadInRegex.search(line) if leadInMatch: leadInFrame = long(leadInMatch.group('sample')) // SAMPLES_PER_FRAME continue leadOutMatch = leadOutRegex.search(line) if leadOutMatch: leadOutFrame_raw = long(leadOutMatch.group('sample')) // SAMPLES_PER_FRAME continue leadOutFrame = leadOutFrame_raw + leadInFrame framelist = [i + leadInFrame + pregap for i in raw_framelist] secondslist = [i//FRAMES_PER_SECOND for i in framelist] discIdLongForm = "" discIdLongForm = discIdLongForm + "%02X" % 1 discIdLongForm = discIdLongForm + "%02X" % numTracks discIdLongForm = discIdLongForm + "%08X" % leadOutFrame for x in framelist: discIdLongForm = discIdLongForm + "%08X" % x for x in range(numTracks, 99): discIdLongForm = discIdLongForm + "%08X" % 0 discid = base64.standard_b64encode(sha.new(discIdLongForm).digest()) discid = discid.replace("+", ".") discid = discid.replace("/", "_") discid = discid.replace("=", "-") return [ discid, numTracks ]