def delete_tag(filename): with fileutil.opened(filename, "rb+") as file: try: (cls, offset, length) = detect_tag(file) fileutil.replace_chunk(file, offset, length, bytes()) except NoTagError: pass
def read(cls, filename, offset=None, encoding="iso-8859-1"): """Read an ID3v1 tag from a file.""" with fileutil.opened(filename, "rb") as file: if offset is None: file.seek(-128, 2) else: file.seek(offset) data = file.read(128) return cls.decode(data, encoding=encoding)
def write(self, filename, encoding="iso-8859-1", errors="strict"): with fileutil.opened(filename, "rb+") as file: file.seek(-128, 2) data = file.read(128) if data[:3] == b"TAG": file.seek(-128, 2) else: file.seek(0, 2) file.write(self.encode(encoding, errors))
def delete(cls, filename, offset=None): """Delete ID3v1 tag from a file (if present).""" with fileutil.opened(filename, "rb+") as file: if offset is None: file.seek(-128, 2) else: file.seek(offset) offset = file.tell() data = file.read(128) if data[:3] == b"TAG": fileutil.replace_chunk(file, offset, 128, b"", in_place=True)
def write(self, filename=None): if not filename: filename = self._filename if not filename: raise TypeError("invalid file: {0}".format(filename)) with fileutil.opened(filename, "rb+") as file: try: (offset, length) = detect_tag(file)[1:3] except NoTagError: (offset, length) = (0, 0) if offset > 0: delete_tag(file) (offset, length) = (0, 0) tag_data = self.encode(size_hint=length) fileutil.replace_chunk(file, offset, length, tag_data)
def detect_tag(filename): """Return type and position of ID3v2 tag in filename. Returns (tag_class, offset, length), where tag_class is either Tag22, Tag23, or Tag24, and (offset, length) is the position of the tag in the file. """ with fileutil.opened(filename, "rb") as file: file.seek(0) header = file.read(10) file.seek(0) if len(header) < 10: raise NoTagError("File too short") if header[0:3] != b"ID3": raise NoTagError("ID3v2 tag not found") if header[3] not in _tag_versions or header[4] != 0: raise TagError("Unknown ID3 version: 2.{0}.{1}" .format(*header[3:5])) cls = _tag_versions[header[3]] offset = 0 length = Syncsafe.decode(header[6:10]) + 10 if header[3] == 4 and header[5] & _TAG24_FOOTER: length += 10 return (cls, offset, length)
def read(cls, filename, offset=0): """Read an ID3v2 tag from a file.""" i = 0 with fileutil.opened(filename, "rb") as file: file.seek(offset) tag = cls() tag._read_header(file) frames = tag._read_frames(file) for (frameid, bflags, data) in frames: if len(data) == 0: warn("{0}: Ignoring empty frame".format(frameid), EmptyFrameWarning) else: frame = tag._decode_frame(frameid, bflags, data, i) if frame is not None: l = tag._frames.setdefault(frame.frameid, []) l.append(frame) i += 1 try: tag._filename = file.name except AttributeError: pass return tag
def read_tag(filename): with fileutil.opened(filename, "rb") as file: (cls, offset, length) = detect_tag(file) return cls.read(file, offset)