def __save_new(self, fileobj, atoms, ilst_data, padding_func): hdlr = Atom.render(b"hdlr", b"\x00" * 8 + b"mdirappl" + b"\x00" * 9) meta_data = b"\x00\x00\x00\x00" + hdlr + ilst_data try: path = atoms.path(b"moov", b"udta") except KeyError: path = atoms.path(b"moov") offset = path[-1]._dataoffset # ignoring some atom overhead... but we don't have padding left anyway # and padding_size is guaranteed to be less than zero content_size = get_size(fileobj) - offset padding_size = -len(meta_data) assert padding_size < 0 info = PaddingInfo(padding_size, content_size) new_padding = info._get_padding(padding_func) new_padding = min(0xFFFFFFFF, new_padding) free = Atom.render(b"free", b"\x00" * new_padding) meta = Atom.render(b"meta", meta_data + free) if path[-1].name != b"udta": # moov.udta not found -- create one data = Atom.render(b"udta", meta) else: data = meta insert_bytes(fileobj, len(data), offset) fileobj.seek(offset) fileobj.write(data) self.__update_parents(fileobj, path, len(data)) self.__update_offsets(fileobj, atoms, len(data), offset)
def save(self, filename=None, v1=1, v2_version=4, v23_sep='/', padding=None): """Save changes to a file. Args: filename: Filename to save the tag to. If no filename is given, the one most recently loaded is used. v1 (ID3v1SaveOptions): if 0, ID3v1 tags will be removed. if 1, ID3v1 tags will be updated but not added. if 2, ID3v1 tags will be created and/or updated v2 (int): version of ID3v2 tags (3 or 4). v23_sep (str): the separator used to join multiple text values if v2_version == 3. Defaults to '/' but if it's None will be the ID3v2v2.4 null separator. padding (function): A function taking a PaddingInfo which should return the amount of padding to use. If None (default) will default to something reasonable. By default Mutagen saves ID3v2.4 tags. If you want to save ID3v2.3 tags, you must call method update_to_v23 before saving the file. The lack of a way to update only an ID3v1 tag is intentional. Can raise id3.error. """ if filename is None: filename = self.filename try: f = open(filename, 'rb+') except IOError as err: from errno import ENOENT if err.errno != ENOENT: raise f = open(filename, 'ab') # create, then reopen f = open(filename, 'rb+') try: try: header = ID3Header(f) except ID3NoHeaderError: old_size = 0 else: old_size = header.size data = self._prepare_data(f, 0, old_size, v2_version, v23_sep, padding) new_size = len(data) if (old_size < new_size): insert_bytes(f, new_size - old_size, old_size) elif (old_size > new_size): delete_bytes(f, old_size - new_size, new_size) f.seek(0) f.write(data) self.__save_v1(f, v1) finally: f.close()
def save(self, filename=None, v1=1, v2_version=4, v23_sep='/', padding=None): """Save changes to a file. Args: filename: Filename to save the tag to. If no filename is given, the one most recently loaded is used. v1 (ID3v1SaveOptions): if 0, ID3v1 tags will be removed. if 1, ID3v1 tags will be updated but not added. if 2, ID3v1 tags will be created and/or updated v2 (int): version of ID3v2 tags (3 or 4). v23_sep (str): the separator used to join multiple text values if v2_version == 3. Defaults to '/' but if it's None will be the ID3v2v2.4 null separator. padding (function): A function taking a PaddingInfo which should return the amount of padding to use. If None (default) will default to something reasonable. By default Mutagen saves ID3v2.4 tags. If you want to save ID3v2.3 tags, you must call method update_to_v23 before saving the file. The lack of a way to update only an ID3v1 tag is intentional. Can raise id3.error. """ if filename is None: filename = self.filename try: f = open(filename, 'rb+') except IOError as err: from errno import ENOENT if err.errno != ENOENT: raise f = open(filename, 'ab') # create, then reopen f = open(filename, 'rb+') try: try: header = ID3Header(f) except ID3NoHeaderError: old_size = 0 else: old_size = header.size data = self._prepare_data( f, 0, old_size, v2_version, v23_sep, padding) new_size = len(data) if (old_size < new_size): insert_bytes(f, new_size - old_size, old_size) elif (old_size > new_size): delete_bytes(f, old_size - new_size, new_size) f.seek(0) f.write(data) self.__save_v1(f, v1) finally: f.close()