Exemplo n.º 1
0
    def __init__(self, comment_strings, vendor_string):
        """comment_strings is a list of unicode strings

        vendor_string is a unicode string"""

        MetaData.__setattr__(self, "comment_strings", comment_strings)
        MetaData.__setattr__(self, "vendor_string", vendor_string)
Exemplo n.º 2
0
    def __setitem__(self, key, values):
        new_values = values[:]
        new_comment_strings = []
        matching_keys = self.ALIASES.get(key.upper(), frozenset([key.upper()]))

        for comment in self.comment_strings:
            if (u"=" in comment):
                (c_key, c_value) = comment.split(u"=", 1)
                if (c_key.upper() in matching_keys):
                    try:
                        # replace current value with newly set value
                        new_comment_strings.append(
                            u"%s=%s" % (c_key, new_values.pop(0)))
                    except IndexError:
                        # no more newly set values, so remove current value
                        continue
                else:
                    # passthrough unmatching values
                    new_comment_strings.append(comment)
            else:
                # passthrough values with no "=" sign
                new_comment_strings.append(comment)

        # append any leftover values
        for new_value in new_values:
            new_comment_strings.append(u"%s=%s" % (key.upper(), new_value))

        MetaData.__setattr__(self, "comment_strings", new_comment_strings)
    def __setitem__(self, key, values):
        from audiotools import PY3
        assert(isinstance(key, str if PY3 else unicode))
        for v in values:
            assert(isinstance(v, str if PY3 else unicode))

        new_values = values[:]
        new_comment_strings = []
        matching_keys = self.ALIASES.get(key.upper(), frozenset([key.upper()]))

        for comment in self.comment_strings:
            if u"=" in comment:
                (c_key, c_value) = comment.split(u"=", 1)
                if c_key.upper() in matching_keys:
                    try:
                        # replace current value with newly set value
                        new_comment_strings.append(
                            u"{}={}".format(c_key, new_values.pop(0)))
                    except IndexError:
                        # no more newly set values, so remove current value
                        continue
                else:
                    # passthrough unmatching values
                    new_comment_strings.append(comment)
            else:
                # passthrough values with no "=" sign
                new_comment_strings.append(comment)

        # append any leftover values
        for new_value in new_values:
            new_comment_strings.append(u"{}={}".format(key.upper(), new_value))

        MetaData.__setattr__(self, "comment_strings", new_comment_strings)
Exemplo n.º 4
0
    def __setitem__(self, key, values):
        from audiotools import PY3
        assert (isinstance(key, str if PY3 else unicode))
        for v in values:
            assert (isinstance(v, str if PY3 else unicode))

        new_values = values[:]
        new_comment_strings = []
        matching_keys = self.ALIASES.get(key.upper(), frozenset([key.upper()]))

        for comment in self.comment_strings:
            if u"=" in comment:
                (c_key, c_value) = comment.split(u"=", 1)
                if c_key.upper() in matching_keys:
                    try:
                        # replace current value with newly set value
                        new_comment_strings.append(u"{}={}".format(
                            c_key, new_values.pop(0)))
                    except IndexError:
                        # no more newly set values, so remove current value
                        continue
                else:
                    # passthrough unmatching values
                    new_comment_strings.append(comment)
            else:
                # passthrough values with no "=" sign
                new_comment_strings.append(comment)

        # append any leftover values
        for new_value in new_values:
            new_comment_strings.append(u"{}={}".format(key.upper(), new_value))

        MetaData.__setattr__(self, "comment_strings", new_comment_strings)
Exemplo n.º 5
0
    def __setattr__(self, attr, value):
        if (attr in self.ATTRIBUTE_MAP):
            if (value is not None):
                import re

                if (attr == 'track_number'):
                    try:
                        self[b'Track'].data = (re.sub(
                            r'\d+', u"%d" % (value),
                            self[b'Track'].__unicode__(), 1).encode("utf-8"))
                    except KeyError:
                        self[b'Track'] = self.ITEM.string(
                            b'Track', __number_pair__(value, self.track_total))
                elif (attr == 'track_total'):
                    try:
                        if (re.search(r'/\D*\d+', self[b'Track'].__unicode__())
                                is not None):
                            self[b'Track'].data = (re.sub(
                                r'(/\D*)(\d+)', u"\\g<1>" + u"%d" % (value),
                                self[b'Track'].__unicode__(),
                                1).encode("utf-8"))
                        else:
                            self[b'Track'].data = (
                                u"%s/%d" % (self[b'Track'].__unicode__(),
                                            value)).encode("utf-8")
                    except KeyError:
                        self[b'Track'] = self.ITEM.string(
                            b'Track', __number_pair__(self.track_number,
                                                      value))
                elif (attr == 'album_number'):
                    try:
                        self[b'Media'].data = (re.sub(
                            r'\d+', u"%d" % (value),
                            self[b'Media'].__unicode__(), 1).encode("utf-8"))
                    except KeyError:
                        self[b'Media'] = self.ITEM.string(
                            b'Media', __number_pair__(value, self.album_total))
                elif (attr == 'album_total'):
                    try:
                        if (re.search(r'/\D*\d+', self[b'Media'].__unicode__())
                                is not None):
                            self[b'Media'].data = (re.sub(
                                r'(/\D*)(\d+)', u"\\g<1>" + u"%d" % (value),
                                self[b'Media'].__unicode__(),
                                1).encode("utf-8"))
                        else:
                            self[b'Media'].data = (
                                u"%s/%d" % (self[b'Media'].__unicode__(),
                                            value)).encode("utf-8")
                    except KeyError:
                        self[b'Media'] = self.ITEM.string(
                            b'Media', __number_pair__(self.album_number,
                                                      value))
                else:
                    self[self.ATTRIBUTE_MAP[attr]] = self.ITEM.string(
                        self.ATTRIBUTE_MAP[attr], value)
            else:
                delattr(self, attr)
        else:
            MetaData.__setattr__(self, attr, value)
Exemplo n.º 6
0
    def metadata(self):
        def get_track_metadata(track_node, album_metadata, track_number):
            try:
                #FIXME - not sure if name or sort-name should take precendence
                artist_name = get_xml_text_node(
                    get_xml_nodes(track_node, u'artist')[0], u'name')
            except IndexError:
                artist_name = album_metadata.artist_name

            track_metadata = MetaData(track_name=get_xml_text_node(
                track_node, u'title'),
                                      artist_name=artist_name,
                                      track_number=track_number)

            track_metadata.merge(album_metadata)
            return track_metadata

        try:
            release = self.dom.getElementsByTagName(u'release')[0]
        except IndexError:
            return AlbumMetaData([])

        album_name = get_xml_text_node(release, u'title')

        try:
            #FIXME - not sure if name or sort-name should take precendence
            artist_name = get_xml_text_node(
                get_xml_nodes(release, u'artist')[0], u'name')
        except IndexError:
            artist_name = u''

        try:
            tracks = get_xml_nodes(
                get_xml_nodes(release, u'track-list')[0], u'track')
        except IndexError:
            tracks = []

        album_metadata = MetaData(album_name=album_name,
                                  artist_name=artist_name,
                                  track_total=len(tracks))

        try:
            release_events = get_xml_nodes(release, u'release-event-list')[0]
            event = get_xml_nodes(release_events, u'event')[-1]
            album_metadata.year = event.getAttribute('date')[0:4]
            album_metadata.catalog = event.getAttribute('catalog-number')
        except IndexError:
            pass

        return AlbumMetaData([
            get_track_metadata(track_node=node,
                               album_metadata=album_metadata,
                               track_number=i + 1)
            for (i, node) in enumerate(tracks)
        ])
 def __init__(self, track_name, artist_name, album_name,
              year, comment, track_number, genre):
     #pre-emptively cut down overlong fields
     MetaData.__init__(self,
                       track_name=track_name[0:30],
                       artist_name=artist_name[0:30],
                       album_name=album_name[0:30],
                       year=year[0:4],
                       comment=comment[0:28],
                       track_number=track_number)
     self.__dict__['genre'] = genre
Exemplo n.º 8
0
    def __setattr__(self, attr, value):
        if (attr in self.ATTRIBUTE_MAP):
            if (value is not None):
                import re

                if (attr == 'track_number'):
                    try:
                        self['Track'].data = re.sub(r'\d+', str(int(value)),
                                                    self['Track'].data, 1)
                    except KeyError:
                        self['Track'] = self.ITEM.string(
                            'Track', __number_pair__(value, self.track_total))
                elif (attr == 'track_total'):
                    try:
                        if (re.search(r'/\D*\d+', self['Track'].data)
                                is not None):
                            self['Track'].data = re.sub(
                                r'(/\D*)(\d+)', "\\g<1>" + str(int(value)),
                                self['Track'].data, 1)
                        else:
                            self['Track'].data = "%s/%d" % (self['Track'].data,
                                                            value)
                    except KeyError:
                        self['Track'] = self.ITEM.string(
                            'Track', __number_pair__(self.track_number, value))
                elif (attr == 'album_number'):
                    try:
                        self['Media'].data = re.sub(r'\d+', str(int(value)),
                                                    self['Media'].data, 1)
                    except KeyError:
                        self['Media'] = self.ITEM.string(
                            'Media', __number_pair__(value, self.album_total))
                elif (attr == 'album_total'):
                    try:
                        if (re.search(r'/\D*\d+', self['Media'].data)
                                is not None):
                            self['Media'].data = re.sub(
                                r'(/\D*)(\d+)', "\\g<1>" + str(int(value)),
                                self['Media'].data, 1)
                        else:
                            self['Media'].data = "%s/%d" % (self['Media'].data,
                                                            value)
                    except KeyError:
                        self['Media'] = self.ITEM.string(
                            'Media', __number_pair__(self.album_number, value))
                else:
                    self[self.ATTRIBUTE_MAP[attr]] = self.ITEM.string(
                        self.ATTRIBUTE_MAP[attr], value)
            else:
                delattr(self, attr)
        else:
            MetaData.__setattr__(self, attr, value)
    def __init__(self, comment_strings, vendor_string):
        """comment_strings is a list of unicode strings

        vendor_string is a unicode string"""

        from audiotools import PY3

        # some debug type checking
        for s in comment_strings:
            assert(isinstance(s, str if PY3 else unicode))
        assert(isinstance(vendor_string, str if PY3 else unicode))

        MetaData.__setattr__(self, "comment_strings", comment_strings)
        MetaData.__setattr__(self, "vendor_string", vendor_string)
Exemplo n.º 10
0
    def __init__(self, track_name, artist_name, album_name, year, comment, track_number, genre):
        """all fields except track_number are binary strings"""

        # pre-emptively cut down overlong fields
        MetaData.__init__(
            self,
            track_name=track_name[0:30],
            artist_name=artist_name[0:30],
            album_name=album_name[0:30],
            year=year[0:4],
            comment=comment[0:28],
            track_number=track_number,
        )
        self.__dict__["genre"] = genre
Exemplo n.º 11
0
    def __init__(self, comment_strings, vendor_string):
        """comment_strings is a list of unicode strings

        vendor_string is a unicode string"""

        from audiotools import PY3

        # some debug type checking
        for s in comment_strings:
            assert (isinstance(s, str if PY3 else unicode))
        assert (isinstance(vendor_string, str if PY3 else unicode))

        MetaData.__setattr__(self, "comment_strings", comment_strings)
        MetaData.__setattr__(self, "vendor_string", vendor_string)
Exemplo n.º 12
0
        def get_track_metadata(track_node, album_metadata, track_number):
            try:
                #FIXME - not sure if name or sort-name should take precendence
                artist_name = get_xml_text_node(
                    get_xml_nodes(track_node, u'artist')[0], u'name')
            except IndexError:
                artist_name = album_metadata.artist_name

            track_metadata = MetaData(track_name=get_xml_text_node(
                track_node, u'title'),
                                      artist_name=artist_name,
                                      track_number=track_number)

            track_metadata.merge(album_metadata)
            return track_metadata
Exemplo n.º 13
0
    def __delitem__(self, key):
        new_comment_strings = []
        matching_keys = self.ALIASES.get(key.upper(), frozenset([key.upper()]))

        for comment in self.comment_strings:
            if (u"=" in comment):
                (c_key, c_value) = comment.split(u"=", 1)
                if (c_key.upper() not in matching_keys):
                    # passthrough unmatching values
                    new_comment_strings.append(comment)
            else:
                # passthrough values with no "=" sign
                new_comment_strings.append(comment)

        MetaData.__setattr__(self, "comment_strings", new_comment_strings)
Exemplo n.º 14
0
    def intersection(self, metadata):
        """given a MetaData-compatible object,
        returns a new MetaData object which contains
        all the matching fields and images of this object and 'metadata'
        """
        def comment_present(comment):
            if u"=" in comment:
                key, value = comment.split(u"=", 1)
                try:
                    for other_value in metadata[key]:
                        if value == other_value:
                            return True
                    else:
                        return False
                except KeyError:
                    return False
            else:
                for other_comment in metadata.comment_strings:
                    if comment == other_comment:
                        return True
                else:
                    return False

        if isinstance(metadata, VorbisComment):
            return self.__class__([
                comment
                for comment in self.comment_strings if comment_present(comment)
            ], self.vendor_string)
        else:
            return MetaData.intersection(self, metadata)
    def intersection(self, metadata):
        """given a MetaData-compatible object,
        returns a new MetaData object which contains
        all the matching fields and images of this object and 'metadata'
        """

        def comment_present(comment):
            if u"=" in comment:
                key, value = comment.split(u"=", 1)
                try:
                    for other_value in metadata[key]:
                        if value == other_value:
                            return True
                    else:
                        return False
                except KeyError:
                    return False
            else:
                for other_comment in metadata.comment_strings:
                    if comment == other_comment:
                        return True
                else:
                    return False

        if isinstance(metadata, VorbisComment):
            return self.__class__([comment
                                   for comment in self.comment_strings
                                   if comment_present(comment)],
                                  self.vendor_string)
        else:
            return MetaData.intersection(self, metadata)
Exemplo n.º 16
0
    def __delattr__(self, attr):
        import re

        def zero_number(unicode_value):
            return re.sub(r'\d+', u"0", unicode_value, 1)

        if attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]

            if attr in {'track_number', 'album_number'}:
                try:
                    tag = self[key]
                    if tag.total() is None:
                        # if no slashed _total field, delete entire tag
                        del(self[key])
                    else:
                        # otherwise replace initial portion with 0
                        self[key] = self.ITEM.string(
                            key, zero_number(tag.__unicode__()))
                except KeyError:
                    # no tag to delete
                    pass
            elif attr in {'track_total', 'album_total'}:
                try:
                    tag = self[key]
                    if tag.total() is not None:
                        if tag.number() is not None:
                            self[key] = self.ITEM.string(
                                key,
                                tag.__unicode__().split(u"/", 1)[0].rstrip())
                        else:
                            del(self[key])
                    else:
                        # no total portion, so nothing to do
                        pass
                except KeyError:
                    # no tag to delete portion of
                    pass
            else:
                try:
                    del(self[key])
                except KeyError:
                    pass
        elif attr in MetaData.FIELDS:
            pass
        else:
            MetaData.__delattr__(self, attr)
Exemplo n.º 17
0
    def __delattr__(self, attr):
        import re

        def zero_number(unicode_value):
            return re.sub(r'\d+', u"0", unicode_value, 1)

        if attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]

            if attr in {'track_number', 'album_number'}:
                try:
                    tag = self[key]
                    if tag.total() is None:
                        # if no slashed _total field, delete entire tag
                        del(self[key])
                    else:
                        # otherwise replace initial portion with 0
                        self[key] = self.ITEM.string(
                            key, zero_number(tag.__unicode__()))
                except KeyError:
                    # no tag to delete
                    pass
            elif attr in {'track_total', 'album_total'}:
                try:
                    tag = self[key]
                    if tag.total() is not None:
                        if tag.number() is not None:
                            self[key] = self.ITEM.string(
                                key,
                                tag.__unicode__().split(u"/", 1)[0].rstrip())
                        else:
                            del(self[key])
                    else:
                        # no total portion, so nothing to do
                        pass
                except KeyError:
                    # no tag to delete portion of
                    pass
            else:
                try:
                    del(self[key])
                except KeyError:
                    pass
        elif attr in MetaData.FIELDS:
            pass
        else:
            MetaData.__delattr__(self, attr)
Exemplo n.º 18
0
    def __getattr__(self, attr):
        # returns the first matching key for the given attribute
        # in our list of comment strings

        if ((attr == "track_number") or (attr == "album_number")):
            try:
                # get the TRACKNUMBER/DISCNUMBER values
                # return the first value that contains an integer
                for value in self[self.ATTRIBUTE_MAP[attr]]:
                    integer = re.search(r'\d+', value)
                    if (integer is not None):
                        return int(integer.group(0))
                else:
                    # otherwise, return None
                    return None
            except KeyError:
                # if no TRACKNUMBER/DISCNUMBER, return None
                return None
        elif ((attr == "track_total") or (attr == "album_total")):
            try:
                # get the TRACKTOTAL/DISCTOTAL values
                # return the first value that contains an integer
                for value in self[self.ATTRIBUTE_MAP[attr]]:
                    integer = re.search(r'\d+', value)
                    if (integer is not None):
                        return int(integer.group(0))
            except KeyError:
                pass

            # if no TRACKTOTAL/DISCTOTAL,
            # or none of them contain an integer,
            # look for slashed TRACKNUMBER/DISCNUMBER values
            try:
                for value in self[{
                        "track_total": u"TRACKNUMBER",
                        "album_total": u"DISCNUMBER"
                }[attr]]:
                    integer = re.search(r'/\D*(\d+)', value)
                    if (integer is not None):
                        return int(integer.group(1))
            except KeyError:
                # no slashed TRACKNUMBER/DISCNUMBER values either
                # so return None
                return None
        elif (attr in self.ATTRIBUTE_MAP):
            # attribute is supported by VorbisComment
            try:
                # if present, return the first value
                return self[self.ATTRIBUTE_MAP[attr]][0]
            except KeyError:
                # if not present, return None
                return None
        elif (attr in self.FIELDS):
            # attribute is supported by MetaData
            # but not supported by VorbisComment
            return None
        else:
            # attribute is not MetaData-specific
            return MetaData.__getattribute__(self, attr)
    def to_disc_metadata(self):
        from audiotools import MetaData

        return MetaData(album_name=self.get(u"TITLE", None),
                        performer_name=self.get(u"PERFORMER", None),
                        artist_name=self.get(u"SONGWRITER", None),
                        composer_name=self.get(u"COMPOSER", None),
                        comment=self.get(u"MESSAGE", None))
Exemplo n.º 20
0
    def __delitem__(self, key):
        from audiotools import PY3
        assert (isinstance(key, str if PY3 else unicode))

        new_comment_strings = []
        matching_keys = self.ALIASES.get(key.upper(), frozenset([key.upper()]))

        for comment in self.comment_strings:
            if u"=" in comment:
                (c_key, c_value) = comment.split(u"=", 1)
                if c_key.upper() not in matching_keys:
                    # passthrough unmatching values
                    new_comment_strings.append(comment)
            else:
                # passthrough values with no "=" sign
                new_comment_strings.append(comment)

        MetaData.__setattr__(self, "comment_strings", new_comment_strings)
Exemplo n.º 21
0
    def metadata_audiotools(self, path, media):

        from audiotools import MetaData
        import audiotools

        meta = MetaData()

        # release-level metadata
        if media.release and media.release.main_image:

            if meta.supports_images() and os.path.exists(media.release.main_image.path):
                opt = dict(size=(200, 200), crop=True, bw=False, quality=80)
                image = get_thumbnailer(media.release.main_image).get_thumbnail(opt)
                meta.add_image(get_raw_image(image.path, 0))

        audiotools.open(path).update_metadata(meta)

        return
Exemplo n.º 22
0
    def delete_metadata(self):
        """deletes the track's MetaData

        this removes or unsets tags as necessary in order to remove all data
        raises IOError if unable to write the file"""

        from audiotools import MetaData

        self.set_metadata(MetaData())
    def __delitem__(self, key):
        from audiotools import PY3
        assert(isinstance(key, str if PY3 else unicode))

        new_comment_strings = []
        matching_keys = self.ALIASES.get(key.upper(), frozenset([key.upper()]))

        for comment in self.comment_strings:
            if u"=" in comment:
                (c_key, c_value) = comment.split(u"=", 1)
                if c_key.upper() not in matching_keys:
                    # passthrough unmatching values
                    new_comment_strings.append(comment)
            else:
                # passthrough values with no "=" sign
                new_comment_strings.append(comment)

        MetaData.__setattr__(self, "comment_strings", new_comment_strings)
Exemplo n.º 24
0
    def to_track_metadata(self):
        from audiotools import MetaData

        return MetaData(
            track_name=decode_string(self.get("TITLE", None)),
            performer_name=decode_string(self.get("PERFORMER", None)),
            artist_name=decode_string(self.get("SONGWRITER", None)),
            composer_name=decode_string(self.get("COMPOSER", None)),
            comment=decode_string(self.get("MESSAGE", None)),
            ISRC=decode_string(self.get("ISRC", None)))
Exemplo n.º 25
0
    def delete_metadata(self):
        """deletes the track's MetaData

        raises IOError if unable to write the file"""

        if ((self.get_replay_gain() is not None) or
            (self.get_cuesheet() is not None)):
            # non-textual metadata is present and needs preserving
            self.set_metadata(MetaData())
        else:
            # no non-textual metadata, so wipe out the entire block
            from os import access, R_OK, W_OK
            from audiotools.bitstream import BitstreamReader
            from audiotools import transfer_data

            if not access(self.filename, R_OK | W_OK):
                raise IOError(self.filename)

            with open(self.filename, "rb") as f:
                f.seek(-32, 2)

                (preamble,
                 version,
                 tag_size,
                 item_count,
                 read_only,
                 item_encoding,
                 is_header,
                 no_footer,
                 has_header) = BitstreamReader(f, True).parse(
                    ApeTag.HEADER_FORMAT)

            if (preamble == b'APETAGEX') and (version == 2000):
                from audiotools import TemporaryFile
                from os.path import getsize

                # there's existing metadata to delete
                # so rewrite file without trailing metadata tag
                if has_header:
                    old_tag_size = 32 + tag_size
                else:
                    old_tag_size = tag_size

                # copy everything but the last "old_tag_size" bytes
                # from existing file to rewritten file
                new_apev2 = TemporaryFile(self.filename)
                old_apev2 = open(self.filename, "rb")

                limited_transfer_data(
                    old_apev2.read,
                    new_apev2.write,
                    getsize(self.filename) - old_tag_size)

                old_apev2.close()
                new_apev2.close()
Exemplo n.º 26
0
    def delete_metadata(self):
        """deletes the track's MetaData

        this removes or unsets tags as necessary in order to remove all data
        raises IOError if unable to write the file"""

        from audiotools import MetaData

        # the vorbis comment packet is required,
        # so simply zero out its contents
        self.set_metadata(MetaData())
Exemplo n.º 27
0
    def from_cuesheet(cls, cuesheet, total_frames, sample_rate, metadata=None):
        if (metadata is None):
            metadata = MetaData()

        return cls.from_files([
            DummyAudioFile(length=(pcm_frames * 75) / sample_rate,
                           metadata=metadata,
                           track_number=i + 1)
            for (i,
                 pcm_frames) in enumerate(cuesheet.pcm_lengths(total_frames))
        ])
Exemplo n.º 28
0
    def __setattr__(self, attr, value):
        def swap_number(unicode_value, new_number):
            import re

            return re.sub(r'\d+', u"%d" % (new_number), unicode_value, 1)

        def swap_slashed_number(unicode_value, new_number):
            if u"/" in unicode_value:
                (first, second) = unicode_value.split(u"/", 1)
                return u"/".join([first, swap_number(second, new_number)])
            else:
                return u"/".join([unicode_value, u"%d" % (new_number)])

        if attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]
            if value is not None:
                if attr in {'track_number', 'album_number'}:
                    try:
                        current_value = self[key].__unicode__()
                        self[key] = self.ITEM.string(
                            key, swap_number(current_value, value))
                    except KeyError:
                        self[key] = self.ITEM.string(
                            key, __number_pair__(value, None))
                elif attr in {'track_total', 'album_total'}:
                    try:
                        current_value = self[key].__unicode__()
                        self[key] = self.ITEM.string(
                            key, swap_slashed_number(current_value, value))
                    except KeyError:
                        self[key] = self.ITEM.string(
                            key, __number_pair__(None, value))
                elif attr == 'compilation':
                    self[key] = self.ITEM.string(key,
                                                 u"%d" % (1 if value else 0))
                else:
                    self[key] = self.ITEM.string(key, value)
            else:
                delattr(self, attr)
        else:
            MetaData.__setattr__(self, attr, value)
Exemplo n.º 29
0
    def __setattr__(self, attr, value):
        def swap_number(unicode_value, new_number):
            import re

            return re.sub(r'\d+', u"{:d}".format(new_number), unicode_value, 1)

        def swap_slashed_number(unicode_value, new_number):
            if u"/" in unicode_value:
                (first, second) = unicode_value.split(u"/", 1)
                return u"/".join([first, swap_number(second, new_number)])
            else:
                return u"/".join([unicode_value, u"{:d}".format(new_number)])

        if attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]
            if value is not None:
                if attr in {'track_number', 'album_number'}:
                    try:
                        current_value = self[key].__unicode__()
                        self[key] = self.ITEM.string(
                            key, swap_number(current_value, value))
                    except KeyError:
                        self[key] = self.ITEM.string(
                            key, __number_pair__(value, None))
                elif attr in {'track_total', 'album_total'}:
                    try:
                        current_value = self[key].__unicode__()
                        self[key] = self.ITEM.string(
                            key, swap_slashed_number(current_value, value))
                    except KeyError:
                        self[key] = self.ITEM.string(
                            key, __number_pair__(None, value))
                elif attr == 'compilation':
                    self[key] = self.ITEM.string(
                        key, u"{:d}".format(1 if value else 0))
                else:
                    self[key] = self.ITEM.string(key, value)
            else:
                delattr(self, attr)
        else:
            MetaData.__setattr__(self, attr, value)
Exemplo n.º 30
0
    def __init__(self, tags, contains_header=True, contains_footer=True):
        """constructs an ApeTag from a list of ApeTagItem objects"""

        for tag in tags:
            assert(isinstance(tag, ApeTagItem))
        MetaData.__setattr__(self, "tags", list(tags))
        MetaData.__setattr__(self, "contains_header", contains_header)
        MetaData.__setattr__(self, "contains_footer", contains_footer)
Exemplo n.º 31
0
    def __init__(self, tags, contains_header=True, contains_footer=True):
        """constructs an ApeTag from a list of ApeTagItem objects"""

        for tag in tags:
            assert(isinstance(tag, ApeTagItem))
        MetaData.__setattr__(self, "tags", list(tags))
        MetaData.__setattr__(self, "contains_header", contains_header)
        MetaData.__setattr__(self, "contains_footer", contains_footer)
Exemplo n.º 32
0
    def __init__(self, tags, contains_header=True, contains_footer=True):
        """constructs an ApeTag from a list of ApeTagItem objects"""

        for tag in tags:
            if (not isinstance(tag, ApeTagItem)):
                raise ValueError("%s is not ApeTag" % (repr(tag)))
        MetaData.__setattr__(self, "tags", list(tags))
        MetaData.__setattr__(self, "contains_header", contains_header)
        MetaData.__setattr__(self, "contains_footer", contains_footer)
Exemplo n.º 33
0
    def __init__(self, tags, contains_header=True, contains_footer=True):
        """constructs an ApeTag from a list of ApeTagItem objects"""

        for tag in tags:
            if (not isinstance(tag, ApeTagItem)):
                raise ValueError("%s is not ApeTag" % (repr(tag)))
        MetaData.__setattr__(self, "tags", list(tags))
        MetaData.__setattr__(self, "contains_header", contains_header)
        MetaData.__setattr__(self, "contains_footer", contains_footer)
Exemplo n.º 34
0
 def __getattr__(self, attr):
     if attr in self.ATTRIBUTE_MAP:
         try:
             if attr in {'track_number', 'album_number'}:
                 return self[self.ATTRIBUTE_MAP[attr]].number()
             elif attr in {'track_total', 'album_total'}:
                 return self[self.ATTRIBUTE_MAP[attr]].total()
             else:
                 return self[self.ATTRIBUTE_MAP[attr]].__unicode__()
         except KeyError:
             return None
     elif attr in MetaData.FIELDS:
         return None
     else:
         return MetaData.__getattribute__(self, attr)
Exemplo n.º 35
0
    def intersection(self, metadata):
        """given a MetaData-compatible object,
        returns a new MetaData object which contains
        all the matching fields and images of this object and 'metadata'
        """

        if type(metadata) is ID3v1Comment:
            return ID3v1Comment(
                genre=(self.__genre__ if
                       self.__genre__ == metadata.__genre__ else 0),
                **{arg: getattr(self, field)
                   for arg, field in ID3v1Comment.ID3v1_FIELDS.items()
                   if getattr(self, field) == getattr(metadata, field)})
        else:
            return MetaData.intersection(self, metadata)
Exemplo n.º 36
0
 def __delattr__(self, attr):
     if attr == "track_number":
         MetaData.__setattr__(self, "__track_number__", 0)
     elif attr in self.FIELD_LENGTHS:
         MetaData.__setattr__(self, self.ID3v1_FIELDS[attr], u"")
     elif attr in self.FIELDS:
         # field not supported by ID3v1Comment, so ignore it
         pass
     else:
         MetaData.__delattr__(self, attr)
Exemplo n.º 37
0
 def __delattr__(self, attr):
     if (attr == "track_number"):
         MetaData.__setattr__(self, "__track_number__", chr(0))
     elif (attr in self.FIELD_LENGTHS):
         MetaData.__setattr__(self, self.ID3v1_FIELDS[attr],
                              chr(0) * self.FIELD_LENGTHS[attr])
     elif (attr in self.FIELDS):
         # field not supported by ID3v1Comment, so ignore it
         pass
     else:
         MetaData.__delattr__(self, attr)
Exemplo n.º 38
0
 def __getattr__(self, attr):
     if attr == "track_number":
         number = self.__track_number__
         if number > 0:
             return number
         else:
             return None
     elif attr in self.ID3v1_FIELDS:
         value = getattr(self, self.ID3v1_FIELDS[attr])
         if len(value) > 0:
             return value
         else:
             return None
     elif attr in self.FIELDS:
         return None
     else:
         return MetaData.__getattribute__(self, attr)
Exemplo n.º 39
0
    def intersection(self, metadata):
        """given a MetaData-compatible object,
        returns a new MetaData object which contains
        all the matching fields and images of this object and 'metadata'
        """

        if type(metadata) is ID3v1Comment:
            return ID3v1Comment(
                genre=(self.__genre__
                       if self.__genre__ == metadata.__genre__ else 0),
                **{
                    arg: getattr(self, field)
                    for arg, field in ID3v1Comment.ID3v1_FIELDS.items()
                    if getattr(self, field) == getattr(metadata, field)
                })
        else:
            return MetaData.intersection(self, metadata)
Exemplo n.º 40
0
    def __unicode__(self):
        if ('Cuesheet' not in self.keys()):
            return ApeTag.__unicode__(self)
        else:
            import cue

            try:
                return u"%s%sCuesheet:\n%s" % \
                    (MetaData.__unicode__(self),
                     os.linesep * 2,
                     sheet_to_unicode(
                            cue.parse(
                                cue.tokens(unicode(self['Cuesheet']).encode(
                                        'ascii', 'replace'))),
                            self.frame_count))
            except cue.CueException:
                return ApeTag.__unicode__(self)
Exemplo n.º 41
0
 def __getattr__(self, attr):
     if attr == "track_number":
         number = self.__track_number__
         if number > 0:
             return number
         else:
             return None
     elif attr in self.ID3v1_FIELDS:
         value = getattr(self, self.ID3v1_FIELDS[attr])
         if len(value) > 0:
             return value
         else:
             return None
     elif attr in self.FIELDS:
         return None
     else:
         return MetaData.__getattribute__(self, attr)
Exemplo n.º 42
0
    def __eq__(self, metadata):
        if (isinstance(metadata, ApeTag)):
            if (set(self.keys()) != set(metadata.keys())):
                return False

            for tag in self.tags:
                try:
                    if (tag.data != metadata[tag.key].data):
                        return False
                except KeyError:
                    return False
            else:
                return True
        elif (isinstance(metadata, MetaData)):
            return MetaData.__eq__(self, metadata)
        else:
            return False
    def get_metadata(self):
        """returns MetaData of Sheet, or None
        this metadata often contains information such as catalog number
        or CD-TEXT values"""

        from audiotools import MetaData

        if (self.__catalog__ is not None) and (self.__cd_text__ is not None):
            metadata = self.__cd_text__.to_disc_metadata()
            metadata.catalog = self.__catalog__
            return metadata
        elif self.__catalog__ is not None:
            return MetaData(catalog=self.__catalog__)
        elif self.__cd_text__ is not None:
            return self.__cd_text__.to_disc_metadata()
        else:
            return None
Exemplo n.º 44
0
    def __unicode__(self):
        if ('Cuesheet' not in self.keys()):
            return ApeTag.__unicode__(self)
        else:
            import cue

            try:
                return u"%s%sCuesheet:\n%s" % \
                    (MetaData.__unicode__(self),
                     os.linesep * 2,
                     sheet_to_unicode(
                            cue.parse(
                                cue.tokens(unicode(self['Cuesheet']).encode(
                                        'ascii', 'replace'))),
                            self.frame_count))
            except cue.CueException:
                return ApeTag.__unicode__(self)
    def get_metadata(self):
        """returns SheetTrack's MetaData, or None"""

        from audiotools import MetaData

        isrc = self.first_flag(TOCFlag_ISRC)
        cd_text = self.first_flag(CDText)
        if (isrc is not None) and (cd_text is not None):
            metadata = cd_text.to_track_metadata()
            metadata.ISRC = decode_string(isrc.isrc())
            return metadata
        elif cd_text is not None:
            return cd_text.to_track_metadata()
        elif isrc is not None:
            return MetaData(ISRC=decode_string(isrc.isrc()))
        else:
            return None
Exemplo n.º 46
0
    def __eq__(self, metadata):
        if (isinstance(metadata, ApeTag)):
            if (set(self.keys()) != set(metadata.keys())):
                return False

            for tag in self.tags:
                try:
                    if (tag.data != metadata[tag.key].data):
                        return False
                except KeyError:
                    return False
            else:
                return True
        elif (isinstance(metadata, MetaData)):
            return MetaData.__eq__(self, metadata)
        else:
            return False
Exemplo n.º 47
0
 def __delattr__(self, attr):
     if attr == "track_number":
         MetaData.__setattr__(self, "__track_number__", 0)
     elif attr in self.FIELD_LENGTHS:
         MetaData.__setattr__(self,
                              self.ID3v1_FIELDS[attr],
                              u"")
     elif attr in self.FIELDS:
         # field not supported by ID3v1Comment, so ignore it
         pass
     else:
         MetaData.__delattr__(self, attr)
Exemplo n.º 48
0
 def __delattr__(self, attr):
     if (attr == "track_number"):
         MetaData.__setattr__(self, "__track_number__", chr(0))
     elif (attr in self.FIELD_LENGTHS):
         MetaData.__setattr__(self,
                              self.ID3v1_FIELDS[attr],
                              chr(0) * self.FIELD_LENGTHS[attr])
     elif (attr in self.FIELDS):
         # field not supported by ID3v1Comment, so ignore it
         pass
     else:
         MetaData.__delattr__(self, attr)
Exemplo n.º 49
0
    def intersection(self, metadata):
        """given a MetaData-compatible object,
        returns a new MetaData object which contains
        all the matching fields and images of this object and 'metadata'
        """

        if type(metadata) is ApeTag:
            matching_keys = {key for key in
                             set(self.keys()) & set(metadata.keys())
                             if self[key] == metadata[key]}

            return ApeTag(
                [tag.copy() for tag in self.tags
                 if tag.key in matching_keys],
                contains_header=self.contains_header or
                                metadata.contains_header,
                contains_footer=self.contains_footer or
                                metadata.contains_footer)
        else:
            return MetaData.intersection(self, metadata)
Exemplo n.º 50
0
 def __getattr__(self, attr):
     if (attr == "track_number"):
         number = ord(self.__track_number__)
         if (number > 0):
             return number
         else:
             return None
     elif (attr in self.ID3v1_FIELDS):
         value = getattr(
             self,
             self.ID3v1_FIELDS[attr]).rstrip(chr(0)).decode('ascii',
                                                            'replace')
         if (len(value) > 0):
             return value
         else:
             return None
     elif (attr in self.FIELDS):
         return None
     else:
         return MetaData.__getattribute__(self, attr)
Exemplo n.º 51
0
 def __setattr__(self, attr, value):
     if attr == "track_number":
         MetaData.__setattr__(
             self,
             "__track_number__",
             min(0 if (value is None) else int(value), 0xFF))
     elif attr in self.FIELD_LENGTHS:
         if value is None:
             delattr(self, attr)
         else:
             # all are text fields
             MetaData.__setattr__(
                 self,
                 self.ID3v1_FIELDS[attr],
                 value[0:self.FIELD_LENGTHS[attr]])
     elif attr in self.FIELDS:
         # field not supported by ID3v1Comment, so ignore it
         pass
     else:
         MetaData.__setattr__(self, attr, value)
    def __setattr__(self, attr, value):
        # updates the first matching field for the given attribute
        # in our list of comment strings

        def has_number(unicode_string):
            import re

            return re.search(r'\d+', unicode_string) is not None

        def swap_number(unicode_value, new_number):
            import re

            return re.sub(r'\d+', u"{:d}".format(new_number), unicode_value, 1)

        if (attr in self.FIELDS) and (value is None):
            # setting any value to None is equivilent to deleting it
            # in this high-level implementation
            delattr(self, attr)
        elif attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]

            if attr in {'track_number', 'album_number'}:
                try:
                    current_values = self[key]
                    for i in range(len(current_values)):
                        current_value = current_values[i]
                        if u"/" not in current_value:
                            if has_number(current_value):
                                current_values[i] = swap_number(current_value,
                                                                value)
                                self[key] = current_values
                                break
                        else:
                            (first, second) = current_value.split(u"/", 1)
                            if has_number(first):
                                current_values[i] = u"/".join(
                                    [swap_number(first, value), second])
                                self[key] = current_values
                                break
                    else:
                        # no integer field matching key, so add new one
                        self[key] = current_values + [u"{:d}".format(value)]
                except KeyError:
                    # no current field with key, so add new one
                    self[key] = [u"{:d}".format(value)]
            elif attr in {'track_total', 'album_total'}:
                # look for standalone TRACKTOTAL/DISCTOTAL field
                try:
                    current_values = self[key]

                    for i in range(len(current_values)):
                        current_value = current_values[i]
                        if has_number(current_value):
                            current_values[i] = swap_number(current_value,
                                                            value)
                            self[key] = current_values
                            return
                except KeyError:
                    current_values = []

                # no TRACKTOTAL/DISCTOTAL field
                # or none of them contain an integer,
                # so look for slashed TRACKNUMBER/DISCNUMBER values
                try:
                    new_key = {"track_total": u"TRACKNUMBER",
                               "album_total": u"DISCNUMBER"}[attr]
                    slashed_values = self[new_key]

                    for i in range(len(slashed_values)):
                        current_value = slashed_values[i]
                        if u"/" in current_value:
                            (first, second) = current_value.split(u"/", 1)
                            if has_number(second):
                                slashed_values[i] = u"/".join(
                                    [first, swap_number(second, value)])
                                self[new_key] = slashed_values
                                return
                except KeyError:
                    # no TRACKNUMBER/DISCNUMBER field found
                    pass

                # no slashed TRACKNUMBER/DISCNUMBER values either
                # so append a TRACKTOTAL/DISCTOTAL field
                self[key] = current_values + [u"{:d}".format(value)]
            elif attr == "compilation":
                self[key] = [u"1" if value else u"0"]
            else:
                # leave subsequent fields with the same key as-is
                try:
                    current_values = self[key]
                    self[key] = [value] + current_values[1:]
                except KeyError:
                    # no current field with key, so add new one
                    self[key] = [value]
        elif attr in self.FIELDS:
            # attribute is supported by MetaData
            # but not supported by VorbisComment
            # so ignore it
            pass
        else:
            # attribute is not MetaData-specific, so set as-is
            MetaData.__setattr__(self, attr, value)
Exemplo n.º 53
0
    def __delattr__(self, attr):
        import re

        if (attr == 'track_number'):
            try:
                # if "Track" field contains a slashed total
                if (re.search(r'\d+.*?/.*?\d+',
                              self['Track'].data) is not None):
                    # replace unslashed portion with 0
                    self['Track'].data = re.sub(r'\d+',
                                                str(int(0)),
                                                self['Track'].data,
                                                1)
                else:
                    # otherwise, remove "Track" field
                    del(self['Track'])
            except KeyError:
                pass
        elif (attr == 'track_total'):
            try:
                track_number = re.search(r'\d+',
                                         self["Track"].data.split("/")[0])
                # if track number is nonzero
                if (((track_number is not None) and
                     (int(track_number.group(0)) != 0))):
                    # if "Track" field contains a slashed total
                    # remove slashed total from "Track" field
                    self['Track'].data = re.sub(r'\s*/.*',
                                                "",
                                                self['Track'].data)
                else:
                    # if "Track" field contains a slashed total
                    if (re.search(r'/\D*?\d+',
                                  self['Track'].data) is not None):
                        # remove "Track" field entirely
                        del(self['Track'])
            except KeyError:
                pass
        elif (attr == 'album_number'):
            try:
                # if "Media" field contains a slashed total
                if (re.search(r'\d+.*?/.*?\d+',
                              self['Media'].data) is not None):
                    # replace unslashed portion with 0
                    self['Media'].data = re.sub(r'\d+',
                                                str(int(0)),
                                                self['Media'].data,
                                                1)
                else:
                    # otherwise, remove "Media" field
                    del(self['Media'])
            except KeyError:
                pass
        elif (attr == 'album_total'):
            try:
                album_number = re.search(r'\d+',
                                         self["Media"].data.split("/")[0])
                # if album number is nonzero
                if (((album_number is not None) and
                     (int(album_number.group(0)) != 0))):
                    # if "Media" field contains a slashed total
                    # remove slashed total from "Media" field
                    self['Media'].data = re.sub(r'\s*/.*',
                                                "",
                                                self['Media'].data)
                else:
                    # if "Media" field contains a slashed total
                    if (re.search(r'/\D*?\d+',
                                  self['Media'].data) is not None):
                        # remove "Media" field entirely
                        del(self['Media'])
            except KeyError:
                pass
        elif (attr in self.ATTRIBUTE_MAP):
            try:
                del(self[self.ATTRIBUTE_MAP[attr]])
            except KeyError:
                pass
        elif (attr in MetaData.FIELDS):
            pass
        else:
            MetaData.__delattr__(self, attr)
Exemplo n.º 54
0
    def __init__(self, track_name=u"",
                 artist_name=u"",
                 album_name=u"",
                 year=u"",
                 comment=u"",
                 track_number=0,
                 genre=0):
        """fields are as follows:

        | field        | length |
        |--------------+--------|
        | track_name   |     30 |
        | artist_name  |     30 |
        | album_name   |     30 |
        | year         |      4 |
        | comment      |     28 |
        | track_number |      1 |
        | genre        |      1 |
        |--------------+--------|

        track_name, artist_name, album_name, year and
        comment are unicode strings

        track_number and genre are integers
        """

        if len(track_name) > 30:
            raise ValueError("track_name cannot be longer than 30 characters")
        if len(artist_name) > 30:
            raise ValueError("artist_name cannot be longer than 30 characters")
        if len(album_name) > 30:
            raise ValueError("album_name cannot be longer than 30 characters")
        if len(year) > 4:
            raise ValueError("year cannot be longer than 4 characters")
        if len(comment) > 28:
            raise ValueError("comment cannot be longer than 28 characters")

        MetaData.__setattr__(self, "__track_name__", track_name)
        MetaData.__setattr__(self, "__artist_name__", artist_name)
        MetaData.__setattr__(self, "__album_name__", album_name)
        MetaData.__setattr__(self, "__year__", year)
        MetaData.__setattr__(self, "__comment__", comment)
        MetaData.__setattr__(self, "__track_number__", track_number)
        MetaData.__setattr__(self, "__genre__", genre)
 def __eq__(self, metadata):
     if isinstance(metadata, self.__class__):
         return self.comment_strings == metadata.comment_strings
     else:
         return MetaData.__eq__(self, metadata)
Exemplo n.º 56
0
    def __setattr__(self, attr, value):
        if (attr in self.ATTRIBUTE_MAP):
            if (value is not None):
                import re

                if (attr == 'track_number'):
                    try:
                        self['Track'].data = re.sub(r'\d+',
                                                    str(int(value)),
                                                    self['Track'].data,
                                                    1)
                    except KeyError:
                        self['Track'] = self.ITEM.string(
                            'Track', __number_pair__(value, self.track_total))
                elif (attr == 'track_total'):
                    try:
                        if (re.search(r'/\D*\d+',
                                      self['Track'].data) is not None):
                            self['Track'].data = re.sub(
                                r'(/\D*)(\d+)',
                                "\\g<1>" + str(int(value)),
                                self['Track'].data,
                                1)
                        else:
                            self['Track'].data = "%s/%d" % (
                                self['Track'].data,
                                value)
                    except KeyError:
                        self['Track'] = self.ITEM.string(
                            'Track', __number_pair__(self.track_number, value))
                elif (attr == 'album_number'):
                    try:
                        self['Media'].data = re.sub(r'\d+',
                                                    str(int(value)),
                                                    self['Media'].data,
                                                    1)
                    except KeyError:
                        self['Media'] = self.ITEM.string(
                            'Media', __number_pair__(value, self.album_total))
                elif (attr == 'album_total'):
                    try:
                        if (re.search(r'/\D*\d+',
                                      self['Media'].data) is not None):
                            self['Media'].data = re.sub(
                                r'(/\D*)(\d+)',
                                "\\g<1>" + str(int(value)),
                                self['Media'].data,
                                1)
                        else:
                            self['Media'].data = "%s/%d" % (
                                self['Media'].data,
                                value)
                    except KeyError:
                        self['Media'] = self.ITEM.string(
                            'Media', __number_pair__(self.album_number, value))
                else:
                    self[self.ATTRIBUTE_MAP[attr]] = self.ITEM.string(
                        self.ATTRIBUTE_MAP[attr], value)
            else:
                delattr(self, attr)
        else:
            MetaData.__setattr__(self, attr, value)
Exemplo n.º 57
0
    def inject_metadata(self, format, version):

        """
        audiotools.MetaData
        """
        meta = MetaData()

        """
        prepare metadata object
        """
        # track-level metadata
        meta.track_name = self.name
        meta.track_number = self.tracknumber
        meta.media = "DIGITAL"
        meta.isrc = self.isrc

        """ Needs fixing...
        for extra_artist in self.extra_artists.all():
            print extra_artist
        meta.performer_name =
        meta.composer_name =
        meta.conductor_name =
        """

        # release-level metadata
        if self.release:
            meta.album_name = self.release.name
            meta.catalog = self.release.catalognumber
            meta.track_total = len(self.release.media_release.all())

            if self.release.releasedate:
                try:
                    meta.year = str(self.release.releasedate.year)
                    meta.date = str(self.release.releasedate)

                except Exception, e:
                    print e

            try:

                cover_image = self.release.cover_image if self.release.cover_image else self.release.main_image

                if meta.supports_images() and cover_image:
                    for i in meta.images():
                        meta.delete_image(i)

                    opt = dict(size=(200, 200), crop=True, bw=False, quality=80)
                    image = get_thumbnailer(cover_image).get_thumbnail(opt)
                    meta.add_image(get_raw_image(image.path, 0))

            except Exception, e:
                print e
    def __getattr__(self, attr):
        # returns the first matching key for the given attribute
        # in our list of comment strings

        if attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]

            if attr in {'track_number', 'album_number'}:
                try:
                    # get the TRACKNUMBER/DISCNUMBER values
                    # return the first value that contains an integer
                    for value in self[key]:
                        integer = re.search(r'\d+', value)
                        if integer is not None:
                            return int(integer.group(0))
                    else:
                        # otherwise, return None
                        return None
                except KeyError:
                    # if no TRACKNUMBER/DISCNUMBER, return None
                    return None
            elif attr in {'track_total', 'album_total'}:
                try:
                    # get the TRACKTOTAL/DISCTOTAL values
                    # return the first value that contains an integer
                    for value in self[key]:
                        integer = re.search(r'\d+', value)
                        if integer is not None:
                            return int(integer.group(0))
                except KeyError:
                    pass

                # if no TRACKTOTAL/DISCTOTAL,
                # or none of them contain an integer,
                # look for slashed TRACKNUMBER/DISCNUMBER values
                try:
                    for value in self[{"track_total": u"TRACKNUMBER",
                                       "album_total": u"DISCNUMBER"}[attr]]:
                        if u"/" in value:
                            integer = re.search(r'\d+',
                                                value.split(u"/", 1)[1])
                            if integer is not None:
                                return int(integer.group(0))
                    else:
                        return None
                except KeyError:
                    # no slashed TRACKNUMBER/DISCNUMBER values either
                    # so return None
                    return None
            elif attr == "compilation":
                try:
                    # if present, return True if the first value is "1"
                    return self[key][0] == u"1"
                except KeyError:
                    # if not present, return None
                    return None
            else:
                # attribute is supported by VorbisComment
                try:
                    # if present, return the first value
                    return self[key][0]
                except KeyError:
                    # if not present, return None
                    return None
        elif attr in self.FIELDS:
            # attribute is supported by MetaData
            # but not supported by VorbisComment
            return None
        else:
            # attribute is not MetaData-specific
            return MetaData.__getattribute__(self, attr)
    def __delattr__(self, attr):
        #FIXME
        # deletes all matching keys for the given attribute
        # in our list of comment strings

        import re

        if attr in self.ATTRIBUTE_MAP:
            key = self.ATTRIBUTE_MAP[attr]

            if attr in {'track_number', 'album_number'}:
                try:
                    current_values = self[key]

                    # save the _total side of any slashed fields for later
                    slashed_totals = [int(match.group(0)) for match in
                                      [re.search(r'\d+',
                                                 value.split(u"/", 1)[1])
                                       for value in current_values if
                                       u"/" in value]
                                      if match is not None]

                    # remove the TRACKNUMBER/DISCNUMBER field itself
                    self[key] = []

                    # if there are any slashed totals
                    # and there isn't a TRACKTOTAL/DISCTOTAL field already,
                    # add a new one
                    total_key = {'track_number': u"TRACKTOTAL",
                                 'album_number': u"DISCTOTAL"}[attr]

                    if (len(slashed_totals) > 0) and (total_key not in self):
                        self[total_key] = [u"{:d}".format(slashed_totals[0])]
                except KeyError:
                    # no TRACKNUMBER/DISCNUMBER field to remove
                    pass
            elif attr in {'track_total', 'album_total'}:
                def slash_filter(unicode_string):
                    if u"/" not in unicode_string:
                        return unicode_string
                    else:
                        return unicode_string.split(u"/", 1)[0].rstrip()

                slashed_key = {"track_total": u"TRACKNUMBER",
                               "album_total": u"DISCNUMBER"}[attr]

                # remove TRACKTOTAL/DISCTOTAL fields
                self[key] = []

                # preserve the non-slashed side of
                # TRACKNUMBER/DISCNUMBER fields
                try:
                    self[slashed_key] = [slash_filter(s) for s in
                                         self[slashed_key]]
                except KeyError:
                    # no TRACKNUMBER/DISCNUMBER fields
                    pass
            else:
                # unlike __setattr_, which tries to preserve multiple instances
                # of fields, __delattr__ wipes them all
                # so that orphaned fields don't show up after deletion
                self[key] = []
        elif attr in self.FIELDS:
            # attribute is part of MetaData
            # but not supported by VorbisComment
            pass
        else:
            MetaData.__delattr__(self, attr)
Exemplo n.º 60
0
    def __getattr__(self, attr):
        import re

        if (attr == 'track_number'):
            try:
                track_text = unicode(self["Track"])
                track = re.search(r'\d+', track_text)
                if (track is not None):
                    track_number = int(track.group(0))
                    if ((track_number == 0) and
                        (re.search(r'/.*?(\d+)',
                                   track_text) is not None)):
                        # if track_total is nonzero and track_number is 0
                        # track_number is a placeholder
                        # so treat track_number as None
                        return None
                    else:
                        return track_number
                else:
                    # "Track" isn't an integer
                    return None
            except KeyError:
                # no "Track" in list of items
                return None
        elif (attr == 'track_total'):
            try:
                track = re.search(r'/.*?(\d+)', unicode(self["Track"]))
                if (track is not None):
                    return int(track.group(1))
                else:
                    # no slashed integer field in "Track"
                    return None
            except KeyError:
                # no "Track" in list of items
                return None
        elif (attr == 'album_number'):
            try:
                media_text = unicode(self["Media"])
                media = re.search(r'\d+', media_text)
                if (media is not None):
                    album_number = int(media.group(0))
                    if ((album_number == 0) and
                        (re.search(r'/.*?(\d+)',
                                   media_text) is not None)):
                        # if album_total is nonzero and album_number is 0
                        # album_number is a placeholder
                        # so treat album_number as None
                        return None
                    else:
                        return album_number
                else:
                    # "Media" isn't an integer
                    return None
            except KeyError:
                # no "Media" in list of items
                return None
        elif (attr == 'album_total'):
            try:
                media = re.search(r'/.*?(\d+)', unicode(self["Media"]))
                if (media is not None):
                    return int(media.group(1))
                else:
                    # no slashed integer field in "Media"
                    return None
            except KeyError:
                # no "Media" in list of items
                return None
        elif (attr in self.ATTRIBUTE_MAP):
            try:
                return unicode(self[self.ATTRIBUTE_MAP[attr]])
            except KeyError:
                return None
        elif (attr in MetaData.FIELDS):
            return None
        else:
            return MetaData.__getattribute__(self, attr)