def load(self, filething, known_frames=None, translate=True, v2_version=4): """load(filething, known_frames=None, translate=True, v2_version=4) Load tags from a filename. Args: filename (filething): filename or file object to load tag data from known_frames (Dict[`mutagen.text`, `Frame`]): dict mapping frame IDs to Frame objects translate (bool): Update all tags to ID3v2.3/4 internally. If you intend to save, this must be true or you have to call update_to_v23() / update_to_v24() manually. v2_version (int): if update_to_v23 or update_to_v24 get called (3 or 4) Example of loading a custom frame:: my_frames = dict(mutagen.id3.Frames) class XMYF(Frame): ... my_frames["XMYF"] = XMYF mutagen.id3.ID3(filename, known_frames=my_frames) """ fileobj = filething.fileobj if v2_version not in (3, 4): raise ValueError("Only 3 and 4 possible for v2_version") self.unknown_frames = [] self._header = None self._padding = 0 self._pre_load_header(fileobj) try: self._header = ID3Header(fileobj) except (ID3NoHeaderError, ID3UnsupportedVersionError): frames, offset = find_id3v1(fileobj) if frames is None: raise self.version = ID3Header._V11 for v in frames.values(): self.add(v) else: # XXX: attach to the header object so we have it in spec parsing.. if known_frames is not None: self._header._known_frames = known_frames data = read_full(fileobj, self.size - 10) remaining_data = self._read(self._header, data) self._padding = len(remaining_data) if translate: if v2_version == 3: self.update_to_v23() else: self.update_to_v24()
def __init__(self, fileobj=None): """Raises ID3NoHeaderError, ID3UnsupportedVersionError or error""" if fileobj is None: # for testing self._flags = 0 return fn = getattr(fileobj, "name", "<unknown>") data = fileobj.read(10) if len(data) != 10: raise ID3NoHeaderError("%s: too small" % fn) id3, vmaj, vrev, flags, size = struct.unpack('>3sBBB4s', data) self._flags = flags self.size = BitPaddedInt(size) + 10 self.version = (2, vmaj, vrev) if id3 != b'ID3': raise ID3NoHeaderError("%r doesn't start with an ID3 tag" % fn) if vmaj not in [2, 3, 4]: raise ID3UnsupportedVersionError("%r ID3v2.%d not supported" % (fn, vmaj)) if not BitPaddedInt.has_valid_padding(size): raise error("Header size not synchsafe") if (self.version >= self._V24) and (flags & 0x0f): raise error("%r has invalid flags %#02x" % (fn, flags)) elif (self._V23 <= self.version < self._V24) and (flags & 0x1f): raise error("%r has invalid flags %#02x" % (fn, flags)) if self.f_extended: extsize_data = read_full(fileobj, 4) if PY3: frame_id = extsize_data.decode("ascii", "replace") else: frame_id = extsize_data if frame_id in Frames: # Some tagger sets the extended header flag but # doesn't write an extended header; in this case, the # ID3 data follows immediately. Since no extended # header is going to be long enough to actually match # a frame, and if it's *not* a frame we're going to be # completely lost anyway, this seems to be the most # correct check. # https://github.com/quodlibet/quodlibet/issues/126 self._flags ^= 0x40 extsize = 0 fileobj.seek(-4, 1) elif self.version >= self._V24: # "Where the 'Extended header size' is the size of the whole # extended header, stored as a 32 bit synchsafe integer." extsize = BitPaddedInt(extsize_data) - 4 if not BitPaddedInt.has_valid_padding(extsize_data): raise error("Extended header size not synchsafe") else: # "Where the 'Extended header size', currently 6 or 10 bytes, # excludes itself." extsize = struct.unpack('>L', extsize_data)[0] self._extdata = read_full(fileobj, extsize)
def __init__(self, fileobj=None): """Raises ID3NoHeaderError, ID3UnsupportedVersionError or error""" if fileobj is None: # for testing self._flags = 0 return fn = getattr(fileobj, "name", "<unknown>") data = fileobj.read(10) if len(data) != 10: raise ID3NoHeaderError("%s: too small" % fn) id3, vmaj, vrev, flags, size = struct.unpack('>3sBBB4s', data) self._flags = flags self.size = BitPaddedInt(size) + 10 self.version = (2, vmaj, vrev) if id3 != b'ID3': raise ID3NoHeaderError("%r doesn't start with an ID3 tag" % fn) if vmaj not in [2, 3, 4]: raise ID3UnsupportedVersionError("%r ID3v2.%d not supported" % (fn, vmaj)) if not BitPaddedInt.has_valid_padding(size): raise error("Header size not synchsafe") if (self.version >= self._V24) and (flags & 0x0f): raise error( "%r has invalid flags %#02x" % (fn, flags)) elif (self._V23 <= self.version < self._V24) and (flags & 0x1f): raise error( "%r has invalid flags %#02x" % (fn, flags)) if self.f_extended: extsize_data = read_full(fileobj, 4) if PY3: frame_id = extsize_data.decode("ascii", "replace") else: frame_id = extsize_data if frame_id in Frames: # Some tagger sets the extended header flag but # doesn't write an extended header; in this case, the # ID3 data follows immediately. Since no extended # header is going to be long enough to actually match # a frame, and if it's *not* a frame we're going to be # completely lost anyway, this seems to be the most # correct check. # https://github.com/quodlibet/quodlibet/issues/126 self._flags ^= 0x40 extsize = 0 fileobj.seek(-4, 1) elif self.version >= self._V24: # "Where the 'Extended header size' is the size of the whole # extended header, stored as a 32 bit synchsafe integer." extsize = BitPaddedInt(extsize_data) - 4 if not BitPaddedInt.has_valid_padding(extsize_data): raise error( "Extended header size not synchsafe") else: # "Where the 'Extended header size', currently 6 or 10 bytes, # excludes itself." extsize = struct.unpack('>L', extsize_data)[0] self._extdata = read_full(fileobj, extsize)