3 # mutagen aims to be an all purpose media tagging library
4 # Copyright (C) 2005 Michael Urman
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of version 2 of the GNU General Public License as
8 # published by the Free Software Foundation.
10 # $Id: __init__.py 4348 2008-12-02 02:41:15Z piman $
13 """Mutagen aims to be an all purpose tagging library.
15 import mutagen.[format]
16 metadata = mutagen.[format].Open(filename)
18 metadata acts like a dictionary of tags in the file. Tags are generally a
19 list of string-like values, but may have additional methods available
20 depending on tag or format. They may also be entirely different objects
21 for certain keys, again depending on format.
25 version_string
= ".".join(map(str, version
))
31 class Metadata(object):
32 """An abstract dict-like object.
34 Metadata is the base class for many of the tag objects in Mutagen.
37 def __init__(self
, *args
, **kwargs
):
39 self
.load(*args
, **kwargs
)
41 def load(self
, *args
, **kwargs
):
42 raise NotImplementedError
44 def save(self
, filename
=None):
45 raise NotImplementedError
47 def delete(self
, filename
=None):
48 raise NotImplementedError
50 class FileType(mutagen
._util
.DictMixin
):
51 """An abstract object wrapping tags and audio stream information.
54 info -- stream information (length, bitrate, sample rate)
55 tags -- metadata tags, if any
57 Each file format has different potential tags and stream
60 FileTypes implement an interface very similar to Metadata; the
61 dict interface, save, load, and delete calls on a FileType call
62 the appropriate methods on its tag data.
68 _mimes
= ["application/octet-stream"]
70 def __init__(self
, filename
=None, *args
, **kwargs
):
72 warnings
.warn("FileType constructor requires a filename",
75 self
.load(filename
, *args
, **kwargs
)
77 def load(self
, filename
, *args
, **kwargs
):
78 raise NotImplementedError
80 def __getitem__(self
, key
):
81 """Look up a metadata tag key.
83 If the file has no tags at all, a KeyError is raised.
85 if self
.tags
is None: raise KeyError, key
86 else: return self
.tags
[key
]
88 def __setitem__(self
, key
, value
):
89 """Set a metadata tag.
91 If the file has no tags, an appropriate format is added (but
92 not written until save is called).
96 self
.tags
[key
] = value
98 def __delitem__(self
, key
):
99 """Delete a metadata tag key.
101 If the file has no tags at all, a KeyError is raised.
103 if self
.tags
is None: raise KeyError, key
104 else: del(self
.tags
[key
])
107 """Return a list of keys in the metadata tag.
109 If the file has no tags at all, an empty list is returned.
111 if self
.tags
is None: return []
112 else: return self
.tags
.keys()
114 def delete(self
, filename
=None):
115 """Remove tags from a file."""
116 if self
.tags
is not None:
118 filename
= self
.filename
121 "delete(filename=...) is deprecated, reload the file",
123 return self
.tags
.delete(filename
)
125 def save(self
, filename
=None, **kwargs
):
126 """Save metadata tags."""
128 filename
= self
.filename
131 "save(filename=...) is deprecated, reload the file",
133 if self
.tags
is not None:
134 return self
.tags
.save(filename
, **kwargs
)
135 else: raise ValueError("no tags in file")
138 """Print stream information and comment key=value pairs."""
139 stream
= "%s (%s)" % (self
.info
.pprint(), self
.mime
[0])
140 try: tags
= self
.tags
.pprint()
141 except AttributeError:
143 else: return stream
+ ((tags
and "\n" + tags
) or "")
146 raise NotImplementedError
148 def __get_mime(self
):
150 for Kind
in type(self
).__mro
__:
151 for mime
in getattr(Kind
, '_mimes', []):
152 if mime
not in mimes
:
156 mime
= property(__get_mime
)
158 def File(filename
, options
=None, easy
=False):
159 """Guess the type of the file and try to open it.
161 The file type is decided by several things, such as the first 128
162 bytes (which usually contains a file type identifier), the
163 filename extension, and the presence of existing tags.
165 If no appropriate type could be found, None is returned.
169 from mutagen
.asf
import ASF
170 from mutagen
.apev2
import APEv2File
171 from mutagen
.flac
import FLAC
173 from mutagen
.easyid3
import EasyID3FileType
as ID3FileType
175 from mutagen
.id3
import ID3FileType
177 from mutagen
.mp3
import EasyMP3
as MP3
179 from mutagen
.mp3
import MP3
180 from mutagen
.oggflac
import OggFLAC
181 from mutagen
.oggspeex
import OggSpeex
182 from mutagen
.oggtheora
import OggTheora
183 from mutagen
.oggvorbis
import OggVorbis
185 from mutagen
.trueaudio
import EasyTrueAudio
as TrueAudio
187 from mutagen
.trueaudio
import TrueAudio
188 from mutagen
.wavpack
import WavPack
190 from mutagen
.easymp4
import EasyMP4
as MP4
192 from mutagen
.mp4
import MP4
193 from mutagen
.musepack
import Musepack
194 from mutagen
.monkeysaudio
import MonkeysAudio
195 from mutagen
.optimfrog
import OptimFROG
196 options
= [MP3
, TrueAudio
, OggTheora
, OggSpeex
, OggVorbis
, OggFLAC
,
197 FLAC
, APEv2File
, MP4
, ID3FileType
, WavPack
, Musepack
,
198 MonkeysAudio
, OptimFROG
, ASF
]
203 fileobj
= open(filename
, "rb")
205 header
= fileobj
.read(128)
206 # Sort by name after score. Otherwise import order affects
207 # Kind sort order, which affects treatment of things with
209 results
= [(Kind
.score(filename
, fileobj
, header
), Kind
.__name
__)
213 results
= zip(results
, options
)
215 (score
, name
), Kind
= results
[-1]
216 if score
> 0: return Kind(filename
)