Example #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)
    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)
Example #3
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)
Example #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)
Example #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)
 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)
Example #7
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)
Example #8
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)
 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)
Example #10
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)
Example #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)
    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)
Example #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)
    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)
Example #15
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)
Example #16
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)
Example #17
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)
Example #18
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)
Example #19
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)
Example #20
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)
Example #21
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)
 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)
Example #23
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)
Example #24
0
 def __setattr__(self, attr, value):
     if (attr == "track_number"):
         if (value is None):
             MetaData.__setattr__(self, "__track_number__", chr(0))
         else:
             MetaData.__setattr__(self,
                                  "__track_number__",
                                  chr(min(int(value), 0xFF)))
     elif (attr in self.FIELD_LENGTHS):
         if (value is None):
             delattr(self, attr)
         else:
             # all are text fields
             encoded = value.encode('ascii', 'replace')
             if (len(encoded) < self.FIELD_LENGTHS[attr]):
                 MetaData.__setattr__(
                     self,
                     self.ID3v1_FIELDS[attr],
                     encoded + chr(0) * (self.FIELD_LENGTHS[attr] -
                                         len(encoded)))
             elif (len(encoded) > self.FIELD_LENGTHS[attr]):
                 MetaData.__setattr__(
                     self,
                     self.ID3v1_FIELDS[attr],
                     encoded[0:self.FIELD_LENGTHS[attr]])
             else:
                 MetaData.__setattr__(
                     self,
                     self.ID3v1_FIELDS[attr],
                     encoded)
     elif (attr in self.FIELDS):
         # field not supported by ID3v1Comment, so ignore it
         pass
     else:
         MetaData.__setattr__(self, attr, value)
Example #25
0
 def __setattr__(self, attr, value):
     if (attr == "track_number"):
         if (value is None):
             MetaData.__setattr__(self, "__track_number__", chr(0))
         else:
             MetaData.__setattr__(self, "__track_number__",
                                  chr(min(int(value), 0xFF)))
     elif (attr in self.FIELD_LENGTHS):
         if (value is None):
             delattr(self, attr)
         else:
             # all are text fields
             encoded = value.encode('ascii', 'replace')
             if (len(encoded) < self.FIELD_LENGTHS[attr]):
                 MetaData.__setattr__(
                     self, self.ID3v1_FIELDS[attr], encoded + chr(0) *
                     (self.FIELD_LENGTHS[attr] - len(encoded)))
             elif (len(encoded) > self.FIELD_LENGTHS[attr]):
                 MetaData.__setattr__(self, self.ID3v1_FIELDS[attr],
                                      encoded[0:self.FIELD_LENGTHS[attr]])
             else:
                 MetaData.__setattr__(self, self.ID3v1_FIELDS[attr],
                                      encoded)
     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)
Example #27
0
    def __init__(self,
                 track_name=chr(0) * 30,
                 artist_name=chr(0) * 30,
                 album_name=chr(0) * 30,
                 year=chr(0) * 4,
                 comment=chr(0) * 28,
                 track_number=chr(0),
                 genre=chr(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 |
        |--------------+--------|

        all are binary strings of the given length
        and must not be any shorter or longer
        """

        if (len(track_name) != 30):
            raise ValueError("track_name must be exactly 30 bytes")
        if (len(artist_name) != 30):
            raise ValueError("artist_name must be exactly 30 bytes")
        if (len(album_name) != 30):
            raise ValueError("album_name must be exactly 30 bytes")
        if (len(year) != 4):
            raise ValueError("year must be exactly 4 bytes")
        if (len(comment) != 28):
            raise ValueError("comment must be exactly 28 bytes")
        if (len(track_number) != 1):
            raise ValueError("track_number must be exactly 1 byte")
        if (len(genre) != 1):
            raise ValueError("genre must be exactly 1 byte")

        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 __setattr__(self, attr, value):
        # updates the first matching field for the given attribute
        # in our list of comment strings

        if ((value is None) and (attr in self.FIELDS)):
            # setting any value to None is equivilent to deleting it
            # in this high-level implementation
            delattr(self, attr)
        elif ((attr == "track_number") or (attr == "album_number")):
            key = self.ATTRIBUTE_MAP[attr]
            try:
                new_values = self[key]
                for i in range(len(new_values)):
                    # look for the first TRACKNUMBER/DISCNUMBER field
                    # which contains an integer
                    if (re.search(r'\d+', new_values[i]) is not None):
                        # and replace the integer part of the field
                        new_values[i] = re.sub(r'\d+', u"%d" % (value),
                                               new_values[i], 1)

                        # then set the field to the new set of values
                        # (which may contain subsequent fields to leave as-is)
                        self[key] = new_values
                        break
                else:
                    # no integer field with matching key
                    # so append new integer field
                    self[key] = self[key] + [u"%d" % (value)]
            except KeyError:
                # no TRACKNUMBER/DISCNUMBER field
                # so add a new one
                self[key] = [u"%d" % (value)]
        elif ((attr == "track_total") or (attr == "album_total")):
            key = self.ATTRIBUTE_MAP[attr]
            try:
                new_values = self[key]
                for i in range(len(new_values)):
                    # look for the first TRACKTOTAL/DISCTOTAL field
                    # which contains an integer
                    if (re.search(r'\d+', new_values[i]) is not None):
                        # and replace the integer part of the field
                        new_values[i] = re.sub(r'\d+', u"%d" % (value),
                                               new_values[i], 1)
                        self[key] = new_values
                        return
            except KeyError:
                new_values = []

            # no TRACKTOTAL/DISCTOTAL field
            # or none of them contain an integer,
            # so look for slashed TRACKNUMBER/DISCNUMBER values
            try:
                slashed_key = {
                    "track_total": u"TRACKNUMBER",
                    "album_total": u"DISCNUMBER"
                }[attr]
                new_slashed_values = self[slashed_key]
                for i in range(len(new_slashed_values)):
                    # look for the first TRACKNUMBER/DISCNUMBER field
                    # which contains a slashed value
                    if (re.search(r'/\D*\d+', new_slashed_values[i])
                            is not None):
                        # and replace the slashed part of the field
                        new_slashed_values[i] = re.sub(
                            r'(/\D*)(\d+)', u'\\g<1>' + (u"%d" % (value)),
                            new_slashed_values[i], 1)
                        self[slashed_key] = new_slashed_values
                        return
            except KeyError:
                # no TRACKNUMBER/DISCNUMBER field found
                pass

            # no TRACKTOTAL/DISCTOTAL fields
            # or no integer values in those fields,
            # and no slashed TRACKNUMBER/DISCNUMBER values
            # or no integer values in those fields,
            # so append a TRACKTOTAL/DISCTOTAL field
            self[key] = new_values + [u"%d" % (value)]
        elif (attr in self.ATTRIBUTE_MAP.keys()):
            key = self.ATTRIBUTE_MAP[attr]
            try:
                current_values = self[key]
                # try to leave subsequent fields with the same key as-is
                self[key] = [u"%s" % (value)] + current_values[1:]
            except KeyError:
                # no current field with the same key, so add a new one
                self[key] = [u"%s" % (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)
Example #29
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)
Example #30
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)
Example #31
0
    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)
Example #32
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 __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)
Example #34
0
    def __init__(self, track_name=chr(0) * 30,
                 artist_name=chr(0) * 30,
                 album_name=chr(0) * 30,
                 year=chr(0) * 4,
                 comment=chr(0) * 28,
                 track_number=chr(0),
                 genre=chr(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 |
        |--------------+--------|

        all are binary strings of the given length
        and must not be any shorter or longer
        """

        if (len(track_name) != 30):
            raise ValueError("track_name must be exactly 30 bytes")
        if (len(artist_name) != 30):
            raise ValueError("artist_name must be exactly 30 bytes")
        if (len(album_name) != 30):
            raise ValueError("album_name must be exactly 30 bytes")
        if (len(year) != 4):
            raise ValueError("year must be exactly 4 bytes")
        if (len(comment) != 28):
            raise ValueError("comment must be exactly 28 bytes")
        if (len(track_number) != 1):
            raise ValueError("track_number must be exactly 1 byte")
        if (len(genre) != 1):
            raise ValueError("genre must be exactly 1 byte")

        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)