~ubuntu-branches/ubuntu/utopic/mutagen/utopic-proposed

« back to all changes in this revision

Viewing changes to mutagen/easyid3.py

  • Committer: Package Import Robot
  • Author(s): Daniel T Chen
  • Date: 2013-11-27 22:10:48 UTC
  • mfrom: (8.1.17 sid)
  • Revision ID: package-import@ubuntu.com-20131127221048-ae2f5j42ak2ox3kw
Tags: 1.22-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - debian/control: Drop faad and oggz-tools build dependencies (in
    universe).

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of version 2 of the GNU General Public License as
6
6
# published by the Free Software Foundation.
7
 
#
8
 
# $Id: id3.py 3086 2006-04-04 02:13:21Z piman $
9
7
 
10
8
"""Easier access to ID3 tags.
11
9
 
13
11
more like Vorbis or APEv2 tags.
14
12
"""
15
13
 
16
 
from fnmatch import fnmatchcase
17
 
 
18
14
import mutagen.id3
19
15
 
20
16
from mutagen import Metadata
21
17
from mutagen._util import DictMixin, dict_match
22
18
from mutagen.id3 import ID3, error, delete, ID3FileType
23
19
 
 
20
 
24
21
__all__ = ['EasyID3', 'Open', 'delete']
25
22
 
 
23
 
26
24
class EasyID3KeyError(KeyError, ValueError, error):
27
25
    """Raised when trying to get/set an invalid key.
28
26
 
30
28
    catching KeyError is preferred.
31
29
    """
32
30
 
 
31
 
33
32
class EasyID3(DictMixin, Metadata):
34
33
    """A file with an ID3 tag.
35
34
 
44
43
    keys. These can be set on EasyID3 or on individual instances after
45
44
    creation.
46
45
 
47
 
    To use an EasyID3 class with mutagen.mp3.MP3:
 
46
    To use an EasyID3 class with mutagen.mp3.MP3::
 
47
 
48
48
        from mutagen.mp3 import EasyMP3 as MP3
49
49
        MP3(filename)
50
50
 
51
51
    Because many of the attributes are constructed on the fly, things
52
 
    like the following will not work:
 
52
    like the following will not work::
 
53
 
53
54
        ezid3["performer"].append("Joe")
54
 
    Instead, you must do:
 
55
 
 
56
    Instead, you must do::
 
57
 
55
58
        values = ezid3["performer"]
56
59
        values.append("Joe")
57
60
        ezid3["performer"] = values
58
61
 
59
 
 
60
62
    """
61
63
 
62
64
    Set = {}
71
73
    SetFallback = None
72
74
    DeleteFallback = None
73
75
    ListFallback = None
74
 
    
 
76
 
 
77
    @classmethod
75
78
    def RegisterKey(cls, key,
76
79
                    getter=None, setter=None, deleter=None, lister=None):
77
80
        """Register a new key mapping.
99
102
            cls.Delete[key] = deleter
100
103
        if lister is not None:
101
104
            cls.List[key] = lister
102
 
    RegisterKey = classmethod(RegisterKey)
103
105
 
 
106
    @classmethod
104
107
    def RegisterTextKey(cls, key, frameid):
105
108
        """Register a text key.
106
109
 
107
110
        If the key you need to register is a simple one-to-one mapping
108
111
        of ID3 frame name to EasyID3 key, then you can use this
109
 
        function:
 
112
        function::
 
113
 
110
114
            EasyID3.RegisterTextKey("title", "TIT2")
111
115
        """
112
116
        def getter(id3, key):
125
129
            del(id3[frameid])
126
130
 
127
131
        cls.RegisterKey(key, getter, setter, deleter)
128
 
    RegisterTextKey = classmethod(RegisterTextKey)
129
132
 
 
133
    @classmethod
130
134
    def RegisterTXXXKey(cls, key, desc):
131
135
        """Register a user-defined text frame key.
132
136
 
133
137
        Some ID3 tags are stored in TXXX frames, which allow a
134
138
        freeform 'description' which acts as a subkey,
135
 
        e.g. TXXX:BARCODE.
136
 
            EasyID3.RegisterTXXXKey('barcode', 'BARCODE').        
 
139
        e.g. TXXX:BARCODE.::
 
140
 
 
141
            EasyID3.RegisterTXXXKey('barcode', 'BARCODE').
137
142
        """
138
143
        frameid = "TXXX:" + desc
 
144
 
139
145
        def getter(id3, key):
140
146
            return list(id3[frameid])
141
147
 
146
152
                enc = 0
147
153
                # Store 8859-1 if we can, per MusicBrainz spec.
148
154
                for v in value:
149
 
                    if max(v) > u'\x7f':
 
155
                    if v and max(v) > u'\x7f':
150
156
                        enc = 3
151
157
                id3.add(mutagen.id3.TXXX(encoding=enc, text=value, desc=desc))
152
158
            else:
156
162
            del(id3[frameid])
157
163
 
158
164
        cls.RegisterKey(key, getter, setter, deleter)
159
 
    RegisterTXXXKey = classmethod(RegisterTXXXKey)
160
165
 
161
166
    def __init__(self, filename=None):
162
167
        self.__id3 = ID3()
224
229
                strings.append("%s=%s" % (key, value))
225
230
        return "\n".join(strings)
226
231
 
 
232
 
227
233
Open = EasyID3
228
234
 
 
235
 
229
236
def genre_get(id3, key):
230
237
    return id3["TCON"].genres
231
238
 
 
239
 
232
240
def genre_set(id3, key, value):
233
241
    try:
234
242
        frame = id3["TCON"]
238
246
        frame.encoding = 3
239
247
        frame.genres = value
240
248
 
 
249
 
241
250
def genre_delete(id3, key):
242
251
    del(id3["TCON"])
243
252
 
 
253
 
244
254
def date_get(id3, key):
245
255
    return [stamp.text for stamp in id3["TDRC"].text]
246
256
 
 
257
 
247
258
def date_set(id3, key, value):
248
259
    id3.add(mutagen.id3.TDRC(encoding=3, text=value))
249
260
 
 
261
 
250
262
def date_delete(id3, key):
251
263
    del(id3["TDRC"])
252
264
 
 
265
 
253
266
def performer_get(id3, key):
254
267
    people = []
255
268
    wanted_role = key.split(":", 1)[1]
264
277
        return people
265
278
    else:
266
279
        raise KeyError(key)
267
 
    
 
280
 
 
281
 
268
282
def performer_set(id3, key, value):
269
283
    wanted_role = key.split(":", 1)[1]
270
284
    try:
278
292
        people.append((wanted_role, v))
279
293
    mcl.people = people
280
294
 
 
295
 
281
296
def performer_delete(id3, key):
282
297
    wanted_role = key.split(":", 1)[1]
283
298
    try:
291
306
        mcl.people = people
292
307
    else:
293
308
        del(id3["TMCL"])
294
 
        
 
309
 
 
310
 
295
311
def performer_list(id3, key):
296
 
    try: mcl = id3["TMCL"]
 
312
    try:
 
313
        mcl = id3["TMCL"]
297
314
    except KeyError:
298
315
        return []
299
316
    else:
300
317
        return list(set("performer:" + p[0] for p in mcl.people))
301
318
 
 
319
 
302
320
def musicbrainz_trackid_get(id3, key):
303
321
    return [id3["UFID:http://musicbrainz.org"].data.decode('ascii')]
304
322
 
 
323
 
305
324
def musicbrainz_trackid_set(id3, key, value):
306
325
    if len(value) != 1:
307
326
        raise ValueError("only one track ID may be set per song")
314
333
    else:
315
334
        frame.data = value
316
335
 
 
336
 
317
337
def musicbrainz_trackid_delete(id3, key):
318
338
    del(id3["UFID:http://musicbrainz.org"])
319
339
 
 
340
 
320
341
def website_get(id3, key):
321
342
    urls = [frame.url for frame in id3.getall("WOAR")]
322
343
    if urls:
324
345
    else:
325
346
        raise EasyID3KeyError(key)
326
347
 
 
348
 
327
349
def website_set(id3, key, value):
328
350
    id3.delall("WOAR")
329
351
    for v in value:
330
352
        id3.add(mutagen.id3.WOAR(url=v))
331
353
 
 
354
 
332
355
def website_delete(id3, key):
333
356
    id3.delall("WOAR")
334
357
 
 
358
 
335
359
def gain_get(id3, key):
336
360
    try:
337
361
        frame = id3["RVA2:" + key[11:-5]]
340
364
    else:
341
365
        return [u"%+f dB" % frame.gain]
342
366
 
 
367
 
343
368
def gain_set(id3, key, value):
344
369
    if len(value) != 1:
345
 
        raise ValueError("there must be exactly one gain value, not %r.", value)
 
370
        raise ValueError(
 
371
            "there must be exactly one gain value, not %r.", value)
346
372
    gain = float(value[0].split()[0])
347
373
    try:
348
374
        frame = id3["RVA2:" + key[11:-5]]
351
377
        id3.add(frame)
352
378
    frame.gain = gain
353
379
 
 
380
 
354
381
def gain_delete(id3, key):
355
382
    try:
356
383
        frame = id3["RVA2:" + key[11:-5]]
362
389
        else:
363
390
            del(id3["RVA2:" + key[11:-5]])
364
391
 
 
392
 
365
393
def peak_get(id3, key):
366
394
    try:
367
395
        frame = id3["RVA2:" + key[11:-5]]
370
398
    else:
371
399
        return [u"%f" % frame.peak]
372
400
 
 
401
 
373
402
def peak_set(id3, key, value):
374
403
    if len(value) != 1:
375
 
        raise ValueError("there must be exactly one peak value, not %r.", value)
 
404
        raise ValueError(
 
405
            "there must be exactly one peak value, not %r.", value)
376
406
    peak = float(value[0])
377
407
    if peak >= 2 or peak < 0:
378
408
        raise ValueError("peak must be => 0 and < 2.")
383
413
        id3.add(frame)
384
414
    frame.peak = peak
385
415
 
 
416
 
386
417
def peak_delete(id3, key):
387
418
    try:
388
419
        frame = id3["RVA2:" + key[11:-5]]
394
425
        else:
395
426
            del(id3["RVA2:" + key[11:-5]])
396
427
 
 
428
 
397
429
def peakgain_list(id3, key):
398
430
    keys = []
399
431
    for frame in id3.getall("RVA2"):
404
436
for frameid, key in {
405
437
    "TALB": "album",
406
438
    "TBPM": "bpm",
407
 
    "TCMP": "compilation", # iTunes extension
 
439
    "TCMP": "compilation",  # iTunes extension
408
440
    "TCOM": "composer",
409
441
    "TCOP": "copyright",
410
442
    "TENC": "encodedby",
415
447
    "TIT2": "title",
416
448
    "TIT3": "version",
417
449
    "TPE1": "artist",
418
 
    "TPE2": "performer", 
 
450
    "TPE2": "performer",
419
451
    "TPE3": "conductor",
420
452
    "TPE4": "arranger",
421
453
    "TPOS": "discnumber",
422
454
    "TPUB": "organization",
423
455
    "TRCK": "tracknumber",
424
456
    "TOLY": "author",
425
 
    "TSO2": "albumartistsort", # iTunes extension
 
457
    "TSO2": "albumartistsort",  # iTunes extension
426
458
    "TSOA": "albumsort",
427
 
    "TSOC": "composersort", # iTunes extension
 
459
    "TSOC": "composersort",  # iTunes extension
428
460
    "TSOP": "artistsort",
429
461
    "TSOT": "titlesort",
430
462
    "TSRC": "isrc",
431
463
    "TSST": "discsubtitle",
432
 
    }.iteritems():
 
464
}.iteritems():
433
465
    EasyID3.RegisterTextKey(key, frameid)
434
466
 
435
467
EasyID3.RegisterKey("genre", genre_get, genre_set, genre_delete)
463
495
    u"ASIN": "asin",
464
496
    u"ALBUMARTISTSORT": "albumartistsort",
465
497
    u"BARCODE": "barcode",
466
 
    }.iteritems():
 
498
}.iteritems():
467
499
    EasyID3.RegisterTXXXKey(key, desc)
468
500
 
 
501
 
469
502
class EasyID3FileType(ID3FileType):
470
503
    """Like ID3FileType, but uses EasyID3 for tags."""
471
504
    ID3 = EasyID3