예제 #1
0
        def __init__(self, filename=None):
            self.__images = []
            self.__tags = CaselessDict()

            self.filetype = name
            self.__tags['__filetype'] = self.filetype
            self.__tags['__tag_read'] = u'VorbisComment'

            util.MockTag.__init__(self, filename)
예제 #2
0
        def __init__(self, filename=None):
            self.__images = []

            self.__tags = CaselessDict()  #Used as storage.
            #Each key as the is the field as used by puddletag, eg. 'artist'
            #Each value contains an mutagen.id3.Frame object
            #that have two methods, get_value and set_value.
            #get_value returns the value stored by the frame as
            #text/unicode list.
            #set_value should take text/unicode list in parse it into
            #it understands.

            #When saving the frame stored will be used. If it has a 'frames'
            #attributes, those frames will be used instead.

            util.MockTag.__init__(self, filename)
예제 #3
0
 def __deepcopy__(self, memo=None):
     cls = Tag()
     tags = CaselessDict()
     frames = []
     [
         frames.append(frame) if not hasattr(frame, 'frames') else
         frames.extend(frame.frames)
         for key, frame in self.__tags.items()
         if not key.startswith('__')
     ]
     funcs = []
     frames_copy = []
     for frame in frames:
         funcs.append((getattr(frame, 'get_value',
                               None), getattr(frame, 'set_value',
                                              None)))
         if hasattr(frame, 'get_value'):
             delattr(frame, 'get_value')
         if hasattr(frame, 'set_value'):
             delattr(frame, 'set_value')
         frames_copy.append(deepcopy(frame))
     tags = handle(
         dict([(frame.HashKey, frame) for frame in frames_copy]))
     for frame, (get_value, set_value) in zip(frames, funcs):
         if get_value is not None:
             frame.get_value = get_value
         if set_value is not None:
             frame.set_value = set_value
     for key, value in self.__tags.items():
         if key not in tags:
             tags[key] = deepcopy(value)
     cls.set_fundamentals(tags, self.mut_obj, deepcopy(self.images))
     cls.filepath = self.filepath
     return cls
예제 #4
0
        def __init__(self, filename=None):
            self.__images = []

            self.__tags = CaselessDict() #Used as storage.
            #Each key as the is the field as used by puddletag, eg. 'artist'
            #Each value contains an mutagen.id3.Frame object
            #that have two methods, get_value and set_value.
            #get_value returns the value stored by the frame as
            #text/unicode list.
            #set_value should take text/unicode list in parse it into
            #it understands.

            #When saving the frame stored will be used. If it has a 'frames'
            #attributes, those frames will be used instead.

            util.MockTag.__init__(self, filename)
예제 #5
0
    def __init__(self, filename=None):
        self.__images = []
        self.__errors = set()
        self.__tags = CaselessDict()

        util.MockTag.__init__(self, filename)
예제 #6
0
class Tag(util.MockTag):
    """Class for AAC tags."""

    mapping = {}
    revmapping = {}
    IMAGETAGS = (util.MIMETYPE, util.DATA)

    def __init__(self, filename=None):
        self.__images = []
        self.__errors = set()
        self.__tags = CaselessDict()

        util.MockTag.__init__(self, filename)

    def get_filepath(self):
        return util.MockTag.get_filepath(self)

    def set_filepath(self,  val):
        self.__tags.update(util.MockTag.set_filepath(self, val))

    filepath = property(get_filepath, set_filepath)

    def __contains__(self, key):
        if key == '__image':
            return bool(self.images)
        
        elif key == '__total':
            try:
                return bool(get_total(self))
            except (KeyError, ValueError):
                return False
        
        if self.revmapping:
            key = self.revmapping.get(key, key)
        return key in self.__tags

    def __deepcopy__(self, memo=None):
        cls = Tag()
        cls.mapping = self.mapping
        cls.revmapping = self.revmapping
        cls.set_fundamentals(deepcopy(self.__tags), deepcopy(self.images),
            self.mut_obj, deepcopy(self.__freeform), deepcopy(self.__errors))
        cls.filepath = self.filepath
        return cls

    @del_deco
    def __delitem__(self, key):
        if key == '__image':
            self.images = []  
        elif key.startswith('__'):
            return
        else:
            del(self.__tags[key])

    @getdeco
    def __getitem__(self, key):
        if key.startswith('__'):
            if key == '__image':
                return self.images
            elif key == '__total':
                return FUNCS['totaltracks'][0](self.__tags['totaltracks'])
            else:
                return self.__tags[key]

        try:
            return FUNCS[key][0](self.__tags[key])
        except KeyError:
            return gettext(self.__tags[key])

    @setdeco
    def __setitem__(self, key, value):
        if isinstance(key, (int, long)):
            self.__tags[key] = value
            return
        elif key.startswith('__'):
            if key == '__image':
                self.images = value
            if key in FILETAGS:
                setattr(self, fn_hash[key], value)
            elif key == '__total':
                self.__tags['totaltracks'] = FUNCS['totaltracks'][1](value)
            return
        elif isempty(value):
            if key in self:
                del(self[key])
            return
        else:
            try:
                new_val = FUNCS[key][1](value)
                if value:
                    self.__tags[key] = new_val
            except KeyError:
                #User defined tags.
                self.__freeform[key] = '----:com.apple.iTunes:%s' % key
                self.__tags[key] = settext(value)
            except ValueError:
                pass

    def delete(self):
        self.mut_obj.delete()
        for key in self.usertags:
            del(self.__tags[self.revmapping.get(key, key)])
        self.images = []

    def _set_images(self, images):
        if images:
            self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                images)
        else:
            self.__images = []
        cover_info(images, self.__tags)

    def _get_images(self):
        return self.__images

    images = property(_get_images, _set_images)

    def _info(self):
        info = self.mut_obj.info
        fileinfo = [('Path', self[PATH]),
                    ('Size', str_filesize(int(self.size))),
                    ('Filename', self[FILENAME]),
                    ('Modified', self.modified)]

        mp4info = [('Bitrate', self.bitrate),
                   ('Frequency', self.frequency),
                   ('Channels', unicode(info.channels)),
                   ('Length', self.length),
                   ('Bits per sample', unicode(info.bits_per_sample))]

        return [('File', fileinfo), ('MP4 Info', mp4info)]

    info = property(_info)

    def link(self, filename):
        """Links the audio, filename
        returns self if successful, None otherwise."""

        tags, audio = self.load(filename, MP4)
        self.images = []

        if audio is None:
            return

        revmap, mapping = self.revmapping, self.mapping
        self.revmapping, self.mapping = {}, {}

        self.__freeform = {} #Keys are tags as required by mutagen i.e. The '----'
                             #frames. Values are the tag as represented by puddletag.

        if audio.tags: #Not empty
            keys = audio.keys()
            try:
                self.images = map(bin_to_pic, audio['covr'])
                keys.remove('covr')
            except KeyError:
                self.images = []

            convert = lambda k, v: FUNCS[k][1](v)

            #I want 'trkn', to split into track and totaltracks, like Mp3tag.
            if 'trkn' in keys:
                tags['track'] = convert('track',
                    [z[0] for z in audio['trkn']])
                tags['totaltracks'] = convert('totaltracks',
                    [z[1] for z in audio['trkn']])
                keys.remove('trkn')

            #Same as above
            if 'disk' in keys:
                tags['disc'] = convert('disc', [z[0] for z in audio['disk']])
                tags['totaldiscs'] = convert('totaldiscs',
                    [z[1] for z in audio['disk']])
                keys.remove('disk')

            for key in keys:
                if key in TAGS:
                    tags[TAGS[key]] = convert(TAGS[key], audio[key])
                else:
                    field = key[key.find(':', key.find(':') +1) + 1:]
                    try:
                        field = field.decode('utf8')
                    except UnicodeDecodeError:
                        field = field.decode('latin1')

                    self.__freeform[field] = key
                    try:
                        tags[field] = [unicode(v, 'utf8') if not
                            isinstance(v, unicode) else v for v in audio[key]]
                    except UnicodeDecodeError:
                        self.__errors.add(field)

        for k,v in tags.items():
            if not v:
                del(tags[k])

        self.__tags.update(info_to_dict(audio.info))
        self.__tags.update(tags)
        self.revmapping, self.mapping = revmap, mapping
        self.__tags['__tag_read'] = u'MP4'
        self.filetype = 'MP4'
        self.__tags['__filetype'] = self.filetype
        self.set_attrs(ATTRIBUTES, self.__tags)
        self.update_tag_list()
        self.mut_obj = audio

    @keys_deco
    def keys(self):
        return self.__tags.keys()

    def save(self):
        if self.mut_obj.tags is None:
            self.mut_obj.add_tags()
        if self.filepath != self.mut_obj.filename:
            self.mut_obj.filename = self.filepath
        audio = self.mut_obj

        newtag = {}
        tuples = (('track', ['trkn', 'totaltracks']),
            ('disc', ['disk', 'totaldiscs']))
        tags = self.__tags
        for tag, values in tuples:
            if tag in tags:
                denom = tags[tag]
                if values[1] in tags:
                    total = tags[values[1]]
                    newtag[values[0]] = [(int(t), int(total)) for t, total in
                        zip(denom, total)]
                else:
                    newtag[values[0]] = [(int(z), 0) for z in denom]
            elif values[1] in tags:
                total = tags[values[1]]
                newtag[values[0]] = [(0, int(z)) for z in total]

        tags = usertags(self.__tags)
        tags = [(z, tags[z]) for z in tags
            if z not in ['track', 'totaltracks', 'disc', 'totaldiscs']]
        
        for tag, value in tags:
            try:
                newtag[REVTAGS[tag]] = value
            except KeyError:
                newtag[self.__freeform[tag].encode('utf8')] = encode(self.__tags[tag])

        if self.images:
            newtag['covr'] = filter(None, map(pic_to_bin, self.images))

        toremove = [z for z in audio.keys() if
            z not in newtag and z not in self.__errors]
        for key in toremove:
            del(audio[key])
        audio.update(newtag)
        audio.save()

    def set_fundamentals(self, tags, images, mut_obj, freeform=None, errors=None):
        self.__freeform = {} if freeform is None else freeform
        self.__errors = {} if errors is None else errors
        self.__tags = tags
        self.mut_obj = mut_obj
        self.images = images

    def update_tag_list(self):
        l = tag_versions.tags_in_file(self.filepath)
        if l:
            self.__tags['__tag'] = u'MP4, ' + u', '.join(l)
        else:
            self.__tags['__tag'] = u'MP4'
예제 #7
0
    class Tag(util.MockTag):
        IMAGETAGS = (util.MIMETYPE, util.DESCRIPTION, util.DATA, util.IMAGETYPE)
        mapping = {}
        revmapping = {}

        def __init__(self, filename=None):
            self.__images = []
            self.__tags = CaselessDict()

            self.filetype = name
            self.__tags['__filetype'] = self.filetype
            self.__tags['__tag_read'] = u'VorbisComment'

            util.MockTag.__init__(self, filename)

        def get_filepath(self):
            return util.MockTag.get_filepath(self)

        def set_filepath(self,  val):
            self.__tags.update(util.MockTag.set_filepath(self, val))

        filepath = property(get_filepath, set_filepath)

        def _get_images(self):
            return self.__images

        def _set_images(self, images):
            if images:
                self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                    images)
            else:
                self.__images = []
            cover_info(images, self.__tags)

        images = property(_get_images, _set_images)
                
        def __contains__(self, key):
            if key == '__image':
                return bool(self.images)
            
            elif key == '__total':
                try:
                    return bool(get_total(self))
                except (KeyError, ValueError):
                    return False
        
            if self.revmapping:
                key = self.revmapping.get(key, key)
            return key in self.__tags

        def __deepcopy__(self, memo):
            cls = Tag()
            cls.mapping = self.mapping
            cls.revmapping = self.revmapping
            cls.set_fundamentals(deepcopy(self.__tags),
                self.mut_obj, self.images)
            cls.filepath = self.filepath
            return cls

        @del_deco
        def __delitem__(self, key):
            if key == '__image':
                self.images = []
            elif key.startswith('__'):
                return
            else:
                del(self.__tags[key])

        @getdeco
        def __getitem__(self, key):
            if key == '__image':
                return self.images
            elif key == '__total':
                return get_total(self)
            return self.__tags[key]

        @setdeco
        def __setitem__(self, key, value):
            if key.startswith('__'):
                if key == '__image':
                    self.images = value
                elif key == '__total':
                    set_total(self, value)
                elif key in fn_hash:
                    setattr(self, fn_hash[key], value)
            elif isempty(value):
                if key in self:
                    del(self[key])
                else:
                    return
            else:
                if isinstance(value, (int, long)):
                    self.__tags[key.lower()] = [unicode(value)]
                else:
                    self.__tags[key.lower()] = unicode_list(value)

        def delete(self):
            self.mut_obj.delete()
            for key in self.usertags:
                del(self.__tags[self.revmapping.get(key, key)])
            self.images = []

        @keys_deco
        def keys(self):
            return self.__tags.keys()

        def link(self, filename):
            """Links the audio, filename
            returns self if successful, None otherwise."""
            self.__images = []
            tags, audio = self.load(filename, base)
            if audio is None:
                return

            for key in audio:
                if key == COVER_KEY:
                    self.images = map(base64_to_image, audio[key])
                else:
                    self.__tags[key.lower()] = audio.tags[key]

            if base == FLAC:
                self.images = filter(None, map(bin_to_image, audio.pictures))
            elif not self.images:
                self.images = []

            self.__tags.update(info_to_dict(audio.info))
            self.__tags.update(tags)
            self.set_attrs(ATTRIBUTES)
            self.mut_obj = audio
            self._originaltags = self.__tags.keys()
            self.update_tag_list()
            return self

        def save(self):
            """Writes the tags in self.__tags
            to self.filename if no filename is specified."""
            filepath = self.filepath

            if self.mut_obj.tags is None:
                self.mut_obj.add_tags()
            if filepath != self.mut_obj.filename:
                self.mut_obj.filename = filepath
            audio = self.mut_obj

            newtag = {}
            for tag, value in usertags(self.__tags).items():
                newtag[tag] = value

            if self.__images:
                if base == FLAC:
                    audio.clear_pictures()
                    map(lambda p: audio.add_picture(image_to_bin(p)),
                        self.__images)
                else:
                    newtag[COVER_KEY] = filter(None, map(image_to_base64, self.__images))
            else:
                if base == FLAC:
                    audio.clear_pictures()

            toremove = [z for z in audio if z not in newtag]
            for z in toremove:
                del(audio[z])
            audio.update(newtag)
            audio.save()

        def set_fundamentals(self, tags, mut_obj, images=None):
            self.__tags = tags
            self.mut_obj = mut_obj
            if images:
                self.images = images
            else:
                self.images = []
            self._originaltags = tags.keys()

        def update_tag_list(self):
            l = tags_in_file(self.filepath)
            if l:
                self.__tags['__tag'] = u'VorbisComment, ' + u', '.join(l)
            else:
                self.__tags['__tag'] = u'VorbisComment'
예제 #8
0
class Tag(util.MockTag):
    IMAGETAGS = (util.MIMETYPE, util.DATA, util.IMAGETYPE, util.DESCRIPTION)
    mapping = {}
    revmapping = {}

    __rtranslate = {
        'album': 'WM/AlbumTitle',
        'album_subtitle': 'WM/SetSubTitle',
        'albumartist': 'WM/AlbumArtist',
        'albumartistsortorder': 'WM/AlbumArtistSortOrder',
        'albumsortorder': 'WM/AlbumSortOrder',
        'artist': 'Author',
        'bpm': 'WM/BeatsPerMinute',
        'comment:': 'Description',
        'composer': 'WM/Composer',
        'conductor': 'WM/Conductor',
        'copyright': 'WM/Copyright',
        'discnumber': 'WM/PartOfSet',
        'encodedby': 'WM/EncodedBy',
        'encodersettings': 'WM/EncodingSettings',
        'encodingtime': 'WM/EncodingTime',
        'engineer': 'WM/Producer',
        'genre': 'WM/Genre',
        'grouping': 'WM/ContentGroupDescription',
        'initialkey': 'WM/InitialKey',
        'isrc': 'WM/ISRC',
        'label': 'WM/Publisher',
        'language': 'WM/Language',
        'lyricist': 'WM/Writer',
        'lyrics': 'WM/Lyrics',
        'mbrainz_album_id': 'MusicBrainz/Album Id',
        'mbrainz_albumartist_id': 'MusicBrainz/Album Artist Id',
        'mbrainz_artist_id': 'MusicBrainz/Artist Id',
        'mbrainz_discid': 'MusicBrainz/Disc Id',
        'mbrainz_track_id': 'MusicBrainz/Track Id',
        'mbrainz_trmid': 'MusicBrainz/TRM Id',
        'mood': 'WM/Mood',
        'musicip_puid': 'MusicIP/PUID',
        'originalalbum': 'WM/OriginalAlbumTitle',
        'originalartist': 'WM/OriginalArtist',
        'originalfilename': 'WM/OriginalFilename',
        'originallyricist': 'WM/OriginalLyricist',
        'originalyear': 'WM/OriginalReleaseYear',
        'performersortorder': 'WM/ArtistSortOrder',
        'releasecountry': 'MusicBrainz/Album Release Country',
        'releasestatus': 'MusicBrainz/Album Status',
        'releasetype': 'MusicBrainz/Album Type',
        'remixer': 'WM/ModifiedBy',
        'subtitle': 'WM/SubTitle',
        'title': 'Title',
        'titlesortorder': 'WM/TitleSortOrder',
        'track': 'WM/TrackNumber',
        'unsyncedlyrics': 'WM/Lyrics',
        'wwwartist': 'WM/AuthorURL',
        'wwwaudiosource': 'WM/AudioSourceURL',
        'wwwcommercialinfo': 'WM/PromotionURL',
        'wwwcopyright': 'CopyrightURL',
        'year': 'WM/Year',
    }
    __translate = dict([(v, k) for k, v in __rtranslate.iteritems()])

    def __init__(self, filename=None):
        self.__images = []
        self.__tags = CaselessDict()

        util.MockTag.__init__(self, filename)

    def get_filepath(self):
        return util.MockTag.get_filepath(self)

    def set_filepath(self,  val):
        self.__tags.update(util.MockTag.set_filepath(self, val))

    filepath = property(get_filepath, set_filepath)

    def _getImages(self):
        return self.__images

    def _setImages(self, images):
        if images:
            self.__images = map(parse_image, images)
        else:
            self.__images = []
        cover_info(images, self.__tags)

    images = property(_getImages, _setImages)

    def __contains__(self, key):
        if key == '__image':
            return bool(self.images)
        
        elif key == '__total':
            try:
                return bool(get_total(self))
            except (KeyError, ValueError):
                return False
        
        if self.revmapping:
            key = self.revmapping.get(key, key)
        return key in self.__tags

    @getdeco
    def __getitem__(self, key):
        if key == '__image':
            return self.images
        elif key == '__total':
            return get_total(self)
        return self.__tags[key]

    @setdeco
    def __setitem__(self,key,value):
        if key.startswith('__'):

            if key == '__image':
                self.images = value
            elif key in fn_hash:
                setattr(self, fn_hash[key], value)
            elif key == '__total' and 'track' in self:
                if set_total(self, value):
                    return
            return
        elif isempty(value):
            del(self[key])
        elif key in self.__rtranslate:
            self.__tags[key] = unicode_list(value)

    @del_deco
    def __delitem__(self, key):
        if key == '__image':
            self.images = []
        elif key.startswith('__'):
            return
        else:
            del(self.__tags[key])

    def delete(self):
        self.mut_obj.clear()
        for key in self.usertags:
            del(self.__tags[self.revmapping.get(key, key)])
        self.images = []
        self.save()

    def _info(self):
        info = self.mut_obj.info
        fileinfo = [('Path', self[PATH]),
                    ('Size', str_filesize(int(self.size))),
                    ('Filename', self[FILENAME]),
                    ('Modified', self.modified)]

        wmainfo = [('Bitrate', self.bitrate),
                   ('Frequency', self.frequency),
                   ('Channels', unicode(info.channels)),
                   ('Length', self.length)]
        return [('File', fileinfo), ('ASF Info', wmainfo)]

    info = property(_info)

    @keys_deco
    def keys(self):
        return self.__tags.keys()

    def link(self, filename):
        """Links the audio, filename
        returns self if successful, None otherwise."""
        
        
        self.images = None
        tags, audio = self.load(filename, ASF)
        if audio is None:
            return

        for name, values in audio.tags.iteritems():
            try:
                self.__tags[self.__translate[name]] = map(unicode, values)
            except KeyError:
                if isinstance(values[0], ASFUnicodeAttribute):
                    if not '/' in name and name not in self.__tags:
                        self.__tags[name] = map(unicode, values)

        if 'WM/Picture' in audio:
            self.images = map(bin_to_pic, audio['WM/Picture'])

        self.__tags.update(info_to_dict(audio.info))
        self.__tags.update(tags)
        self.__tags['__filetype'] = u'ASF'
        self.filetype = u'ASF'
        self.__tags['__tag_read'] = u'ASF'
        self.set_attrs(ATTRIBUTES)
        self.mut_obj = audio
        self.update_tag_list()
        return self

    def save(self):
        """Writes the tags in self.__tags
        to self.filename if no filename is specified."""
        filepath = self.filepath

        if self.mut_obj.tags is None:
            self.mut_obj.add_tags()
        if filepath != self.mut_obj.filename:
            self.mut_obj.filename = filepath
        audio = self.mut_obj

        newtag = {}
        for field, value in usertags(self.__tags).items():
            try:
                newtag[self.__rtranslate[field]] = value
            except KeyError:
                newtag[field] = value

        pics = map(pic_to_bin, self.images)
        if pics:
            newtag['WM/Picture'] = pics

        toremove = [z for z in audio if z not in newtag]
        for z in toremove:
            del(audio[z])
        audio.update(newtag)
        audio.save()

    def update_tag_list(self):
        l = tag_versions.tags_in_file(self.filepath)
        if l:
            self.__tags['__tag'] = u'ASF, ' + u', '.join(l)
        else:
            self.__tags['__tag'] = u'ASF'
예제 #9
0
    def __init__(self, filename=None):
        self.__images = []
        self.__tags = CaselessDict()

        util.MockTag.__init__(self, filename)
예제 #10
0
    class Tag(TagBase):
        IMAGETAGS = (util.MIMETYPE, util.DESCRIPTION, util.DATA,
                     util.IMAGETYPE)
        mapping = {}
        revmapping = {}

        def __init__(self, filename=None):
            self.__images = []

            self.__tags = CaselessDict()  #Used as storage.
            #Each key as the is the field as used by puddletag, eg. 'artist'
            #Each value contains an mutagen.id3.Frame object
            #that have two methods, get_value and set_value.
            #get_value returns the value stored by the frame as
            #text/unicode list.
            #set_value should take text/unicode list in parse it into
            #it understands.

            #When saving the frame stored will be used. If it has a 'frames'
            #attributes, those frames will be used instead.

            util.MockTag.__init__(self, filename)

        def get_filepath(self):
            return util.MockTag.get_filepath(self)

        def set_filepath(self, val):
            self.__tags.update(util.MockTag.set_filepath(self, val))

        filepath = property(get_filepath, set_filepath)

        def _get_images(self):
            return self.__images

        def _set_images(self, images):
            if images:
                self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                                    images)
            else:
                self.__images = []
            cover_info(images, self.__tags)

        images = property(_get_images, _set_images)

        def _info(self):
            info = self.mut_obj.info
            fileinfo = [('Path', self[PATH]),
                        ('Size', str_filesize(int(self.size))),
                        ('Filename', self[FILENAME]),
                        ('Modified', self.modified)]
            try:
                version = self.mut_obj.tags.version
                version = ('ID3 Version', self.filetype)
            except AttributeError:
                version = ('ID3 Version', 'No tags in file.')
            fileinfo.append(version)

            if isinstance(self.mut_obj, DSFFileType):
                mpginfo = [('Type', 'DSF')]
            elif isinstance(self.mut_obj, AIFFFileType):
                mpginfo = [('Type', 'AIFF')]
            elif (self.mut_obj, ID3FileType):
                mpginfo = [('Version',
                            u'MPEG %i Layer %i' % (info.version, info.layer))]
            else:
                mpginfo = []

            try:
                mpginfo.append(('Bitrate', self.bitrate))
            except AttributeError:
                pass

            try:
                mpginfo.append(('Frequency', self.frequency))
            except AttributeError:
                pass

            try:
                mpginfo.append(('Mode', MODES[info.mode]))
            except AttributeError:
                pass

            try:
                mpginfo.append(('Length', self.length))
            except Att:
                pass

            return [('File', fileinfo), (mpginfo[0][0], mpginfo)]

        info = property(_info)

        def __contains__(self, key):
            if key == '__image':
                return bool(self.images)

            elif key == '__total':
                try:
                    return bool(get_total(self))
                except (KeyError, ValueError):
                    return False

            if self.revmapping:
                key = self.revmapping.get(key, key)

            return key in self.__tags

        def __deepcopy__(self, memo=None):
            cls = Tag()
            tags = CaselessDict()
            frames = []
            [
                frames.append(frame) if not hasattr(frame, 'frames') else
                frames.extend(frame.frames)
                for key, frame in self.__tags.items()
                if not key.startswith('__')
            ]
            funcs = []
            frames_copy = []
            for frame in frames:
                funcs.append((getattr(frame, 'get_value',
                                      None), getattr(frame, 'set_value',
                                                     None)))
                if hasattr(frame, 'get_value'):
                    delattr(frame, 'get_value')
                if hasattr(frame, 'set_value'):
                    delattr(frame, 'set_value')
                frames_copy.append(deepcopy(frame))
            tags = handle(
                dict([(frame.HashKey, frame) for frame in frames_copy]))
            for frame, (get_value, set_value) in zip(frames, funcs):
                if get_value is not None:
                    frame.get_value = get_value
                if set_value is not None:
                    frame.set_value = set_value
            for key, value in self.__tags.items():
                if key not in tags:
                    tags[key] = deepcopy(value)
            cls.set_fundamentals(tags, self.mut_obj, deepcopy(self.images))
            cls.filepath = self.filepath
            return cls

        @del_deco
        def __delitem__(self, key):
            if key == '__image':
                self.images = []
            elif key.startswith('__'):
                return
            else:
                del (self.__tags[key])

        @getdeco
        def __getitem__(self, key):
            if key.startswith('__'):
                if key == '__image':
                    return self.images
                elif key == '__filetype':
                    return self.filetype
                elif key == '__total':
                    return get_total(self)
                else:
                    return self.__tags[key]
            elif not isinstance(key, basestring):
                return self.__tags[key]
            else:
                return self.__tags[key].get_value()

        @setdeco
        def __setitem__(self, key, value):
            if not isinstance(key, basestring):
                self.__tags[key] = value
                return
            if key.startswith('__'):
                if key == '__image':
                    self.images = value
                elif key in fn_hash:
                    setattr(self, fn_hash[key], value)
                elif key == '__total':
                    set_total(self, value)
                return

            value = unicode_list(value)

            if isempty(value):
                if key in self:
                    del (self[key])
                return

            if key in self.__tags:
                self.__tags[key].set_value(value)
            else:
                if key in write_frames:
                    self.__tags.update(write_frames[key](value))
                elif key == u'comment':
                    frame = {'comment': create_comment('', value)['comment:']}
                    self.__tags.update(frame)
                elif key.startswith('comment:'):
                    self.__tags.update(
                        create_comment(key[len('comment:'):], value))
                elif key.startswith('www:'):
                    self.__tags.update(create_userurl(key, value))
                elif key.startswith('ufid:'):
                    self.__tags.update(create_ufid(key, value))
                elif key.startswith('rgain:'):
                    self.__tags.update(create_rgain(key, value))
                elif key.startswith('unsyncedlyrics:'):
                    self.__tags.update(create_uslt(key, value))
                else:
                    self.__tags.update(create_usertext(key, value))

        def delete(self):
            self.mut_obj.delete()
            for key in self.usertags:
                del (self.__tags[self.revmapping.get(key, key)])
            self.images = []

        @keys_deco
        def keys(self):
            return self.__tags.keys()

        def link(self, filename):
            """Links the audio, filename
            returns self if successful, None otherwise."""
            self.__images = []
            tags, audio = self.load(filename, id3_filetype)
            if audio is None:
                return

            if audio.tags:  #Not empty
                audio.tags.update_to_v24()
                self.__tags.update(handle(audio))

                #Get the image data.
                apics = audio.tags.getall("APIC")
                if apics:
                    self.images = map(bin_to_pic, apics)
                else:
                    self.images = []

            self.__tags.update(tags)
            self.__tags.update(info_to_dict(audio.info))

            if self.ext.lower() == 'mp3':
                self.__tags['__filetype'] = u'MP3'
            else:
                self.__tags['__filetype'] = u'ID3'

            self.set_attrs(ATTRIBUTES, self.__tags)

            try:
                self.__tags[
                    '__tag_read'] = u'ID3v%s.%s' % audio.tags.version[:2]
            except AttributeError:
                self.__tags['__tag_read'] = u''
            self.mut_obj = audio
            self._originaltags = audio.keys()
            self.update_tag_list()
            return self

        def save(self, v1=None, v2=None):
            if v1 is None:
                v1 = v1_option
            """Writes the tags to file."""
            filename = self.filepath
            if self.mut_obj.tags is None:
                self.mut_obj.add_tags()
            if filename != self.mut_obj.filename:
                self.mut_obj.tags.filename = filename
                self.mut_obj.filename = filename
            audio = self.mut_obj
            util.MockTag.save(self)

            userkeys = usertags(self.__tags).keys()
            frames = []
            [
                frames.append(frame) if not hasattr(frame, 'frames') else
                frames.extend(frame.frames)
                for key, frame in self.__tags.items() if key in userkeys
            ]
            hashes = dict([(frame.HashKey, frame) for frame in frames])
            toremove = [
                z for z in self._originaltags
                if z in audio and not (z in hashes or z.startswith('APIC'))
            ]
            audio.update(hashes)

            old_apics = [z for z in audio if z.startswith(u'APIC')]
            if self.__images:
                newimages = []
                for image in filter(None, map(pic_to_bin, self.__images)):
                    i = 0
                    while image.HashKey in newimages:
                        i += 1
                        #Pad with spaces so that each key is unique.
                        image.desc += u' ' * i
                    audio[image.HashKey] = image
                    newimages.append(image.HashKey)
                [toremove.append(z) for z in old_apics if z not in newimages]
            else:
                toremove.extend(old_apics)

            for z in set(toremove):
                try:
                    del (audio[z])
                except KeyError:
                    continue

            audio.tags.filename = self.filepath
            v1 = v1_option if v1 is None else v1
            v2 = v2_option if v2 is None else v2

            if AIFF is not None and id3_filetype is AIFFFileType:
                if v2 == 3:
                    audio.tags.save(v2_version=3)  #AIFF doesn't support id3v1
                else:
                    audio.tags.save()  #AIFF doesn't support id3v1

            elif DSF is not None and id3_filetype is DSFFileType:
                if v2 == 3:
                    audio.tags.save(v2_version=3)  #DSF doesn't support id3v1
                else:
                    audio.tags.save()  #DSF doesn't support id3v1
            else:
                if v2 == 4:
                    audio.tags.update_to_v24()
                    audio.tags.save(v1=v1, v2=4)
                else:
                    c = ID3()
                    c.filename = self.filepath
                    c.update(audio)
                    c.update_to_v23()
                    c.save(v1=v1, v2=3)

            self.__tags['__tag_read'] = u'ID3v2.4' if v2 == 4 else u'ID3v2.3'
            self.update_tag_list()
            self._originaltags = audio.keys()

        def set_fundamentals(self, tags, mut_obj, images=None):
            self.__tags = tags
            self.mut_obj = mut_obj
            if images:
                self.images = images
            self._originaltags = tags.keys()
            self.set_attrs(ATTRIBUTES, tags)

        def to_encoding(self, encoding=UTF8):
            frames = []
            saved = []
            for frame in self.__tags.values():
                if hasattr(frame, 'encoding'):
                    frames.append((frame, frame.encoding))
                    frame.encoding = encoding
            try:
                self.save(v2=4)
            except:
                for frame, enc in frames:
                    frame.encoding = enc
                raise

        def update_tag_list(self):
            tag = self.__tags['__tag_read']
            l = tag_versions.tags_in_file(self.filepath)
            if l:
                if tag and tag in l:
                    l.remove(tag)
                    l.insert(0, tag)
                self.__tags['__tag'] = u', '.join(l)
            else:
                self.__tags['__tag'] = tag
예제 #11
0
    class Tag(TagBase):
        IMAGETAGS = (util.MIMETYPE, util.DESCRIPTION, util.DATA,
            util.IMAGETYPE)
        mapping = {}
        revmapping = {}

        def __init__(self, filename=None):
            self.__images = []

            self.__tags = CaselessDict() #Used as storage.
            #Each key as the is the field as used by puddletag, eg. 'artist'
            #Each value contains an mutagen.id3.Frame object
            #that have two methods, get_value and set_value.
            #get_value returns the value stored by the frame as
            #text/unicode list.
            #set_value should take text/unicode list in parse it into
            #it understands.

            #When saving the frame stored will be used. If it has a 'frames'
            #attributes, those frames will be used instead.

            util.MockTag.__init__(self, filename)

        def get_filepath(self):
            return util.MockTag.get_filepath(self)

        def set_filepath(self,  val):
            self.__tags.update(util.MockTag.set_filepath(self, val))

        filepath = property(get_filepath, set_filepath)

        def _get_images(self):
            return self.__images

        def _set_images(self, images):
            if images:
                self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                    images)
            else:
                self.__images = []
            cover_info(images, self.__tags)

        images = property(_get_images, _set_images)

        def _info(self):
            info = self.mut_obj.info
            fileinfo = [('Path', self[PATH]),
                        ('Size', str_filesize(int(self.size))),
                        ('Filename', self[FILENAME]),
                        ('Modified', self.modified)]
            try:
                version = self.mut_obj.tags.version
                version = ('ID3 Version', self.filetype)
            except AttributeError:
                version = ('ID3 Version', 'No tags in file.')
            fileinfo.append(version)

            mpginfo = [('Version', u'MPEG %i Layer %i' % (info.version, info.layer)),
                       ('Bitrate', self.bitrate),
                       ('Frequency', self.frequency),
                       ('Mode', MODES[info.mode]),
                       ('Length', self.length)]

            return [('File', fileinfo), (mpginfo[0][0], mpginfo)]

        info = property(_info)

        def __contains__(self, key):
            if key == '__image':
                return bool(self.images)

            elif key == '__total':
                try:
                    return bool(get_total(self))
                except (KeyError, ValueError):
                    return False

            if self.revmapping:
                key = self.revmapping.get(key, key)

            return key in self.__tags

        def __deepcopy__(self, memo=None):
            cls = Tag()
            tags = CaselessDict()
            frames = []
            [frames.append(frame) if not hasattr(frame, 'frames') else
                frames.extend(frame.frames) for key, frame in self.__tags.items()
                if not key.startswith('__')]
            funcs = []
            frames_copy = []
            for frame in frames:
                funcs.append((getattr(frame, 'get_value', None),
                    getattr(frame, 'set_value', None)))
                if hasattr(frame, 'get_value'):
                    delattr(frame, 'get_value')
                if hasattr(frame, 'set_value'):
                    delattr(frame, 'set_value')
                frames_copy.append(deepcopy(frame))
            tags = handle(dict([(frame.HashKey, frame) for frame in frames_copy]))
            for frame, (get_value, set_value) in zip(frames, funcs):
                if get_value is not None:
                    frame.get_value = get_value
                if set_value is not None:
                    frame.set_value = set_value
            for key, value in self.__tags.items():
                if key not in tags:
                    tags[key] = deepcopy(value)
            cls.set_fundamentals(tags,
                self.mut_obj, deepcopy(self.images))
            cls.filepath = self.filepath
            return cls

        @del_deco
        def __delitem__(self, key):
            if key == '__image':
                self.images = []
            elif key.startswith('__'):
                return
            else:
                del(self.__tags[key])

        @getdeco
        def __getitem__(self,key):
            if key.startswith('__'):
                if key == '__image':
                    return self.images
                elif key == '__filetype':
                    return self.filetype
                elif key == '__total':
                    return get_total(self)
                else:
                    return self.__tags[key]
            elif not isinstance(key, basestring):
                return self.__tags[key]
            else:
                return self.__tags[key].get_value()

        @setdeco
        def __setitem__(self, key, value):
            if not isinstance(key, basestring):
                self.__tags[key] = value
                return
            if key.startswith('__'):
                if key == '__image':
                    self.images = value
                elif key in fn_hash:
                    setattr(self, fn_hash[key], value)
                elif key == '__total':
                    set_total(self, value)
                return

            value = unicode_list(value)

            if isempty(value):
                if key in self:
                    del(self[key])
                return

            if key in self.__tags:
                self.__tags[key].set_value(value)
            else:
                if key in write_frames:
                    self.__tags.update(write_frames[key](value))
                elif key == u'comment':
                    frame = {'comment': create_comment('', value)['comment:']}
                    self.__tags.update(frame)
                elif key.startswith('comment:'):
                    self.__tags.update(create_comment(key[len('comment:'):], value))
                elif key.startswith('www:'):
                    self.__tags.update(create_userurl(key, value))
                elif key.startswith('ufid:'):
                    self.__tags.update(create_ufid(key, value))
                elif key.startswith('rgain:'):
                    self.__tags.update(create_rgain(key, value))
                elif key.startswith('unsyncedlyrics:'):
                    self.__tags.update(create_uslt(key, value))
                else:
                    self.__tags.update(create_usertext(key, value))

        def delete(self):
            self.mut_obj.delete()
            for key in self.usertags:
                del(self.__tags[self.revmapping.get(key, key)])
            self.images = []

        @keys_deco
        def keys(self):
            return self.__tags.keys()

        def link(self, filename):
            """Links the audio, filename
            returns self if successful, None otherwise."""
            self.__images = []
            tags, audio = self.load(filename, id3_filetype)
            if audio is None:
                return

            if audio.tags: #Not empty
                audio.tags.update_to_v24()
                self.__tags.update(handle(audio))

                #Get the image data.
                apics = audio.tags.getall("APIC")
                if apics:
                    self.images = map(bin_to_pic, apics)
                else:
                    self.images = [];

            self.__tags.update(tags)
            self.__tags.update(info_to_dict(audio.info))

            if self.ext.lower() == 'mp3':
                self.__tags['__filetype'] = u'MP3'
            else:
                self.__tags['__filetype'] = u'ID3'

            self.set_attrs(ATTRIBUTES, self.__tags)

            try:
                self.__tags['__tag_read'] = u'ID3v%s.%s' % audio.tags.version[:2]
            except AttributeError:
                self.__tags['__tag_read'] = u''
            self.mut_obj = audio
            self._originaltags = audio.keys()
            self.update_tag_list()
            return self

        def save(self, v1=None, v2=None):
            if v1 is None:
                v1 = v1_option
            """Writes the tags to file."""
            filename = self.filepath
            if self.mut_obj.tags is None:
                self.mut_obj.add_tags()
            if filename != self.mut_obj.filename:
                self.mut_obj.tags.filename = filename
                self.mut_obj.filename = filename
            audio = self.mut_obj
            util.MockTag.save(self)

            userkeys = usertags(self.__tags).keys()
            frames = []
            [frames.append(frame) if not hasattr(frame, 'frames') else
                frames.extend(frame.frames) for key, frame in self.__tags.items()
                if key in userkeys]
            hashes = dict([(frame.HashKey, frame) for frame in frames])
            toremove = [z for z in self._originaltags if z in audio
                        and not (z in hashes or z.startswith('APIC'))]
            audio.update(hashes)

            old_apics = [z for z in audio if z.startswith(u'APIC')]
            if self.__images:
                newimages = []
                for image in filter(None, map(pic_to_bin, self.__images)):
                    i = 0
                    while image.HashKey in newimages:
                        i += 1
                        #Pad with spaces so that each key is unique.
                        image.desc += u' '*i
                    audio[image.HashKey] = image
                    newimages.append(image.HashKey)
                [toremove.append(z) for z in old_apics if z not in newimages]
            else:
                toremove.extend(old_apics)

            for z in set(toremove):
                try:
                    del(audio[z])
                except KeyError:
                    continue

            audio.tags.filename = self.filepath
            v1 = v1_option if v1 is None else v1
            v2 = v2_option if v2 is None else v2

            if AIFF is not None and id3_filetype is AIFFFileType:
                if v2 == 3:
                    audio.tags.save(v2_version=3) #AIFF doesn't support id3v1
                else:
                    audio.tags.save() #AIFF doesn't support id3v1
            else:
                if v2 == 4:
                    audio.tags.update_to_v24()
                    audio.tags.save(v1=v1, v2=4)
                else:
                    c = ID3()
                    c.filename = self.filepath
                    c.update(audio)
                    c.update_to_v23()
                    c.save(v1=v1, v2=3)

            self.__tags['__tag_read'] = u'ID3v2.4' if v2 == 4 else u'ID3v2.3'
            self.update_tag_list()
            self._originaltags = audio.keys()

        def set_fundamentals(self, tags, mut_obj, images=None):
            self.__tags = tags
            self.mut_obj = mut_obj
            if images:
                self.images = images
            self._originaltags = tags.keys()
            self.set_attrs(ATTRIBUTES, tags)

        def to_encoding(self, encoding = UTF8):
            frames = []
            saved = []
            for frame in self.__tags.values():
                if hasattr(frame, 'encoding'):
                    frames.append((frame, frame.encoding))
                    frame.encoding = encoding
            try:
                self.save(v2=4)
            except:
                for frame, enc in frames:
                    frame.encoding = enc
                raise

        def update_tag_list(self):
            tag = self.__tags['__tag_read']
            l = tag_versions.tags_in_file(self.filepath)
            if l:
                if tag and tag in l:
                    l.remove(tag)
                    l.insert(0, tag)
                self.__tags['__tag'] = u', '.join(l)
            else:
                self.__tags['__tag'] = tag
예제 #12
0
    class APEv2Base(MockTag):
        """Tag class for APEv2 files.

        Tags are used as in ogg.py"""
        IMAGETAGS = (util.MIMETYPE, util.DESCRIPTION, util.DATA,
                     util.IMAGETYPE)
        mapping = {}
        revmapping = {}
        apev2 = True

        def __init__(self, filename=None):
            self.__images = []
            self.__tags = CaselessDict()

            MockTag.__init__(self, filename)

        def get_filepath(self):
            return MockTag.get_filepath(self)

        def set_filepath(self, val):
            self.__tags.update(MockTag.set_filepath(self, val))

        filepath = property(get_filepath, set_filepath)

        def _get_images(self):
            return self.__images

        def _set_images(self, images):
            if images:
                self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                                    images)
            else:
                self.__images = []
            cover_info(images, self.__tags)

        images = property(_get_images, _set_images)

        def __contains__(self, key):
            if key == '__image':
                return bool(self.images)

            elif key == '__total':
                try:
                    return bool(get_total(self))
                except (KeyError, ValueError):
                    return False

            if self.revmapping:
                key = self.revmapping.get(key, key)
            return key in self.__tags

        def __deepcopy__(self, memo):
            cls = Tag()
            cls.mapping = self.mapping
            cls.revmapping = self.revmapping
            cls.set_fundamentals(deepcopy(self.__tags), self.mut_obj,
                                 self.images)
            cls.filepath = self.filepath
            return cls

        @del_deco
        def __delitem__(self, key):
            if key == '__image':
                self.images = []
            elif key.startswith('__'):
                return
            else:
                del (self.__tags[key])

        @getdeco
        def __getitem__(self, key):
            if key == '__image':
                return self.images
            elif key == '__total':
                return get_total(self)
            return self.__tags[key]

        @setdeco
        def __setitem__(self, key, value):

            if key == '__image':
                self.images = value
                return

            if key.startswith('__'):
                if key == '__image':
                    self.images = value
                elif key == '__total':
                    set_total(self, value)
                elif key in fn_hash:
                    setattr(self, fn_hash[key], value)
                return
            elif isempty(value):
                if key in self:
                    del (self[key])
            else:
                value = unicode_list(value)
                if isempty(value): return
                self.__tags[key] = value

        def delete(self):
            self.mut_obj.delete()
            for key in self.usertags:
                del (self.__tags[self.revmapping.get(key, key)])
            self.images = []

        def _info(self):
            info = self.mut_obj.info
            fileinfo = [(u'Path', self[PATH]),
                        (u'Size', str_filesize(int(self.size))),
                        (u'Filename', self[FILENAME]),
                        (u'Modified', self.modified)]
            apeinfo = [('Length', self.length)]
            attr = [(u'Channels', 'channels'), (u'Version', 'version')]
            for k, v in attr:
                try:
                    apeinfo.append([k, unicode(getattr(info, v))])
                except AttributeError:
                    continue
            return [('File', fileinfo), ("%s Info" % self.filetype, apeinfo)]

        info = property(_info)

        @keys_deco
        def keys(self):
            return self.__tags.keys()

        def link(self, filename):
            """Links the audio, filename
            returns self if successful, None otherwise."""
            no_header = DefaultHeaderError if header_error is None \
                else header_error

            self.__images = []
            try:
                tags, audio = self.load(filename, mutagen_file)
            except no_header:  #Try loading just APEv2
                tags, audio = self.load(filename, APEv2File)
            except APENoHeaderError:
                audio = mutagen_file()
                tags, audio = self.load(filename, None)
                audio.filename = tags['__filepath']

            if audio is None:
                return

            images = []
            for key in audio:
                try:
                    if key.lower() in COVER_KEYS:
                        img_type = COVER_KEYS.get(key.lower(), 3)
                        images.append(bin_to_pic(audio[key].value, img_type))
                    else:
                        self.__tags[key.lower()] = audio.tags[key][:]
                except TypeError:
                    pass

            self.images = images
            self.__tags.update(info_to_dict(audio.info))
            self.__tags.update(tags)
            self.__tags['__tag_read'] = u'APEv2'
            self.set_attrs(attrib_fields)
            self.filetype = filetype
            self.__tags['__filetype'] = filetype
            self.update_tag_list()
            self.mut_obj = audio
            return self

        def save(self):
            if self.mut_obj.tags is None:
                self.mut_obj.add_tags()
            if self.filepath != self.mut_obj.filename:
                self.mut_obj.filename = self.filepath
            audio = self.mut_obj

            newtag = {}
            if self.images:
                [newtag.update(pic_to_bin(z)) for z in self.images]
            for field, value in usertags(self.__tags).items():
                try:
                    if isinstance(field, unicode):
                        field = field.encode('utf8')
                    newtag[field] = value
                except AttributeError:
                    pass
            toremove = [
                z for z in audio if z not in newtag and audio[z].kind == 0
            ]
            for z in toremove:
                del (audio[z])
            audio.tags.update(newtag)
            audio.save()

        def set_fundamentals(self, tags, mut_obj, images=None):
            self.__tags = tags
            self.mut_obj = mut_obj
            if images:
                self.images = images
            self._originaltags = tags.keys()

        def update_tag_list(self):
            l = tag_versions.tags_in_file(
                self.filepath, [tag_versions.ID3_V1, tag_versions.ID3_V2])
            if l:
                self.__tags['__tag'] = u'APEv2, ' + u', '.join(l)
            else:
                self.__tags['__tag'] = u'APEv2'
예제 #13
0
        def __init__(self, filename=None):
            self.__images = []
            self.__tags = CaselessDict()

            MockTag.__init__(self, filename)
예제 #14
0
    class APEv2Base(MockTag):
        """Tag class for APEv2 files.

        Tags are used as in ogg.py"""
        IMAGETAGS = (util.MIMETYPE, util.DESCRIPTION, util.DATA, util.IMAGETYPE)
        mapping = {}
        revmapping = {}
        apev2 = True

        def __init__(self, filename=None):
            self.__images = []
            self.__tags = CaselessDict()

            MockTag.__init__(self, filename)

        def get_filepath(self):
            return MockTag.get_filepath(self)

        def set_filepath(self,  val):
            self.__tags.update(MockTag.set_filepath(self, val))

        filepath = property(get_filepath, set_filepath)

        def _get_images(self):
            return self.__images

        def _set_images(self, images):
            if images:
                self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                    images)
            else:
                self.__images = []
            cover_info(images, self.__tags)

        images = property(_get_images, _set_images)

        def __contains__(self, key):
            if key == '__image':
                return bool(self.images)
            
            elif key == '__total':
                try:
                    return bool(get_total(self))
                except (KeyError, ValueError):
                    return False
            
            if self.revmapping:
                key = self.revmapping.get(key, key)
            return key in self.__tags

        def __deepcopy__(self, memo):
            cls = Tag()
            cls.mapping = self.mapping
            cls.revmapping = self.revmapping
            cls.set_fundamentals(deepcopy(self.__tags),
                self.mut_obj, self.images)
            cls.filepath = self.filepath
            return cls

        @del_deco
        def __delitem__(self, key):
            if key == '__image':
                self.images = []
            elif key.startswith('__'):
                return
            else:
                del(self.__tags[key])

        @getdeco
        def __getitem__(self, key):
            if key == '__image':
                return self.images
            elif key == '__total':
                return get_total(self)
            return self.__tags[key]

        @setdeco
        def __setitem__(self, key, value):
            
            if key == '__image':
                self.images = value
                return

            if key.startswith('__'):
                if key == '__image':
                    self.images = value
                elif key == '__total':
                    set_total(self, value)
                elif key in fn_hash:
                    setattr(self, fn_hash[key], value)
                return
            elif isempty(value):
                if key in self:
                    del(self[key])
            else:
                value = unicode_list(value)
                if isempty(value): return
                self.__tags[key] = value

        def delete(self):
            self.mut_obj.delete()
            for key in self.usertags:
                del(self.__tags[self.revmapping.get(key, key)])
            self.images = []

        def _info(self):
            info = self.mut_obj.info
            fileinfo = [(u'Path', self[PATH]),
                        (u'Size', str_filesize(int(self.size))),
                        (u'Filename', self[FILENAME]),
                        (u'Modified', self.modified)]
            apeinfo = [('Length', self.length)]
            attr = [
                (u'Channels', 'channels'),
                (u'Version', 'version')]
            for k, v in attr:
                try:
                    apeinfo.append([k, unicode(getattr(info, v))])
                except AttributeError:
                    continue
            return [('File', fileinfo), ("%s Info" % self.filetype, apeinfo)]

        info = property(_info)

        @keys_deco
        def keys(self):
            return self.__tags.keys()

        def link(self, filename):
            """Links the audio, filename
            returns self if successful, None otherwise."""
            no_header = DefaultHeaderError if header_error is None \
                else header_error

            self.__images = []
            try:
                tags, audio = self.load(filename, mutagen_file)
            except no_header: #Try loading just APEv2
                tags, audio = self.load(filename, APEv2File)
            except APENoHeaderError:
                audio = mutagen_file()
                tags, audio = self.load(filename, None)
                audio.filename = tags['__filepath']

            if audio is None:
                return

            images = []
            for key in audio:
                try:
                    if key.lower() in COVER_KEYS:
                        img_type = COVER_KEYS.get(key.lower(), 3)
                        images.append(
                            bin_to_pic(audio[key].value, img_type))
                    else:
                        self.__tags[key.lower()] = audio.tags[key][:]
                except TypeError:
                    pass

            self.images = images
            self.__tags.update(info_to_dict(audio.info))
            self.__tags.update(tags)
            self.__tags['__tag_read'] = u'APEv2'
            self.set_attrs(attrib_fields)
            self.filetype = filetype
            self.__tags['__filetype'] = filetype
            self.update_tag_list()
            self.mut_obj = audio
            return self

        def save(self):
            if self.mut_obj.tags is None:
                self.mut_obj.add_tags()
            if self.filepath != self.mut_obj.filename:
                self.mut_obj.filename = self.filepath
            audio = self.mut_obj

            newtag = {}
            if self.images:
                [newtag.update(pic_to_bin(z)) for z in self.images]
            for field, value in usertags(self.__tags).items():
                try:
                    if isinstance(field, unicode):
                        field = field.encode('utf8')
                    newtag[field] = value
                except AttributeError:
                    pass
            toremove = [z for z in audio if z
                not in newtag and audio[z].kind == 0]
            for z in toremove:
                del(audio[z])
            audio.tags.update(newtag)
            audio.save()

        def set_fundamentals(self, tags, mut_obj, images=None):
            self.__tags = tags
            self.mut_obj = mut_obj
            if images:
                self.images = images
            self._originaltags = tags.keys()

        def update_tag_list(self):
            l = tag_versions.tags_in_file(self.filepath,
                [tag_versions.ID3_V1, tag_versions.ID3_V2])
            if l:
                self.__tags['__tag'] = u'APEv2, ' + u', '.join(l)
            else:
                self.__tags['__tag'] = u'APEv2'
예제 #15
0
class Tag(util.MockTag):
    """Class for AAC tags."""

    mapping = {}
    revmapping = {}
    IMAGETAGS = (util.MIMETYPE, util.DATA)

    def __init__(self, filename=None):
        self.__images = []
        self.__errors = set()
        self.__tags = CaselessDict()

        util.MockTag.__init__(self, filename)

    def get_filepath(self):
        return util.MockTag.get_filepath(self)

    def set_filepath(self, val):
        self.__tags.update(util.MockTag.set_filepath(self, val))

    filepath = property(get_filepath, set_filepath)

    def __contains__(self, key):
        if key == '__image':
            return bool(self.images)

        elif key == '__total':
            try:
                return bool(get_total(self))
            except (KeyError, ValueError):
                return False

        if self.revmapping:
            key = self.revmapping.get(key, key)
        return key in self.__tags

    def __deepcopy__(self, memo=None):
        cls = Tag()
        cls.mapping = self.mapping
        cls.revmapping = self.revmapping
        cls.set_fundamentals(deepcopy(self.__tags), deepcopy(self.images),
                             self.mut_obj, deepcopy(self.__freeform),
                             deepcopy(self.__errors))
        cls.filepath = self.filepath
        return cls

    @del_deco
    def __delitem__(self, key):
        if key == '__image':
            self.images = []
        elif key.startswith('__'):
            return
        else:
            del (self.__tags[key])

    @getdeco
    def __getitem__(self, key):
        if key.startswith('__'):
            if key == '__image':
                return self.images
            elif key == '__total':
                return FUNCS['totaltracks'][0](self.__tags['totaltracks'])
            else:
                return self.__tags[key]

        try:
            return FUNCS[key][0](self.__tags[key])
        except KeyError:
            return gettext(self.__tags[key])

    @setdeco
    def __setitem__(self, key, value):
        if isinstance(key, (int, long)):
            self.__tags[key] = value
            return
        elif key.startswith('__'):
            if key == '__image':
                self.images = value
            if key in FILETAGS:
                setattr(self, fn_hash[key], value)
            elif key == '__total':
                self.__tags['totaltracks'] = FUNCS['totaltracks'][1](value)
            return
        elif isempty(value):
            if key in self:
                del (self[key])
            return
        else:
            try:
                new_val = FUNCS[key][1](value)
                if value:
                    self.__tags[key] = new_val
            except KeyError:
                #User defined tags.
                self.__freeform[key] = '----:com.apple.iTunes:%s' % key
                self.__tags[key] = settext(value)
            except ValueError:
                pass

    def delete(self):
        self.mut_obj.delete()
        for key in self.usertags:
            del (self.__tags[self.revmapping.get(key, key)])
        self.images = []

    def _set_images(self, images):
        if images:
            self.__images = map(lambda i: parse_image(i, self.IMAGETAGS),
                                images)
        else:
            self.__images = []
        cover_info(images, self.__tags)

    def _get_images(self):
        return self.__images

    images = property(_get_images, _set_images)

    def _info(self):
        info = self.mut_obj.info
        fileinfo = [('Path', self[PATH]),
                    ('Size', str_filesize(int(self.size))),
                    ('Filename', self[FILENAME]), ('Modified', self.modified)]

        mp4info = [('Bitrate', self.bitrate), ('Frequency', self.frequency),
                   ('Channels', unicode(info.channels)),
                   ('Length', self.length),
                   ('Bits per sample', unicode(info.bits_per_sample))]

        return [('File', fileinfo), ('MP4 Info', mp4info)]

    info = property(_info)

    def link(self, filename):
        """Links the audio, filename
        returns self if successful, None otherwise."""

        tags, audio = self.load(filename, MP4)
        self.images = []

        if audio is None:
            return

        revmap, mapping = self.revmapping, self.mapping
        self.revmapping, self.mapping = {}, {}

        self.__freeform = {
        }  #Keys are tags as required by mutagen i.e. The '----'
        #frames. Values are the tag as represented by puddletag.

        if audio.tags:  #Not empty
            keys = audio.keys()
            try:
                self.images = map(bin_to_pic, audio['covr'])
                keys.remove('covr')
            except KeyError:
                self.images = []

            convert = lambda k, v: FUNCS[k][1](v)

            #I want 'trkn', to split into track and totaltracks, like Mp3tag.
            if 'trkn' in keys:
                tags['track'] = convert('track', [z[0] for z in audio['trkn']])
                tags['totaltracks'] = convert('totaltracks',
                                              [z[1] for z in audio['trkn']])
                keys.remove('trkn')

            #Same as above
            if 'disk' in keys:
                tags['disc'] = convert('disc', [z[0] for z in audio['disk']])
                tags['totaldiscs'] = convert('totaldiscs',
                                             [z[1] for z in audio['disk']])
                keys.remove('disk')

            for key in keys:
                if key in TAGS:
                    tags[TAGS[key]] = convert(TAGS[key], audio[key])
                else:
                    field = key[key.find(':', key.find(':') + 1) + 1:]
                    try:
                        field = field.decode('utf8')
                    except UnicodeDecodeError:
                        field = field.decode('latin1')

                    self.__freeform[field] = key
                    try:
                        field_value = []
                        for v in audio[key]:
                            if isinstance(v, str):
                                field_value.append(unicode(v, 'utf8'))
                            elif isinstance(v, unicode):
                                field_value.append(v)
                            else:
                                field_value.append(unicode(v))
                    except UnicodeDecodeError:
                        self.__errors.add(field)

        for k, v in tags.items():
            if not v:
                del (tags[k])

        self.__tags.update(info_to_dict(audio.info))
        self.__tags.update(tags)
        self.revmapping, self.mapping = revmap, mapping
        self.__tags['__tag_read'] = u'MP4'
        self.filetype = 'MP4'
        self.__tags['__filetype'] = self.filetype
        self.set_attrs(ATTRIBUTES, self.__tags)
        self.update_tag_list()
        self.mut_obj = audio

    @keys_deco
    def keys(self):
        return self.__tags.keys()

    def save(self):
        if self.mut_obj.tags is None:
            self.mut_obj.add_tags()
        if self.filepath != self.mut_obj.filename:
            self.mut_obj.filename = self.filepath
        audio = self.mut_obj

        newtag = {}
        tuples = (('track', ['trkn',
                             'totaltracks']), ('disc', ['disk', 'totaldiscs']))
        tags = self.__tags
        for tag, values in tuples:
            if tag in tags:
                denom = tags[tag]
                if values[1] in tags:
                    total = tags[values[1]]
                    newtag[values[0]] = [(int(t), int(total))
                                         for t, total in zip(denom, total)]
                else:
                    newtag[values[0]] = [(int(z), 0) for z in denom]
            elif values[1] in tags:
                total = tags[values[1]]
                newtag[values[0]] = [(0, int(z)) for z in total]

        tags = usertags(self.__tags)
        tags = [(z, tags[z]) for z in tags
                if z not in ['track', 'totaltracks', 'disc', 'totaldiscs']]

        for tag, value in tags:
            try:
                newtag[REVTAGS[tag]] = value
            except KeyError:
                newtag[self.__freeform[tag].encode('utf8')] = encode(
                    self.__tags[tag])

        if self.images:
            newtag['covr'] = filter(None, map(pic_to_bin, self.images))

        toremove = [
            z for z in audio.keys()
            if z not in newtag and z not in self.__errors
        ]
        for key in toremove:
            del (audio[key])
        audio.update(newtag)
        audio.save()

    def set_fundamentals(self,
                         tags,
                         images,
                         mut_obj,
                         freeform=None,
                         errors=None):
        self.__freeform = {} if freeform is None else freeform
        self.__errors = {} if errors is None else errors
        self.__tags = tags
        self.mut_obj = mut_obj
        self.images = images

    def update_tag_list(self):
        l = tag_versions.tags_in_file(self.filepath)
        if l:
            self.__tags['__tag'] = u'MP4, ' + u', '.join(l)
        else:
            self.__tags['__tag'] = u'MP4'