This file is indexed.

/usr/lib/python2.7/dist-packages/mutagen/easymp4.py is in python-mutagen 1.31-1ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# -*- coding: utf-8 -*-

# Copyright (C) 2009  Joe Wreschnig
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.

from mutagen import Metadata
from mutagen._util import DictMixin, dict_match
from mutagen.mp4 import MP4, MP4Tags, error, delete
from ._compat import PY2, text_type, PY3


__all__ = ["EasyMP4Tags", "EasyMP4", "delete", "error"]


class EasyMP4KeyError(error, KeyError, ValueError):
    pass


class EasyMP4Tags(DictMixin, Metadata):
    """A file with MPEG-4 iTunes metadata.

    Like Vorbis comments, EasyMP4Tags keys are case-insensitive ASCII
    strings, and values are a list of Unicode strings (and these lists
    are always of length 0 or 1).

    If you need access to the full MP4 metadata feature set, you should use
    MP4, not EasyMP4.
    """

    Set = {}
    Get = {}
    Delete = {}
    List = {}

    def __init__(self, *args, **kwargs):
        self.__mp4 = MP4Tags(*args, **kwargs)
        self.load = self.__mp4.load
        self.save = self.__mp4.save
        self.delete = self.__mp4.delete
        self._padding = self.__mp4._padding

    filename = property(lambda s: s.__mp4.filename,
                        lambda s, fn: setattr(s.__mp4, 'filename', fn))

    @classmethod
    def RegisterKey(cls, key,
                    getter=None, setter=None, deleter=None, lister=None):
        """Register a new key mapping.

        A key mapping is four functions, a getter, setter, deleter,
        and lister. The key may be either a string or a glob pattern.

        The getter, deleted, and lister receive an MP4Tags instance
        and the requested key name. The setter also receives the
        desired value, which will be a list of strings.

        The getter, setter, and deleter are used to implement __getitem__,
        __setitem__, and __delitem__.

        The lister is used to implement keys(). It should return a
        list of keys that are actually in the MP4 instance, provided
        by its associated getter.
        """
        key = key.lower()
        if getter is not None:
            cls.Get[key] = getter
        if setter is not None:
            cls.Set[key] = setter
        if deleter is not None:
            cls.Delete[key] = deleter
        if lister is not None:
            cls.List[key] = lister

    @classmethod
    def RegisterTextKey(cls, key, atomid):
        """Register a text key.

        If the key you need to register is a simple one-to-one mapping
        of MP4 atom name to EasyMP4Tags key, then you can use this
        function::

            EasyMP4Tags.RegisterTextKey("artist", "\xa9ART")
        """
        def getter(tags, key):
            return tags[atomid]

        def setter(tags, key, value):
            tags[atomid] = value

        def deleter(tags, key):
            del(tags[atomid])

        cls.RegisterKey(key, getter, setter, deleter)

    @classmethod
    def RegisterIntKey(cls, key, atomid, min_value=0, max_value=(2 ** 16) - 1):
        """Register a scalar integer key.
        """

        def getter(tags, key):
            return list(map(text_type, tags[atomid]))

        def setter(tags, key, value):
            clamp = lambda x: int(min(max(min_value, x), max_value))
            tags[atomid] = [clamp(v) for v in map(int, value)]

        def deleter(tags, key):
            del(tags[atomid])

        cls.RegisterKey(key, getter, setter, deleter)

    @classmethod
    def RegisterIntPairKey(cls, key, atomid, min_value=0,
                           max_value=(2 ** 16) - 1):
        def getter(tags, key):
            ret = []
            for (track, total) in tags[atomid]:
                if total:
                    ret.append(u"%d/%d" % (track, total))
                else:
                    ret.append(text_type(track))
            return ret

        def setter(tags, key, value):
            clamp = lambda x: int(min(max(min_value, x), max_value))
            data = []
            for v in value:
                try:
                    tracks, total = v.split("/")
                    tracks = clamp(int(tracks))
                    total = clamp(int(total))
                except (ValueError, TypeError):
                    tracks = clamp(int(v))
                    total = min_value
                data.append((tracks, total))
            tags[atomid] = data

        def deleter(tags, key):
            del(tags[atomid])

        cls.RegisterKey(key, getter, setter, deleter)

    @classmethod
    def RegisterFreeformKey(cls, key, name, mean="com.apple.iTunes"):
        """Register a text key.

        If the key you need to register is a simple one-to-one mapping
        of MP4 freeform atom (----) and name to EasyMP4Tags key, then
        you can use this function::

            EasyMP4Tags.RegisterFreeformKey(
                "musicbrainz_artistid", "MusicBrainz Artist Id")
        """
        atomid = "----:" + mean + ":" + name

        def getter(tags, key):
            return [s.decode("utf-8", "replace") for s in tags[atomid]]

        def setter(tags, key, value):
            encoded = []
            for v in value:
                if not isinstance(v, text_type):
                    if PY3:
                        raise TypeError("%r not str" % v)
                    v = v.decode("utf-8")
                encoded.append(v.encode("utf-8"))
            tags[atomid] = encoded

        def deleter(tags, key):
            del(tags[atomid])

        cls.RegisterKey(key, getter, setter, deleter)

    def __getitem__(self, key):
        key = key.lower()
        func = dict_match(self.Get, key)
        if func is not None:
            return func(self.__mp4, key)
        else:
            raise EasyMP4KeyError("%r is not a valid key" % key)

    def __setitem__(self, key, value):
        key = key.lower()

        if PY2:
            if isinstance(value, basestring):
                value = [value]
        else:
            if isinstance(value, text_type):
                value = [value]

        func = dict_match(self.Set, key)
        if func is not None:
            return func(self.__mp4, key, value)
        else:
            raise EasyMP4KeyError("%r is not a valid key" % key)

    def __delitem__(self, key):
        key = key.lower()
        func = dict_match(self.Delete, key)
        if func is not None:
            return func(self.__mp4, key)
        else:
            raise EasyMP4KeyError("%r is not a valid key" % key)

    def keys(self):
        keys = []
        for key in self.Get.keys():
            if key in self.List:
                keys.extend(self.List[key](self.__mp4, key))
            elif key in self:
                keys.append(key)
        return keys

    def pprint(self):
        """Print tag key=value pairs."""
        strings = []
        for key in sorted(self.keys()):
            values = self[key]
            for value in values:
                strings.append("%s=%s" % (key, value))
        return "\n".join(strings)

for atomid, key in {
    '\xa9nam': 'title',
    '\xa9alb': 'album',
    '\xa9ART': 'artist',
    'aART': 'albumartist',
    '\xa9day': 'date',
    '\xa9cmt': 'comment',
    'desc': 'description',
    '\xa9grp': 'grouping',
    '\xa9gen': 'genre',
    'cprt': 'copyright',
    'soal': 'albumsort',
    'soaa': 'albumartistsort',
    'soar': 'artistsort',
    'sonm': 'titlesort',
    'soco': 'composersort',
}.items():
    EasyMP4Tags.RegisterTextKey(key, atomid)

for name, key in {
    'MusicBrainz Artist Id': 'musicbrainz_artistid',
    'MusicBrainz Track Id': 'musicbrainz_trackid',
    'MusicBrainz Album Id': 'musicbrainz_albumid',
    'MusicBrainz Album Artist Id': 'musicbrainz_albumartistid',
    'MusicIP PUID': 'musicip_puid',
    'MusicBrainz Album Status': 'musicbrainz_albumstatus',
    'MusicBrainz Album Type': 'musicbrainz_albumtype',
    'MusicBrainz Release Country': 'releasecountry',
}.items():
    EasyMP4Tags.RegisterFreeformKey(key, name)

for name, key in {
    "tmpo": "bpm",
}.items():
    EasyMP4Tags.RegisterIntKey(key, name)

for name, key in {
    "trkn": "tracknumber",
    "disk": "discnumber",
}.items():
    EasyMP4Tags.RegisterIntPairKey(key, name)


class EasyMP4(MP4):
    """Like :class:`MP4 <mutagen.mp4.MP4>`,
    but uses :class:`EasyMP4Tags` for tags.

    :ivar info: :class:`MP4Info <mutagen.mp4.MP4Info>`
    :ivar tags: :class:`EasyMP4Tags`
    """

    MP4Tags = EasyMP4Tags

    Get = EasyMP4Tags.Get
    Set = EasyMP4Tags.Set
    Delete = EasyMP4Tags.Delete
    List = EasyMP4Tags.List
    RegisterTextKey = EasyMP4Tags.RegisterTextKey
    RegisterKey = EasyMP4Tags.RegisterKey