Ejemplo n.º 1
0
def delete(filename, delete_v1=True, delete_v2=True):
    """Remove tags from a file.

    Keyword arguments:

    * delete_v1 -- delete any ID3v1 tag
    * delete_v2 -- delete any ID3v2 tag
    """

    f = xbmcvfs.File(filename)

    if delete_v1:
        tag, offset = _find_id3v1(f)
        if tag is not None:
            f.seek(offset, 2)
            f.truncate()

    # technically an insize=0 tag is invalid, but we delete it anyway
    # (primarily because we used to write it)
    if delete_v2:
        f.seek(0, 0)
        idata = f.read(10)
        try:
            id3, vmaj, vrev, flags, insize = unpack('>3sBBB4s', idata)
        except struct.error:
            id3, insize = b'', -1
        insize = BitPaddedInt(insize)
        if id3 == b'ID3' and insize >= 0:
            delete_bytes(f, insize + 10, 0)
Ejemplo n.º 2
0
def delete(filename, delete_v1=True, delete_v2=True):
    """Remove tags from a file.

    Keyword arguments:

    * delete_v1 -- delete any ID3v1 tag
    * delete_v2 -- delete any ID3v2 tag
    """

    f = xbmcvfs.File(filename)

    if delete_v1:
        tag, offset = _find_id3v1(f)
        if tag is not None:
            f.seek(offset, 2)
            f.truncate()

    # technically an insize=0 tag is invalid, but we delete it anyway
    # (primarily because we used to write it)
    if delete_v2:
        f.seek(0, 0)
        idata = f.read(10)
        try:
            id3, vmaj, vrev, flags, insize = unpack('>3sBBB4s', idata)
        except struct.error:
            id3, insize = b'', -1
        insize = BitPaddedInt(insize)
        if id3 == b'ID3' and insize >= 0:
            delete_bytes(f, insize + 10, 0)
Ejemplo n.º 3
0
    def delete(self):
        """Removes the chunk from the file"""

        delete_bytes(self.__fileobj, self.size, self.offset)
        if self.parent_chunk is not None:
            self.parent_chunk._update_size(
                self.parent_chunk.data_size - self.size)
Ejemplo n.º 4
0
    def delete(self, filename=None):
        """Remove tags from a file."""

        filename = filename or self.filename
        with open(filename, "r+b") as fileobj:
            data = _APEv2Data(fileobj)
            if data.start is not None and data.size is not None:
                delete_bytes(fileobj, data.end - data.start, data.start)

        self.clear()
Ejemplo n.º 5
0
    def delete(self, filename=None):
        """Remove tags from a file."""

        filename = filename or self.filename
        with open(filename, "r+b") as fileobj:
            data = _APEv2Data(fileobj)
            if data.start is not None and data.size is not None:
                delete_bytes(fileobj, data.end - data.start, data.start)

        self.clear()
Ejemplo n.º 6
0
    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()
Ejemplo n.º 7
0
    def save(self, filename=None):
        """Save changes to a file.

        If no filename is given, the one most recently loaded is used.

        Tags are always written at the end of the file, and include
        a header and a footer.
        """

        filename = filename or self.filename
        try:
            fileobj = open(filename, "r+b")
        except IOError:
            fileobj = open(filename, "w+b")
        data = _APEv2Data(fileobj)

        if data.is_at_start:
            delete_bytes(fileobj, data.end - data.start, data.start)
        elif data.start is not None:
            fileobj.seek(data.start)
            # Delete an ID3v1 tag if present, too.
            fileobj.truncate()
        fileobj.seek(0, 2)

        tags = []
        for key, value in self.items():
            # Packed format for an item:
            # 4B: Value length
            # 4B: Value type
            # Key name
            # 1B: Null
            # Key value
            value_data = value._write()
            if not isinstance(key, bytes):
                key = key.encode("utf-8")
            tag_data = bytearray()
            tag_data += struct.pack("<2I", len(value_data), value.kind << 1)
            tag_data += key + b"\0" + value_data
            tags.append(bytes(tag_data))

        # "APE tags items should be sorted ascending by size... This is
        # not a MUST, but STRONGLY recommended. Actually the items should
        # be sorted by importance/byte, but this is not feasible."
        tags.sort(key=len)
        num_tags = len(tags)
        tags = b"".join(tags)

        header = bytearray(b"APETAGEX")
        # version, tag size, item count, flags
        header += struct.pack("<4I", 2000,
                              len(tags) + 32, num_tags, HAS_HEADER | IS_HEADER)
        header += b"\0" * 8
        fileobj.write(header)

        fileobj.write(tags)

        footer = bytearray(b"APETAGEX")
        footer += struct.pack("<4I", 2000,
                              len(tags) + 32, num_tags, HAS_HEADER)
        footer += b"\0" * 8

        fileobj.write(footer)
        fileobj.close()
Ejemplo n.º 8
0
    def save(self, filename=None):
        """Save changes to a file.

        If no filename is given, the one most recently loaded is used.

        Tags are always written at the end of the file, and include
        a header and a footer.
        """

        filename = filename or self.filename
        try:
            fileobj = open(filename, "r+b")
        except IOError:
            fileobj = open(filename, "w+b")
        data = _APEv2Data(fileobj)

        if data.is_at_start:
            delete_bytes(fileobj, data.end - data.start, data.start)
        elif data.start is not None:
            fileobj.seek(data.start)
            # Delete an ID3v1 tag if present, too.
            fileobj.truncate()
        fileobj.seek(0, 2)

        tags = []
        for key, value in self.items():
            # Packed format for an item:
            # 4B: Value length
            # 4B: Value type
            # Key name
            # 1B: Null
            # Key value
            value_data = value._write()
            if not isinstance(key, bytes):
                key = key.encode("utf-8")
            tag_data = bytearray()
            tag_data += struct.pack("<2I", len(value_data), value.kind << 1)
            tag_data += key + b"\0" + value_data
            tags.append(bytes(tag_data))

        # "APE tags items should be sorted ascending by size... This is
        # not a MUST, but STRONGLY recommended. Actually the items should
        # be sorted by importance/byte, but this is not feasible."
        tags.sort(key=len)
        num_tags = len(tags)
        tags = b"".join(tags)

        header = bytearray(b"APETAGEX")
        # version, tag size, item count, flags
        header += struct.pack("<4I", 2000, len(tags) + 32, num_tags,
                              HAS_HEADER | IS_HEADER)
        header += b"\0" * 8
        fileobj.write(header)

        fileobj.write(tags)

        footer = bytearray(b"APETAGEX")
        footer += struct.pack("<4I", 2000, len(tags) + 32, num_tags,
                              HAS_HEADER)
        footer += b"\0" * 8

        fileobj.write(footer)
        fileobj.close()
Ejemplo n.º 9
0
    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()