def parse_frames(self): """ Recursively Parse Frames """ read = 0 readframes = 0 while read < self.tag["size"]: framedata = self.get_next_frame(self.tag["size"] - read) if framedata: try: read += len(framedata) if self.version == '2.2': frame = ID3v2_2_Frame(frame=framedata) elif self.version == '2.3': frame = ID3v2_3_Frame(frame=framedata) elif self.version == '2.4': frame = ID3v2_4_Frame(frame=framedata) readframes += 1 self.frames.append(frame) except ID3Exception: pass # ignore unrecognised frames else: self.tag["padding"] = self._read_null_bytes() debug("NULL Padding: %d" % self.tag["padding"]) break # do a sanity check on the size/padding if not self.tag.has_key("padding"): self.tag["padding"] = 0 if self.tag["size"] != read + self.tag["padding"]: self.tag["size"] = read + self.tag["padding"] return len(self.frames)
def x_comm(self): """ extract comment field sets: encoding, lang, shortcomment, longcomment """ data = self.rawdata self.encoding = encodings[ord(data[0])] self.language = data[1:4] self.shortcomment = '' self.longcomment = '' if is_double_byte(self.encoding): for i in range(4,len(data)-1): if data[i:i+2] == '\x00\x00': self.shortcomment = data[4:i].strip('\x00') self.longcomment = data[i+2:].strip('\x00') break else: for i in range(4,len(data)): if data[i] == '\x00': self.shortcomment = data[4:i].strip('\x00') self.longcomment = data[i+1:].strip('\x00') break debug('Read Field: %s Len: %d Enc: %s Lang: %s Comm: %s' % (self.fid, self.length, self.encoding, self.language, str([self.shortcomment, self.longcomment])))
def x_text(self): """ Extract Text Fields @todo: handle multiple strings seperated by \x00 sets: encoding, strings """ data = self.rawdata self.encoding = encodings[ord(data[0])] rawtext = data[1:] if normalize_encoding(self.encoding) == 'latin_1': text = rawtext self.strings = text.split('\x00') else: text = rawtext.decode(self.encoding) if is_double_byte(self.encoding): self.strings = text.split('\x00\x00') else: self.strings = text.split('\x00') try: dummy = text.encode('utf_8') debug('Read Field: %s Len: %d Enc: %s Text: %s' % (self.fid, self.length, self.encoding, str([text]))) except UnicodeDecodeError: debug('Read Field: %s Len: %d Enc: %s Text: %s (Err)' % (self.fid, self.length, self.encoding, str([text])))
def x_geob(self): """ Extract GEOB set: encoding, mimetype, filename, desc, obj """ data = self.rawdata self.encoding = encodings[ord(data[0])] self.mimetype = '' self.filename = '' self.desc = '' self.obj = '' for i in range(1,len(data)): if data[i] == '\x00': self.mimetype = data[1:i] break if not self.mimetype: raise ID3FrameException("Unable to extract GEOB. Missing mimetype") # FIXME: because filename and desc are optional, we should be # smarter about splitting if is_double_byte(self.encoding): for i in range(len(self.mimetype)+2,len(data)-1): if data[i:i+2] == '\x00\x00': self.filename = data[len(self.mimetype)+2:i] ptr = len(self.mimetype) + len(self.filename) + 4 break else: for i in range(len(self.mimetype)+2,len(data)-1): if data[i] == '\x00': self.filename = data[len(self.mimetype)+2:i] ptr = len(self.mimetype) + len(self.filename) + 3 break if is_double_byte(self.encoding): for i in range(ptr,len(data)-1): if data[i:i+2] == '\x00\x00': self.desc = data[ptr:i] self.obj = data[i+2:] break else: for i in range(ptr,len(data)-1): if data[i] == '\x00': self.desc = data[ptr:i] self.obj = data[i+1:] break debug("Read Field: %s Len: %d Enc: %s Mime: %s Filename: %s Desc: %s ObjLen: %d" % (self.fid, self.length, self.encoding, self.mimetype, self.filename, self.desc, len(self.obj)))
def x_pcnt(self): """ Extract Play Count sets: counter """ data = self.rawdata bytes = self.length counter = 0 if bytes == 4: counter = struct.unpack('!I',data)[0] else: for i in range(0,bytes): counter += struct.unpack('B',data[i]) * pow(256,i) debug('Read Field: %s Len: %d Count: %d' % (self.fid, bytes, counter)) self.counter = counter
def x_apic(self): """ Extract APIC set: encoding, mimetype, desc, pict, picttype """ data = self.rawdata self.encoding = encodings[ord(data[0])] self.mimetype = '' self.desc = '' self.pict = '' self.picttype = 0 # get mime type (must be latin-1) imgtype = data[1:4] if not imgtype: raise ID3FrameException("APIC extraction failed. Missing mimetype") if imgtype not in ID3V2_2_FRAME_IMAGE_FORMAT_TO_MIME_TYPE.keys(): raise ID3FrameException("Unrecognised mime-type") else: self.mimetype = ID3V2_2_FRAME_IMAGE_FORMAT_TO_MIME_TYPE[imgtype] picttype = ord(data[len(imgtype) + 1]) # get picture description for i in range(len(imgtype) + 2, len(data) - 1): print [data[i:i+3]] if data[i] == '\x00': self.desc = data[len(imgtype)+2:i] if data[i+1] == '\x00': self.pict = data[i+2:] else: self.pict = data[i+1:] break debug('Read Field: %s Len: %d PicType: %d Mime: %s Desc: %s PicLen: %d' % (self.fid, self.length, self.picttype, self.mimetype, self.desc, len(self.pict)))
def parse_header(self): """ Parse Header of the file """ self.f.seek(0) data = self.f.read(ID3V2_FILE_HEADER_LENGTH) if len(data) != ID3V2_FILE_HEADER_LENGTH: raise ID3HeaderInvalidException("ID3 tag header is incomplete") self.tag = {} self.frames = [] id3, ver, flags, rawsize = struct.unpack("!3sHB4s", data) if id3 != "ID3": raise ID3HeaderInvalidException("ID3v2 header not found") self.tag["size"] = unsyncsafe(rawsize) # NOTE: size = excluding header + footer version = '2.%d' % (ver >> 8) if version not in self.supported: raise ID3NotImplementedException("version %s not supported" % \ version) else: self.version = version if self.version in ('2.4', '2.3'): for flagname, bit in ID3V2_3_TAG_HEADER_FLAGS: self.tag[flagname] = (flags >> bit) & 0x01 elif self.version == '2.2': for flagname, bit in ID3V2_2_TAG_HEADER_FLAGS: self.tag[flagname] = (flags >> bit) & 0x01 if self.tag.has_key("ext") and self.tag["ext"]: self.parse_ext_header() debug(self.tag)
def x_apic(self): """ Extract APIC set: encoding, mimetype, desc, pict, picttype """ data = self.rawdata self.encoding = encodings[ord(data[0])] self.mimetype = '' self.desc = '' self.pict = '' self.picttype = 0 # get mime type (must be latin-1) for i in range(1,len(data)): if data[i] == '\x00': self.mimetype = data[1:i] break if not self.mimetype: raise ID3FrameException("APIC extraction failed. Missing mimetype") picttype = ord(data[len(self.mimetype) + 2]) # get picture description for i in range(len(self.mimetype) + 2, len(data)-1): if data[i] == '\x00': self.desc = data[len(self.mimetype)+2:i] if data[i+1] == '\x00': self.pict = data[i+2:] else: self.pict = data[i+1:] break debug('Read Field: %s Len: %d PicType: %d Mime: %s Desc: %s PicLen: %d' % (self.fid, self.length, self.picttype, self.mimetype, self.desc, len(self.pict)))
def x_wxxx(self): """ Extract URL set: encoding, desc, url """ data = self.rawdata self.encoding = encodings[ord(data[0])] if is_double_byte(self.encoding): for i in range(1,len(data)-1): if data[i:i+2] == '\x00\x00': self.desc = data[1:i] self.url = data[i+2:] break else: for i in range(1,len(data)): if data[i] == '\x00': self.desc = data[1:i] self.url = data[i+1:] break debug("Read field: %s Len: %s Enc: %s Desc: %s URL: %s" % (self.fid, self.length, self.encoding, self.desc, str([self.url])))
def x_url(self): debug("Read Field: %s Len: %d Data: %s" % (self.fid, self.length, [self.rawdata])) return