class APIC(Frame): """Attached (or linked) Picture. Attributes: * encoding -- text encoding for the description * mime -- a MIME type (e.g. image/jpeg) or '-->' if the data is a URI * type -- the source of the image (3 is the album front cover) * desc -- a text description of the image * data -- raw image data, as a byte string Mutagen will automatically compress large images when saving tags. """ _framespec = [ EncodingSpec('encoding'), Latin1TextSpec('mime'), ByteSpec('type'), EncodedTextSpec('desc'), BinaryDataSpec('data'), ] def __eq__(self, other): return self.data == other __hash__ = Frame.__hash__ @property def HashKey(self): return '%s:%s:%s' % (self.FrameID, self.desc, hashlib.md5(self.data).hexdigest()) def _pprint(self): return "%s (%s, %d bytes)" % ( self.desc, self.mime, len(self.data))
class POPM(FrameOpt): """Popularimeter. This frame keys a rating (out of 255) and a play count to an email address. Attributes: * email -- email this POPM frame is for * rating -- rating from 0 to 255 * count -- number of times the files has been played (optional) """ _framespec = [ Latin1TextSpec('email'), ByteSpec('rating'), ] _optionalspec = [IntegerSpec('count')] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.email) def __eq__(self, other): return self.rating == other __hash__ = FrameOpt.__hash__ def __pos__(self): return self.rating def _pprint(self): return "%s=%r %r/255" % ( self.email, getattr(self, 'count', None), self.rating)
class PRIV(Frame): """Private frame.""" _framespec = [ Latin1TextSpec('owner'), BinaryDataSpec('data'), ] @property def HashKey(self): return '%s:%s:%s' % ( self.FrameID, self.owner, self.data.decode('latin1')) def __bytes__(self): return self.data def __eq__(self, other): return self.data == other def _pprint(self): isascii = ord_(max(self.data)) < 128 if isascii: return "%s=%s" % (self.owner, self.data) else: return "%s (%d bytes)" % (self.owner, len(self.data)) __hash__ = Frame.__hash__
class UrlFrame(Frame): """A frame containing a URL string. The ID3 specification is silent about IRIs and normalized URL forms. Mutagen assumes all URLs in files are encoded as Latin 1, but string conversion of this frame returns a UTF-8 representation for compatibility with other string conversions. The only sane way to handle URLs in MP3s is to restrict them to ASCII. """ _framespec = [Latin1TextSpec('url')] def __bytes__(self): return self.url.encode('utf-8') def __str__(self): return self.url def __eq__(self, other): return self.url == other __hash__ = Frame.__hash__ def _pprint(self): return self.url
class GRID(FrameOpt): """Group identification registration.""" _framespec = [ Latin1TextSpec('owner'), ByteSpec('group'), ] _optionalspec = [BinaryDataSpec('data')] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.group) def __pos__(self): return self.group def __bytes__(self): return self.owner.encode('utf-8') def __str__(self): return self.owner def __eq__(self, other): return self.owner == other or self.group == other __hash__ = FrameOpt.__hash__
class UFID(Frame): """Unique file identifier. Attributes: * owner -- format/type of identifier * data -- identifier """ _framespec = [ Latin1TextSpec('owner'), BinaryDataSpec('data'), ] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.owner) def __eq__(s, o): if isinstance(o, UFI): return s.owner == o.owner and s.data == o.data else: return s.data == o __hash__ = Frame.__hash__ def _pprint(self): isascii = ord_(max(self.data)) < 128 if isascii: return "%s=%s" % (self.owner, self.data) else: return "%s (%d bytes)" % (self.owner, len(self.data))
class LINK(FrameOpt): """Linked information. Attributes: * frameid -- the ID of the linked frame * url -- the location of the linked frame * data -- further ID information for the frame """ _framespec = [ StringSpec('frameid', 4), Latin1TextSpec('url'), ] _optionalspec = [BinaryDataSpec('data')] @property def HashKey(self): try: return "%s:%s:%s:%r" % ( self.FrameID, self.frameid, self.url, self.data) except AttributeError: return "%s:%s:%s" % (self.FrameID, self.frameid, self.url) def __eq__(self, other): try: return (self.frameid, self.url, self.data) == other except AttributeError: return (self.frameid, self.url) == other __hash__ = FrameOpt.__hash__
class AENC(FrameOpt): """Audio encryption. Attributes: * owner -- key identifying this encryption type * preview_start -- unencrypted data block offset * preview_length -- number of unencrypted blocks * data -- data required for decryption (optional) Mutagen cannot decrypt files. """ _framespec = [ Latin1TextSpec('owner'), SizedIntegerSpec('preview_start', 2), SizedIntegerSpec('preview_length', 2), ] _optionalspec = [BinaryDataSpec('data')] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.owner) def __bytes__(self): return self.owner.encode('utf-8') def __str__(self): return self.owner def __eq__(self, other): return self.owner == other __hash__ = FrameOpt.__hash__
class GEOB(Frame): """General Encapsulated Object. A blob of binary data, that is not a picture (those go in APIC). Attributes: * encoding -- encoding of the description * mime -- MIME type of the data or '-->' if the data is a URI * filename -- suggested filename if extracted * desc -- text description of the data * data -- raw data, as a byte string """ _framespec = [ EncodingSpec('encoding'), Latin1TextSpec('mime'), EncodedTextSpec('filename'), EncodedTextSpec('desc'), BinaryDataSpec('data'), ] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.desc) def __eq__(self, other): return self.data == other __hash__ = Frame.__hash__
class WXXX(UrlFrame): """User-defined URL data. Like TXXX, this has a freeform description associated with it. """ _framespec = [ EncodingSpec('encoding'), EncodedTextSpec('desc'), Latin1TextSpec('url'), ] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.desc)
class RVA2(Frame): """Relative volume adjustment (2). This frame is used to implemented volume scaling, and in particular, normalization using ReplayGain. Attributes: * desc -- description or context of this adjustment * channel -- audio channel to adjust (master is 1) * gain -- a + or - dB gain relative to some reference level * peak -- peak of the audio as a floating point number, [0, 1] When storing ReplayGain tags, use descriptions of 'album' and 'track' on channel 1. """ _framespec = [ Latin1TextSpec('desc'), ChannelSpec('channel'), VolumeAdjustmentSpec('gain'), VolumePeakSpec('peak'), ] _channels = ["Other", "Master volume", "Front right", "Front left", "Back right", "Back left", "Front centre", "Back centre", "Subwoofer"] @property def HashKey(self): return '%s:%s' % (self.FrameID, self.desc) def __eq__(self, other): try: return ((str(self) == other) or (self.desc == other.desc and self.channel == other.channel and self.gain == other.gain and self.peak == other.peak)) except AttributeError: return False __hash__ = Frame.__hash__ def __str__(self): return "%s: %+0.4f dB/%0.4f" % ( self._channels[self.channel], self.gain, self.peak)
class OWNE(Frame): """Ownership frame.""" _framespec = [ EncodingSpec('encoding'), Latin1TextSpec('price'), StringSpec('date', 8), EncodedTextSpec('seller'), ] def __str__(self): return self.seller.encode('utf-8') def __unicode__(self): return self.seller def __eq__(self, other): return self.seller == other __hash__ = Frame.__hash__
class EQU2(Frame): """Equalisation (2). Attributes: method -- interpolation method (0 = band, 1 = linear) desc -- identifying description adjustments -- list of (frequency, vol_adjustment) pairs """ _framespec = [ ByteSpec("method"), Latin1TextSpec("desc"), VolumeAdjustmentsSpec("adjustments"), ] def __eq__(self, other): return self.adjustments == other __hash__ = Frame.__hash__ @property def HashKey(self): return '%s:%s' % (self.FrameID, self.desc)
class ENCR(Frame): """Encryption method registration. The standard does not allow multiple ENCR frames with the same owner or the same method. Mutagen only verifies that the owner is unique. """ _framespec = [ Latin1TextSpec('owner'), ByteSpec('method'), BinaryDataSpec('data'), ] @property def HashKey(self): return "%s:%s" % (self.FrameID, self.owner) def __str__(self): return self.data def __eq__(self, other): return self.data == other __hash__ = Frame.__hash__
class LNK(LINK): """Linked information""" _framespec = [StringSpec('frameid', 3), Latin1TextSpec('url')] _optionalspec = [BinaryDataSpec('data')]