My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
Mutagen  
Mutagen tagging library
Updated Nov 30, 2009 by joe.wreschnig@gmail.com

Mutagen

Mutagen has moved!

Mutagen is now a separate project on Google Code. This page will remain intact until the new project has moved up in the search results, but updates and issues against Mutagen itself should be part of that project.

What is Mutagen?

Mutagen is a Python module to handle audio metadata. It supports ASF, FLAC, M4A, Monkey's Audio, MP3, Musepack, Ogg FLAC, Ogg Speex, Ogg Theora, Ogg Vorbis, True Audio, WavPack and OptimFROG audio files. All versions of ID3v2 are supported, and all standard ID3v2.4 frames are parsed. It can read Xing headers to accurately calculate the bitrate and length of MP3s. ID3 and APEv2 tags can be edited regardless of audio format. It can also manipulate Ogg streams on an individual packet/page level.

There is a brief tutorial with several API examples.

Where do I get it?

The download page will have the latest version.

Why Mutagen?

Quod Libet has more strenuous requirements in an ID3 library than most programs that deal with tags. Furthermore, most tagging libraries suck. Therefore we felt it was necessary to write our own.

  • Mutagen has a simple API, that is roughly the same across all tag formats and versions, and that integrates into Python's builtin types and interfaces.
  • New frame types and file formats are easily added, and the behavior of the current formats can be changed by extending them.
  • Freeform keys, multiple values, Unicode, and other advanced features were considered from the start and are fully supported.
  • All ID3v2 versions and all ID3v2.4 frames are covered, including rare ones like POPM or RVA2.
  • We take automated testing very seriously. All bug fixes are commited with a test that prevents them from recurring, and new features are committed with a full test suite.

Real World Use

Mutagen can load every MP3 we have thrown at it (when it hasn't, we make it do so). Scripts are included so you can run the same tests on your collection.

The following software projects are using Mutagen for tagging:

  • Ex Falso and Quod Libet, a flexible tagger and player
  • Listen, a music player for GNOME
  • Exaile, a media player aiming to be similar to KDE's AmaroK, but for GTK+
  • ZOMG, a command-line player for ZSH
  • Debian's version of JACK, an audio CD ripper, uses Mutagen to tag FLACs
  • Amarok's replaygain script
  • csikk, web-based music sharing on LAN
  • Advanced Audio Architecture, management framework for digital music
  • Picard, cross-platform MusicBrainz tagger
  • pytagsfs, virtual file system for organizing media files by metadata
Comment by znup...@gmail.com, Oct 9, 2008

Where can we find examples on how to use the Mutagen library?

Comment by lclamo...@gmail.com, Nov 29, 2008

Any plans for python 3.0 compatibility?

Comment by kelvin.b...@gmail.com, Dec 11, 2008

a small example querying a flac file

#!/usr/bin/env python
from mutagen.flac import FLAC
from pprint import pprint
import sys

DEBUG=False

if len(sys.argv) > 1:
    fname = sys.argv[1]
else:
    fname = "/Users/philou/Music/Lhasa/La Llorona/01 De Cara A La Pared.flac"

audio = FLAC(fname)
if DEBUG:
    print "DD: instancied a mutagen object of type %s for file %s" % (type(audio), fname)
    print "DD: pprint(instance):"
    pprint(audio)
    print "/DD"
    print

if audio.has_key('artist'):      print "Artist:              ", audio['artist'][0]
if audio.has_key('album'):       print "Album:               ", audio['album'][0]
if audio.has_key('tracktotal'):
    tracktot = int(audio['tracktotal'][0])
else:
    tracktot = None
if audio.has_key('tracknumber'):
    trackn = int(audio['tracknumber'][0])
    if tracktot != None:
        track_str = "%s / %s" % (trackn, tracktot)
    else:
        track_str = str(trackn)
    print "Track:                %s" % track_str
if audio.has_key('title'):       print "Title:               ", audio['title'][0]
if audio.has_key('mcn'):         print "MCN:                 ", audio['mcn'][0]
if audio.has_key('isrc'):        print "ISRC:                ", audio['isrc'][0]

print "Sample rate:         ", audio.info.sample_rate
print "Nr. of channels:     ", audio.info.channels
print "Bits per sample:     ", audio.info.bits_per_sample
print "Total nr. of samples:", audio.info.total_samples
print "Length in secs:      ", audio.info.length
print "MD5:                 ", audio.info.md5_signature
Comment by steven.strobe.cc@gmail.com, Dec 21, 2008

An apparent source of confusion is the relationship between mutagen.mp3, id3, and easyid3. mp3.MP3 should be used to open an MP3 file; in addition to reading ID3v2 tags using either of the two ID3 parsers in Mutagen, it also reads additional information from the actual MPEG stream which may not be in the ID3 tags (like bitrate and duration).

An mp3.MP3 object behaves like a dict, like ID3 and EasyID3; in fact, the methods for getting and setting keys and values on an MP3 appear to simply map to the underlying ID3 parser's. If the ID3 tags you're working are on MP3 files, stick to using mp3.MP3 instead of using ID3 objects directly.

An mp3.MP3 object also has the method add_tags(), which allows you to add ID3 tags to a file that doesn't have any. This is the only way to add ID3 tags within Mutagen, AFAIK.

Comment by steven.strobe.cc@gmail.com, Dec 29, 2008

Also: mp3.add_tags has an optional argument 'ID3', which works just like the same arg on the constructor of an mp3 object, viz:

from mutagen.mp3 import MP3
from mutagen.easyid3 import EasyID3
import mutagen.id3

def test(filename):
   """Example which shows how to automatically add tags to an MP3 using EasyID3."""

   m = MP3(filename, ID3=EasyID3)

   try:
       m.add_tags(ID3=EasyID3)
       print("Added tags to %s" % filename)
   except mutagen.id3.error:
       print("%s already had tags" % filename)

   m['title'] = 'Test!'
   m.save()
   print(m.pprint())
   print('\n')

test('has-tags.mp3')
test('no-tags.mp3')
Comment by Lucian.B...@gmail.com, Jan 17, 2009

Any chance this library could ever be licensed as LGPL?

Comment by dhorn2...@gmail.com, Jan 29, 2009

An example of writing tags to an ASF/WMA file in a format that ffmpeg knows how to decode:

from mutagen.asf import ASF 
audio = ASF("myfilename.wma")
audio["Title"] = "MyTitle"
audio["Author"] = "MyArtist"
audio["WM/AlbumTitle"] = "MyAlbum"
audio["WM/TrackNumber"] = "12"
#print ASF.pprint(audio)
#print ASF.keys(audio)
ASF.save(audio)

I use the "Author" tag for "Artist", as that happens to be the mapping used by musicpd (mpd) when it uses ffmepg AVFormatContext() to get the tags from the wma file.

Comment by hlangos...@gmail.com, Feb 23, 2009

How about a new page for MutagenExamples? ? I'd contribute a simple image extractor:

#!/usr/bin/python
import os
import sys
import locale
from optparse import OptionParser

def main(argv):
    from mutagen.id3 import ID3

    parser = OptionParser()
    (options, args) = parser.parse_args(argv[1:])
    if not args:
        raise SystemExit(parser.print_help() or 1)

    enc = locale.getpreferredencoding()
    for filename in args:
        print "--", filename
        try:
            f = ID3(filename);
            for frame in f.getall("APIC"):
                print frame.pprint().encode(enc, 'replace')
                ext = ".img"
                if (frame.mime == "image/jpeg") or (frame.mime == "image/jpg"): ext = ".jpg"
                if frame.mime == "image/png": ext = ".png"
                if frame.mime == "image/gif": ext = ".gif"
                (proot,pext) = os.path.splitext(filename)
                imgfilename = proot + ext
                if os.path.exists(imgfilename) : print "File " + imgfilename + " exists. Skipping!"
                else:
                    print "Writing image to " + imgfilename + " !"
                    myfile = file(imgfilename, 'wb')
                    myfile.write(frame.data)
                    myfile.close()
        except AttributeError: print "- Unknown file type"
        except KeyboardInterrupt: raise
        except Exception, err: print str(err)
        print

main(sys.argv)
Comment by beatmi...@gmail.com, Mar 26, 2009

I'd like a way to determine if there is an id3v1 tag, even when an id3v2 tag is also present. For example, mutagen.id3.ID3.version will return (2,3,0) when both v1 and v2 tags are present. Any suggestions on how to check if an id3v1 tag is also there? Thanks.

Comment by caslav.i...@gmx.net, Mar 27, 2009

What about COMM tags? As it is now, it converts only tags starting with T, but COMM too can contain text. I personally did something like this to make it work on my MP3s, but have no idea if it makes sense:

Index: mid3iconv
===================================================================
--- mid3iconv   (revision 4351)
+++ mid3iconv   (working copy)
@@ -62,9 +62,9 @@
                 print str(err)
             continue

-        for tag in filter(lambda t: t.startswith("T"), id3):
+        for tag in id3:
             frame = id3[tag]
-            if isinstance(frame, mutagen.id3.TimeStampTextFrame): # non-unicode fields
+            if isinstance(frame, mutagen.id3.TimeStampTextFrame) or not hasattr(frame, "text"): # non-unicode fields
                 continue

             try:
Comment by hybrid.basis, May 6, 2009

Is there any way to read data from an MP3 file that is already in memory, stored in a file-like object? I've managed to pass the object to MPEGInfo just fine, but have been unable to do so for MP3 - which has made retrieving the ID3 information kind of difficult.

Comment by r3info...@gmail.com, Jul 24, 2009

Hi, here a quick hint how to add iTunes compatible lyrics to an MP3:

lyrics = u"""
Some text
here
does not really
mattah
"""

tagg = id3.ID3("some.mp3")
tagg[u"USLT::'eng'"] = id3.USLT()     # add a new unsynchronized lyrics element
tagg[u"USLT::'eng'"].text = lyrics
tagg[u"USLT::'eng'"].encoding=1       # i guess it means utf8
tagg[u"USLT::'eng'"].lang='eng'       # seems to be used for everything
tagg[u"USLT::'eng'"].desc=u''         # dont know what the description is good for
tagg.save()

Works for me, didnt took the time to read the specs.

Comment by gbrab...@gmail.com, Oct 16, 2009

Hey r3inforce... adding lyrics that way to an mp3 does not work if the lenght of the lyrics is bigger than (somewhat) characters...at least iTunes shows blank lyrics. Do u know another way?

Comment by robert.m...@gmail.com, Feb 24, 2010

Hey grabelo, I think mutagen compress all tags greater than 2K. So iTunes can't work with this tags. I found this out as I can't see the album art in some players. As I comment out the rows in id3.py, which do the "zipping", it works :-)

Comment by vr3...@gmail.com, May 12, 2011

Is there a way to check the lang of an existing USLT frame?

I have a collection of mp3 files that have XXX,eng and nld as the lang. It might be possible that if my program I have is used in another locale or something, it will not be able to read the USLT frame and this won't get any lyrics.


Sign in to add a comment
Powered by Google Project Hosting