예제 #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
    """

    with mutagen.FileOpener(filename, 'rb+') as f:

        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)
예제 #2
0
    def load(self, filename, ID3=None, **kwargs):
        """Load stream and tag information from a file.

        A custom tag reader may be used in instead of the default
        mutagen.id3.ID3 object, e.g. an EasyID3 reader.
        """

        if ID3 is None:
            ID3 = self.ID3
        else:
            # If this was initialized with EasyID3, remember that for
            # when tags are auto-instantiated in add_tags.
            self.ID3 = ID3
        self.filename = filename
        try:
            self.tags = ID3(filename, **kwargs)
        except ID3NoHeaderError:
            self.tags = None

        if self.tags is not None:
            try:
                offset = self.tags.size
            except AttributeError:
                offset = None
        else:
            offset = None

        with mutagen.FileOpener(filename, "rb") as fileobj:
            self.info = self._Info(fileobj, offset)
예제 #3
0
파일: apev2.py 프로젝트: camster1/RTOTV
 def load(self, filename):
     self.filename = filename
     self.info = self._Info(mutagen.FileOpener(filename, "rb"))
     try:
         self.tags = APEv2(filename)
     except APENoHeaderError:
         self.tags = None
예제 #4
0
    def save(self, filename):
        """Save the metadata to the given filename."""
        values = []
        items = self.items()
        items.sort(self.__key_sort)
        for key, value in items:
            render = self.__atoms.get(key[:4],
                                      (None, M4ATags.__render_text))[1]
            values.append(render(self, key, value))
        data = Atom.render("ilst", "".join(values))

        # Find the old atoms.
        fileobj = mutagen.FileOpener(filename, "rb+")
        try:
            atoms = Atoms(fileobj)

            moov = atoms["moov"]

            if moov != atoms.atoms[-1]:
                # "Free" the old moov block. Something in the mdat
                # block is not happy when its offset changes and it
                # won't play back. So, rather than try to figure that
                # out, just move the moov atom to the end of the file.
                offset = self.__move_moov(fileobj, moov)
            else:
                offset = 0

            try:
                path = atoms.path("moov", "udta", "meta", "ilst")
            except KeyError:
                self.__save_new(fileobj, atoms, data, offset)
            else:
                self.__save_existing(fileobj, atoms, path, data, offset)
        finally:
            fileobj.close()
예제 #5
0
파일: aiff.py 프로젝트: camster1/RTOTV
def delete(filename):
    """Completely removes the ID3 chunk from the AIFF file"""

    with mutagen.FileOpener(filename, "rb+") as file_:
        try:
            del IFFFile(file_)[u'ID3']
        except KeyError:
            pass
예제 #6
0
파일: apev2.py 프로젝트: camster1/RTOTV
    def delete(self, filename=None):
        """Remove tags from a file."""

        filename = filename or self.filename
        fileobj = mutagen.FileOpener(filename, "r+b")
        try:
            data = _APEv2Data(fileobj)
            if data.start is not None and data.size is not None:
                delete_bytes(fileobj, data.end - data.start, data.start)
        finally:
            fileobj.close()
        self.clear()
예제 #7
0
파일: asf.py 프로젝트: camster1/RTOTV
 def load(self, filename):
     self.filename = filename
     with mutagen.FileOpener(filename, "rb") as fileobj:
         self.size = 0
         self.size1 = 0
         self.size2 = 0
         self.offset1 = 0
         self.offset2 = 0
         self.num_objects = 0
         self.info = ASFInfo()
         self.tags = ASFTags()
         self.__read_file(fileobj)
예제 #8
0
파일: apev2.py 프로젝트: camster1/RTOTV
    def load(self, filename):
        """Load tags from a filename."""

        self.filename = filename
        fileobj = mutagen.FileOpener(filename, "rb")
        try:
            data = _APEv2Data(fileobj)
        finally:
            fileobj.close()
        if data.tag:
            self.clear()
            self.__parse_tag(data.tag, data.items)
        else:
            raise APENoHeaderError("No APE tag found")
예제 #9
0
파일: ogg.py 프로젝트: camster1/RTOTV
    def load(self, filename):
        """Load file information from a filename."""

        self.filename = filename
        fileobj = mutagen.FileOpener(filename, "rb")
        try:
            try:
                self.info = self._Info(fileobj)
                self.tags = self._Tags(fileobj, self.info)
                self.info._post_tags(fileobj)
            except error as e:
                reraise(self._Error, e, sys.exc_info()[2])
            except EOFError:
                raise self._Error("no appropriate stream found")
        finally:
            fileobj.close()
예제 #10
0
파일: aiff.py 프로젝트: camster1/RTOTV
    def load(self, filename, **kwargs):
        """Load stream and tag information from a file."""
        self.filename = filename

        try:
            self.tags = _IFFID3(filename, **kwargs)
        except ID3NoHeaderError:
            self.tags = None
        except ID3Error as e:
            raise error(e)

        try:
            fileobj = mutagen.FileOpener(filename, "rb")
            self.info = AIFFInfo(fileobj)
        finally:
            fileobj.close()
예제 #11
0
 def load(self, filename):
     self.filename = filename
     fileobj = mutagen.FileOpener(filename, "rb")
     try:
         atoms = Atoms(fileobj)
         try:
             self.info = M4AInfo(atoms, fileobj)
         except StandardError as err:
             reraise(M4AStreamInfoError, err, sys.exc_info()[2])
         try:
             self.tags = M4ATags(atoms, fileobj)
         except M4AMetadataError:
             self.tags = None
         except StandardError as err:
             reraise(M4AMetadataError, err, sys.exc_info()[2])
     finally:
         fileobj.close()
예제 #12
0
파일: ogg.py 프로젝트: camster1/RTOTV
    def save(self, filename=None):
        """Save a tag to a file.

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

        if filename is None:
            filename = self.filename
        fileobj = mutagen.FileOpener(filename, "rb+")
        try:
            try:
                self.tags._inject(fileobj)
            except error as e:
                reraise(self._Error, e, sys.exc_info()[2])
            except EOFError:
                raise self._Error("no appropriate stream found")
        finally:
            fileobj.close()
예제 #13
0
파일: __init__.py 프로젝트: camster1/RTOTV
    def save(self, filename):
        """Save the metadata to the given filename."""

        values = []
        items = sorted(self.items(), key=self._key_sort)
        for key, value in items:
            atom_name = _key2name(key)[:4]
            if atom_name in self.__atoms:
                render_func = self.__atoms[atom_name][1]
            else:
                render_func = type(self).__render_text

            try:
                values.append(render_func(self, key, value))
            except (TypeError, ValueError) as s:
                reraise(MP4MetadataValueError, s, sys.exc_info()[2])

        for key, failed in iteritems(self._failed_atoms):
            # don't write atoms back if we have added a new one with
            # the same name, this excludes freeform which can have
            # multiple atoms with the same key (most parsers seem to be able
            # to handle that)
            if key in self:
                assert _key2name(key) != b"----"
                continue
            for data in failed:
                values.append(Atom.render(_key2name(key), data))

        data = Atom.render(b"ilst", b"".join(values))

        # Find the old atoms.
        with mutagen.FileOpener(filename, "rb+") as fileobj:
            try:
                atoms = Atoms(fileobj)
            except AtomError as err:
                reraise(error, err, sys.exc_info()[2])

            try:
                path = atoms.path(b"moov", b"udta", b"meta", b"ilst")
            except KeyError:
                self.__save_new(fileobj, atoms, data)
            else:
                self.__save_existing(fileobj, atoms, path, data)
예제 #14
0
    def load(self, filename):
        """Load file information from a filename."""

        self.metadata_blocks = []
        self.tags = None
        self.cuesheet = None
        self.seektable = None
        self.filename = filename
        fileobj = StrictFileObject(mutagen.FileOpener(filename, "rb"))
        try:
            self.__check_header(fileobj)
            while self.__read_metadata_block(fileobj):
                pass
        finally:
            fileobj.close()

        try:
            self.metadata_blocks[0].length
        except (AttributeError, IndexError):
            raise FLACNoHeaderError("Stream info block not found")
예제 #15
0
파일: aiff.py 프로젝트: camster1/RTOTV
    def save(self, filename=None, v2_version=4, v23_sep='/'):
        """Save ID3v2 data to the AIFF file"""

        framedata = self._prepare_framedata(v2_version, v23_sep)
        framesize = len(framedata)

        if filename is None:
            filename = self.filename

        # Unlike the parent ID3.save method, we won't save to a blank file
        # since we would have to construct a empty AIFF file
        fileobj = mutagen.FileOpener(filename, 'rb+')
        iff_file = IFFFile(fileobj)

        try:
            if u'ID3' not in iff_file:
                iff_file.insert_chunk(u'ID3')

            chunk = iff_file[u'ID3']
            fileobj.seek(chunk.data_offset)

            header = fileobj.read(10)
            header = self._prepare_id3_header(header, framesize, v2_version)
            header, new_size, _ = header

            data = header + framedata + (b'\x00' * (new_size - framesize))

            # Include ID3 header size in 'new_size' calculation
            new_size += 10

            # Expand the chunk if necessary, including pad byte
            if new_size > chunk.size:
                insert_at = chunk.offset + chunk.size
                insert_size = new_size - chunk.size + new_size % 2
                insert_bytes(fileobj, insert_size, insert_at)
                chunk.resize(new_size)

            fileobj.seek(chunk.data_offset)
            fileobj.write(data)
        finally:
            fileobj.close()
예제 #16
0
파일: __init__.py 프로젝트: camster1/RTOTV
    def load(self, filename):
        self.filename = filename
        with mutagen.FileOpener(filename, "rb") as fileobj:
            try:
                atoms = Atoms(fileobj)
            except AtomError as err:
                reraise(error, err, sys.exc_info()[2])

            try:
                self.info = MP4Info(atoms, fileobj)
            except error:
                raise
            except Exception as err:
                reraise(MP4StreamInfoError, err, sys.exc_info()[2])

            if not MP4Tags._can_load(atoms):
                self.tags = None
            else:
                try:
                    self.tags = self.MP4Tags(atoms, fileobj)
                except error:
                    raise
                except Exception as err:
                    reraise(MP4MetadataError, err, sys.exc_info()[2])
예제 #17
0
파일: aac.py 프로젝트: camster1/RTOTV
 def load(self, filename):
     self.filename = filename
     with mutagen.FileOpener(filename, "rb") as h:
         self.info = AACInfo(h)
예제 #18
0
파일: asf.py 프로젝트: camster1/RTOTV
    def save(self):
        # Move attributes to the right objects
        self.to_content_description = {}
        self.to_extended_content_description = {}
        self.to_metadata = {}
        self.to_metadata_library = []
        for name, value in self.tags:
            library_only = (value.data_size() > 0xFFFF or value.TYPE == GUID)
            can_cont_desc = value.TYPE == UNICODE

            if library_only or value.language is not None:
                self.to_metadata_library.append((name, value))
            elif value.stream is not None:
                if name not in self.to_metadata:
                    self.to_metadata[name] = value
                else:
                    self.to_metadata_library.append((name, value))
            elif name in ContentDescriptionObject.NAMES:
                if name not in self.to_content_description and can_cont_desc:
                    self.to_content_description[name] = value
                else:
                    self.to_metadata_library.append((name, value))
            else:
                if name not in self.to_extended_content_description:
                    self.to_extended_content_description[name] = value
                else:
                    self.to_metadata_library.append((name, value))

        # Add missing objects
        if not self.content_description_obj:
            self.content_description_obj = \
                ContentDescriptionObject()
            self.objects.append(self.content_description_obj)
        if not self.extended_content_description_obj:
            self.extended_content_description_obj = \
                ExtendedContentDescriptionObject()
            self.objects.append(self.extended_content_description_obj)
        if not self.header_extension_obj:
            self.header_extension_obj = \
                HeaderExtensionObject()
            self.objects.append(self.header_extension_obj)
        if not self.metadata_obj:
            self.metadata_obj = \
                MetadataObject()
            self.header_extension_obj.objects.append(self.metadata_obj)
        if not self.metadata_library_obj:
            self.metadata_library_obj = \
                MetadataLibraryObject()
            self.header_extension_obj.objects.append(self.metadata_library_obj)

        # Render the header
        data = b"".join([obj.render(self) for obj in self.objects])
        data = (HeaderObject.GUID +
                struct.pack("<QL",
                            len(data) + 30, len(self.objects)) + b"\x01\x02" +
                data)

        with mutagen.FileOpener(self.filename, "rb+") as fileobj:
            size = len(data)
            if size > self.size:
                insert_bytes(fileobj, size - self.size, self.size)
            if size < self.size:
                delete_bytes(fileobj, self.size - size, 0)
            fileobj.seek(0)
            fileobj.write(data)

        self.size = size
        self.num_objects = len(self.objects)
예제 #19
0
파일: apev2.py 프로젝트: camster1/RTOTV
    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 = mutagen.FileOpener(filename, "r+b")
        except IOError:
            fileobj = mutagen.FileOpener(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()
예제 #20
0
    def save(self, filename=None, deleteid3=False):
        """Save metadata blocks to a file.

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

        if filename is None:
            filename = self.filename
        f = mutagen.FileOpener(filename, 'rb+')

        try:
            # Ensure we've got padding at the end, and only at the end.
            # If adding makes it too large, we'll scale it down later.
            self.metadata_blocks.append(Padding(b'\x00' * 1020))
            MetadataBlock.group_padding(self.metadata_blocks)

            header = self.__check_header(f)
            # "fLaC" and maybe ID3
            available = self.__find_audio_offset(f) - header
            data = MetadataBlock.writeblocks(self.metadata_blocks)

            # Delete ID3v2
            if deleteid3 and header > 4:
                available += header - 4
                header = 4

            if len(data) > available:
                # If we have too much data, see if we can reduce padding.
                padding = self.metadata_blocks[-1]
                newlength = padding.length - (len(data) - available)
                if newlength > 0:
                    padding.length = newlength
                    data = MetadataBlock.writeblocks(self.metadata_blocks)
                    assert len(data) == available

            elif len(data) < available:
                # If we have too little data, increase padding.
                self.metadata_blocks[-1].length += (available - len(data))
                data = MetadataBlock.writeblocks(self.metadata_blocks)
                assert len(data) == available

            if len(data) != available:
                # We couldn't reduce the padding enough.
                diff = (len(data) - available)
                insert_bytes(f, diff, header)

            f.seek(header - 4)
            f.write(b"fLaC" + data)

            # Delete ID3v1
            if deleteid3:
                try:
                    f.seek(-128, 2)
                except IOError:
                    pass
                else:
                    if f.read(3) == b"TAG":
                        f.seek(-128, 2)
                        f.truncate()
        finally:
            f.close()
예제 #21
0
    def load(self, filename, known_frames=None, translate=True, v2_version=4):
        """Load tags from a filename.

        Keyword arguments:

        * filename -- filename to load tag data from
        * known_frames -- dict mapping frame IDs to Frame objects
        * translate -- 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 -- 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)
        """

        if v2_version not in (3, 4):
            raise ValueError("Only 3 and 4 possible for v2_version")

        self.filename = filename
        self.unknown_frames = []
        self.__known_frames = known_frames
        self._header = None

        with mutagen.FileOpener(filename, 'rb') as fileobj:
            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:
                frames = self.__known_frames
                if frames is None:
                    if self.version >= ID3Header._V23:
                        frames = Frames
                    elif self.version >= ID3Header._V22:
                        frames = Frames_2_2

                try:
                    data = _fullread(fileobj, self.size - 10)
                except (ValueError, EOFError, IOError) as e:
                    raise error(e)

                for frame in self.__read_frames(data, frames=frames):
                    if isinstance(frame, Frame):
                        self.add(frame)
                    else:
                        self.unknown_frames.append(frame)
                self.__unknown_version = self.version[:2]

        if translate:
            if v2_version == 3:
                self.update_to_v23()
            else:
                self.update_to_v24()
예제 #22
0
    def save(self, filename=None, v1=1, v2_version=4, v23_sep='/'):
        """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.

        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.
        """

        framedata = self._prepare_framedata(v2_version, v23_sep)
        framesize = len(framedata)

        if not framedata:
            try:
                self.delete(filename)
            except EnvironmentError as err:
                from errno import ENOENT
                if err.errno != ENOENT:
                    raise
            return

        if filename is None:
            filename = self.filename
        try:
            f = mutagen.FileOpener(filename, 'rb+')
        except IOError as err:
            from errno import ENOENT
            if err.errno != ENOENT:
                raise
            f = mutagen.FileOpener(filename, 'ab')  # create, then reopen
            f = mutagen.FileOpener(filename, 'rb+')
        try:
            idata = f.read(10)

            header = self._prepare_id3_header(idata, framesize, v2_version)
            header, outsize, insize = header

            data = header + framedata + (b'\x00' * (outsize - framesize))

            if (insize < outsize):
                insert_bytes(f, outsize - insize, insize + 10)
            f.seek(0)
            f.write(data)

            self.__save_v1(f, v1)

        finally:
            f.close()