[Tutor] How to map different keys together ?
Damon Timm
damontimm at gmail.com
Sun Apr 18 19:42:46 CEST 2010
Hi Alan, et al - thanks for your response and your ideas. I sat down
and did a little more coding so that I might tackle what I can and
bring back where I am having trouble. I have implemented the basic
'tag_map' you suggested without a hitch using my own class and
getitem/setitem builtins. Right now, if there is a one-to-one
correlation between my *generic* key (as a standard between my music
files) and the specific tag for the filetype, I am doing well.
However, everything is not so clear cut in the world of metatagging!
My first stumbling block is that M4A files store the track number and
track total in a single tuple ... but I need them as separate fields
(which is how some of the other formats do it). This is going to be
one of many hurdles -- I need a way to accomplish more than a
one-to-one data map.
See my code, below, as well as some command line examples where I am
having trouble. I feel there may be a way to pass functions through
my tag_map dictionary (maybe a lambda?!) but I can't get my head
around what approach is best (I can't think of any approach, right
now, actually).
Code follows. Thanks again.
class Tags(object):
'''Wrapper class for a mutagen music file object.'''
tag_map = {}
def __init__(self, mutagen):
self._mutagen = mutagen
self.tags = {}
def keys(self):
'''Get list of generic tag keys in use'''
keys = []
for k in self.tag_map.keys():
try:
self._mutagen[self.tag_map[k]]
keys.append(k)
except KeyError:
pass
return keys
def save(self):
'''Save the mutagen changes.'''
self._mutagen.save()
class MP4Tags(Tags):
tag_map = {
# GENERIC : SPECIFIC
'title' : '\xa9nam',
'album' : '\xa9alb',
'artist' : '\xa9ART',
'albumartist' : 'aART',
'comment' : '\xa9cmt',
'compilation' : 'cpil',
'composer' : '\xa9wrt',
'genre' : '\xa9gen',
'discnumber' : 'disk', # returns: (2,10) need lmbda or something ?!
'disctotal' : 'disk', # returns: (2,10) need lmbda or something ?!
'year' : '\xa9day',
'tracknumber' : 'trkn', # returns: (2,10) need lmbda or something ?!
'tracktotal' : 'trkn' # returns: (2,10) need lmbda or something ?!
}
def __getitem__(self, key):
try:
return self._mutagen[self.tag_map[key]]
except KeyError:
pass
def __setitem__(self, key, value):
self._mutagen[self.tag_map[key]] = value
#EOF
**Here is how it works:
>>> import tagging
>>> from mutagen.mp4 import MP4
>>> mp4 = MP4('../tests/data/Compressed/M4A-256.m4a')
>>> mp4_tags = tagging.MP4Tags(mp4)
>>> mp4_tags['title']
[u'bob the builder'] # woo hoo! it works!
>>> mp4_tags['title'] = [u'I can change the title!']
>>> mp4_tags['title']
[u'I can change the title!'] # changing the titles works too
>>> mp4_tags['discnumber']
[(1, 1)] # TODO - I need to return disk[0][0] ... not the tuple
>>> mp4_tags.save()
So, I need to modify how the data is shown to me as well as how I
would go about writing the data something like:
return_tag(disk): return disk[0][0]
save_tag(num): return [(%s, %s)] % ( num,
somehow_get_the_original_second_value_before_re_saving)
Thanks again and any advice or guidance about how to approach this is
greatly appreciated.
Damon
On Sat, Apr 17, 2010 at 3:55 PM, Alan Gauld <alan.gauld at btinternet.com> wrote:
>
> "Damon Timm" <damontimm at gmail.com> wrote
>
>> I am struggling, on a theoretical level, on how to map the various
>> filetype's tag/key naming conventions. I have already created my own
>> MusicFile objects to handle each filetype (with functions for
>> encoding/decoding) but I can't wrap my head around how to map the
>> tags.
>
> I'd define a mapping table per file type that maps from a standad
> set of keys to the file specific tag.
>
> Then define a class that works with the generic tags.
> You can then eirther subclass per file type and use the file specific
> mapping(a class variable) to translate internally or just create a function
> that takes the file mapping as a parameter(maybe in the init() ) and sets
> it up for the generic methods to use.
>
>> And here is what I would need to do to find the song's TITLE text:
>>
>>>>> flac['title']
>>
>> [u'Christmas Waltz']
>>>>>
>>>>> mp3['TIT2'].text #notice this one takes another additional step, as
>>>>> well, by specifying text !
>>
>> [u'Christmas Waltz']
>>>>>
>>>>> mp4['\xa9nam']
>>
>> [u"Christmas Waltz"]
>
> So if the file is mp3 the generic
>
> foo.setTag('title')
>
> will inside the setTag method do
>
> def setTag(self, tag, value)
> key = self.mapping[tag] # get file specific tag
> fileData[key] = value # and use it
> # or
> self.value = fileData[key]
>
>> approach this. I know I could manually assign each key to a class
>> property (using the @property tag) ... but this seems tedious:
>
> That would definitely be overklilll and not bvery flexible for adding new
> file types.
>
> HTH,
>
>
> --
> Alan Gauld
> Author of the Learn to Program web site
> http://www.alan-g.me.uk/
>
> _______________________________________________
> Tutor maillist - Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
>
More information about the Tutor
mailing list