forked from spr/tag_wrapper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mp3.py
159 lines (145 loc) · 5.33 KB
/
mp3.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# Copyright (c) 2008 Scott Paul Robertson ([email protected])
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from tag_wrapper import dictionary_reverse, Tag, TagException
from mutagen.id3 import ID3
from mutagen import id3
encodings = {
'iso-8859-1': 0,
'utf-16': 1,
'utf-16be': 2,
'utf-8': 3,
}
id3_frame_mapping = {
# Art
'APIC:': 'album cover',
# Main information
'TIT2': 'title',
'TPE1': 'artist',
'TPE2': 'album artist',
'TALB': 'album',
'TCOM': 'composer',
'TCON': 'genre',
'TDRC': 'date',
'TRCK': 'tracknumber', # x/total
'TPOS': 'discnumber', # x/total
'TBPM': 'bpm',
# iTunes bonus stuff
'TCMP': 'compilation',
# Gapless support via comments
'TIT1': 'grouping',
# Sorting
'TSOA': 'album sort order',
'TSOT': 'title sort order',
'TSOP': 'artist sort order',
# Miscellaneous
'TCOP': 'copyright',
'TPE3': 'conductor',
'TLEN': 'length',
'TEXT': 'lyricist',
'TENC': 'encoder',
'TSSE': 'encoder settings',
}
norm_frame_mapping = dictionary_reverse(id3_frame_mapping)
class ID3Tag(Tag):
"""The Tag implementation for ID3 tags"""
def __init__(self, tag, lang='eng', encoding=encodings['utf-8']):
super(ID3Tag, self).__init__(tag)
self.lang = lang
if encoding in encodings:
self.encoding = encodings[encoding]
elif encoding <= 3 and encoding >= 0:
self.encoding = encoding
else:
raise TagException('Encoding %s not supported by ID3' % encoding)
def _build_comm_key(self, key, lang='eng'):
"""Builds key for a COMM tag as found in mutagen.id3.ID3"""
return unicode(''.join(('COMM:', key, ":'", lang, "'")))
def _get_real_key(self, key):
"""This returns the key that mutagen.id3.ID3 uses given a "normal"
value.
"""
new_key = ''
if key in norm_frame_mapping:
new_key = norm_frame_mapping[key]
elif key == 'comment':
new_key = self._build_comm_key('', self.lang)
elif key == 'gapless':
new_key = self._build_comm_key('iTunPGAP', self.lang)
else:
new_key = self._build_comm_key(key, self.lang)
return new_key
def __getitem__(self, key):
""" __getitem__: artist = tag['artist']
Returns a list of values
"""
rkey = self._get_real_key(key)
if key == 'album cover':
return [self._tag[rkey].data]
value = self._tag[rkey].text
if type(value) != list:
value = [value]
return map(unicode, value)
def __setitem__(self, key, value):
"""__setitem__: tag['artist'] = "Guster"
If a tag supports multiple values, the user must put vales into
a list themselves. If the tag already exists we overwrite the data.
Mutagen will make a list out of Null separated values.
"""
rkey = self._get_real_key(key)
# Tag is a supported frame
if type(value) != list:
value = [value]
if key in norm_frame_mapping:
if key == 'album cover':
tag_class = getattr(id3, rkey[:-1])
self._tag[rkey] = tag_class(encoding=self.encoding,
desc='', type=3, mime='image/png', data=value[0])
else:
tag_class = getattr(id3, rkey)
self._tag[rkey] = tag_class(encoding=self.encoding, text=value)
# Tag is a comment
else:
desc = key
if key == 'comment':
desc = ''
elif key == 'gapless':
desc = 'iTunPGAP'
self._tag[rkey] = id3.COMM(encoding=self.encoding, lang=self.lang,
desc=desc, text=value)
def __delitem__(self, key):
del(self._tag[self._get_real_key(key)])
def __contains__(self, item):
return (self._get_real_key(item) in self._tag)
def keys(self):
keys = []
for id3_key in self._tag:
if id3_key in id3_frame_mapping:
keys.append(id3_frame_mapping[id3_key])
elif id3_key.startswith('COMM:'):
s = id3_key.split(':')[1]
if s == '':
keys.append('comment')
elif s == 'gapless':
keys.append('gapless')
else:
keys.append(s)
return keys
def save(self):
"""Saves tag (ID3v2.4 and ID3v1.1) to disk."""
try:
self._tag.save(v1=2)
except ValueError:
pass