rendered paste bodyclass MusicHash(object):
subatoms = [['moov'], ['trak', 'udta'], ['mdia', 'meta'], ['minf', 'ilst'], ['stbl'], ['stsd'], []]
atoms_to_hash = ['mdat', 'oboe', 'apID']
def __init__(self, data):
self.data = data
self.hash_func = md5.new()
self._hash = None
def hash__get(self):
if self._hash != None:
return self._hash
return self.calculate_hash()
hash = property(hash__get)
def calculate_hash(self):
if data[4:12] == 'ftypM4A ':
self.hash_m4a()
else:
self.hash_default()
self._hash = self.hash_func.hexdigest()
return self._hash
def hash_default(self):
self.hash_func.update(self.data)
def hash_m4a(self):
self.drm = False
self.parse_data(self.data, 0)
def parse_data(self, data, depth):
loc = 0
while loc < len(data):
size = struct.unpack('>L', data[loc:loc+4])[0]
if size == 0:
atom = data[loc+4:loc+8]
subdata = data[loc+8:]
break
atom = data[loc+4:loc+8]
subdata = data[loc+8:loc+size]
if atom in self.subatoms[depth]:
if atom == 'meta':
self.parse_data(subdata[4:], depth+1)
elif atom == 'stsd':
self.parse_data(subdata[8:], depth +1)
else:
self.parse_data(subdata, depth + 1)
if atom == 'drms':
self.drm = True
if atom in self.atoms_to_hash:
if atom == 'apID' and not self.drm:
self.hash_func.update(subdata)
elif atom != 'apID':
self.hash_func.update(data[loc+4:loc+4+size])
loc += size