<p>Is there a maintained package I can use to retrieve and set MP3 ID3 metadata using Python?</p>

[{'answer_id': 8974, 'author': 'PabloG', 'author_id': 394, 'author_profile': 'https://Stackoverflow.com/users/394', 'pm_score': 3, 'selected': False, 'text': '<p>A simple example from the book Dive Into Python works ok for me, <a href="http://www.diveintopython.org/download/diveintopython-examples-5.4.zip" rel="nofollow noreferrer">this</a> is the download link, the example is fileinfo.py. Don\'t know if it\'s the best, but it can do the basic job.</p>\n\n<p>The entire book is available online <a href="http://www.diveintopython.org/" rel="nofollow noreferrer">here</a>.</p>\n'}, {'answer_id': 8976, 'author': 'Philip Reynolds', 'author_id': 1087, 'author_profile': 'https://Stackoverflow.com/users/1087', 'pm_score': 1, 'selected': False, 'text': '<p>It can depend on exactly what you want to do in addition to reading the metadata. If it is just simply the bitrate / name etc. that you need, and nothing else, something lightweight is probably best.</p>\n\n<p>If you\'re manipulating the mp3 past that PyMedia may be suitable.</p>\n\n<p>There are quite a few, whatever you do get, make sure and test it out on plenty of sample media. There are a few different versions of ID3 tags in particular, so make sure it\'s not too out of date. </p>\n\n<p>Personally I\'ve used this small MP3Info class with luck. It is quite old though.</p>\n\n<p><a href="http://www.omniscia.org/~vivake/python/MP3Info.py" rel="nofollow noreferrer">http://www.omniscia.org/~vivake/python/MP3Info.py</a></p>\n'}, {'answer_id': 9358, 'author': 'Harley Holcombe', 'author_id': 1057, 'author_profile': 'https://Stackoverflow.com/users/1057', 'pm_score': 4, 'selected': False, 'text': '<p>What you\'re after is the <a href="http://id3-py.sourceforge.net/" rel="noreferrer">ID3</a> module.  It\'s very simple and will give you exactly what you need.  Just copy the ID3.py file into your site-packages directory and you\'ll be able to do something like the following:</p>\n\n<pre><code>from ID3 import *\ntry:\n  id3info = ID3(\'file.mp3\')\n  print id3info\n  # Change the tags\n  id3info[\'TITLE\'] = "Green Eggs and Ham"\n  id3info[\'ARTIST\'] = "Dr. Seuss"\n  for k, v in id3info.items():\n    print k, ":", v\nexcept InvalidTagError, message:\n  print "Invalid ID3 tag:", message\n</code></pre>\n'}, {'answer_id': 10845, 'author': 'jkp', 'author_id': 912, 'author_profile': 'https://Stackoverflow.com/users/912', 'pm_score': 5, 'selected': False, 'text': '<p>I\'ve used <a href="https://github.com/quodlibet/mutagen" rel="noreferrer">mutagen</a> to edit tags in media files before.  The nice thing about mutagen is that it can handle other formats, such as mp4, FLAC etc.  I\'ve written several scripts with a lot of success using this API.</p>\n'}, {'answer_id': 102285, 'author': 'Owen', 'author_id': 2109, 'author_profile': 'https://Stackoverflow.com/users/2109', 'pm_score': 7, 'selected': False, 'text': '<p>I used <a href="http://eyed3.nicfit.net/" rel="noreferrer">eyeD3</a> the other day with a lot of success.  I found that it could add artwork to the ID3 tag which the other modules I looked at couldn\'t.  You\'ll have to install using pip or download the tar and execute <code>python setup.py install</code> from the source folder.  </p>\n\n<p>Relevant examples from the website are below.</p>\n\n<p>Reading the contents of an mp3 file containing either v1 or v2 tag info:</p>\n\n<pre><code> import eyeD3\n tag = eyeD3.Tag()\n tag.link("/some/file.mp3")\n print tag.getArtist()\n print tag.getAlbum()\n print tag.getTitle()\n</code></pre>\n\n<p>Read an mp3 file (track length, bitrate, etc.) and access it\'s tag:</p>\n\n<pre><code>if eyeD3.isMp3File(f):\n     audioFile = eyeD3.Mp3AudioFile(f)\n     tag = audioFile.getTag()\n</code></pre>\n\n<p>Specific tag versions can be selected:</p>\n\n<pre><code> tag.link("/some/file.mp3", eyeD3.ID3_V2)\n tag.link("/some/file.mp3", eyeD3.ID3_V1)\n tag.link("/some/file.mp3", eyeD3.ID3_ANY_VERSION)  # The default.\n</code></pre>\n\n<p>Or you can iterate over the raw frames:</p>\n\n<pre><code> tag = eyeD3.Tag()\n tag.link("/some/file.mp3")\n for frame in tag.frames:\n    print frame\n</code></pre>\n\n<p>Once a tag is linked to a file it can be modified and saved:</p>\n\n<pre><code> tag.setArtist(u"Cro-Mags")\n tag.setAlbum(u"Age of Quarrel")\n tag.update()\n</code></pre>\n\n<p>If the tag linked in was v2 and you\'d like to save it as v1:</p>\n\n<pre><code> tag.update(eyeD3.ID3_V1_1)\n</code></pre>\n\n<p>Read in a tag and remove it from the file:</p>\n\n<pre><code> tag.link("/some/file.mp3")\n tag.remove()\n tag.update()\n</code></pre>\n\n<p>Add a new tag:</p>\n\n<pre><code> tag = eyeD3.Tag()\n tag.link(\'/some/file.mp3\')    # no tag in this file, link returned False\n tag.header.setVersion(eyeD3.ID3_V2_3)\n tag.setArtist(\'Fugazi\')\n tag.update()\n</code></pre>\n'}, {'answer_id': 1936720, 'author': 'Ciantic', 'author_id': 183544, 'author_profile': 'https://Stackoverflow.com/users/183544', 'pm_score': 3, 'selected': False, 'text': '<p>I looked the above answers and found out that they are not good for my project because of licensing problems with GPL.</p>\n\n<p>And I found out this: <a href="http://pyid3lib.sourceforge.net/" rel="noreferrer">PyID3Lib</a>, while that particular <em>python binding</em> release date is old, it uses the <a href="http://id3lib.sourceforge.net/" rel="noreferrer">ID3Lib</a>, which itself is up to date.</p>\n\n<p>Notable to mention is that both are <strong>LGPL</strong>, and are good to go.</p>\n'}, {'answer_id': 4559380, 'author': 'Corey Goldberg', 'author_id': 16148, 'author_profile': 'https://Stackoverflow.com/users/16148', 'pm_score': 3, 'selected': False, 'text': '<p>check this one out:</p>\n\n<p><a href="https://github.com/Ciantic/songdetails" rel="noreferrer">https://github.com/Ciantic/songdetails</a></p>\n\n<p>Usage example:</p>\n\n<pre><code>&gt;&gt;&gt; import songdetails\n&gt;&gt;&gt; song = songdetails.scan("data/song.mp3")\n&gt;&gt;&gt; print song.duration\n0:03:12\n</code></pre>\n\n<p>Saving changes:</p>\n\n<pre><code>&gt;&gt;&gt; import songdetails\n&gt;&gt;&gt; song = songdetails.scan("data/commit.mp3")\n&gt;&gt;&gt; song.artist = "Great artist"\n&gt;&gt;&gt; song.save()\n</code></pre>\n'}, {'answer_id': 6621839, 'author': 'quabug', 'author_id': 667519, 'author_profile': 'https://Stackoverflow.com/users/667519', 'pm_score': 3, 'selected': False, 'text': '<p>Just additional information to you guys:</p>\n\n<p>take a look at the section "MP3 stuff and Metadata editors" in the page of <a href="http://wiki.python.org/moin/PythonInMusic" rel="noreferrer">PythonInMusic</a>.</p>\n'}, {'answer_id': 31373513, 'author': 'larryy', 'author_id': 3307951, 'author_profile': 'https://Stackoverflow.com/users/3307951', 'pm_score': 1, 'selected': False, 'text': "<p>After some initial research I thought songdetails might fit my use case, but it doesn't handle .m4b files.  Mutagen does.  Note that while some have (reasonably) taken issue with Mutagen's surfacing of format-native keys, that vary from format to format (TIT2 for mp3, title for ogg, \\xa9nam for mp4, Title for WMA etc.), mutagen.File() has a (new?) easy=True parameter that provides EasyMP3/EasyID3 tags, which have a consistent, albeit limited, set of keys.  I've only done limited testing so far, but the common keys, like album, artist, albumartist, genre, tracknumber, discnumber, etc. are all present and identical for .mb4 and .mp3 files when using easy=True, making it very convenient for my purposes.</p>\n"}, {'answer_id': 34970600, 'author': 'Chris Redford', 'author_id': 130427, 'author_profile': 'https://Stackoverflow.com/users/130427', 'pm_score': 5, 'selected': False, 'text': '<p>A problem with <code>eyed3</code> is that it will throw <code>NotImplementedError("Unable to write ID3 v2.2")</code> for common MP3 files.</p>\n\n<p>In my experience, the <code>mutagen</code> class <code>EasyID3</code> works more reliably. Example:</p>\n\n<pre><code>from mutagen.easyid3 import EasyID3\n\naudio = EasyID3("example.mp3")\naudio[\'title\'] = u"Example Title"\naudio[\'artist\'] = u"Me"\naudio[\'album\'] = u"My album"\naudio[\'composer\'] = u"" # clear\naudio.save()\n</code></pre>\n\n<p>All other tags can be accessed this way and saved, which will serve most purposes. More information can be found in the <a href="https://mutagen.readthedocs.io/en/latest/user/id3.html?#easy-id3" rel="noreferrer">Mutagen Tutorial</a>.</p>\n'}, {'answer_id': 38891913, 'author': 'Abhijeet Deshani', 'author_id': 4972892, 'author_profile': 'https://Stackoverflow.com/users/4972892', 'pm_score': 3, 'selected': False, 'text': '<p>easiest method is <a href="https://github.com/Ciantic/songdetails" rel="nofollow noreferrer">songdetails</a>..</p>\n<p>for read data</p>\n<pre><code>import songdetails\nsong = songdetails.scan(&quot;blah.mp3&quot;)\nif song is not None:\n    print song.artist\n</code></pre>\n<p>similarly for edit</p>\n<pre><code>import songdetails\nsong = songdetails.scan(&quot;blah.mp3&quot;)\nif song is not None:\n    song.artist = u&quot;The Great Blah&quot;\n    song.save()\n</code></pre>\n<p>Don\'t forget to add <strong>u</strong> before name until you know chinese language.</p>\n<p>u can read and edit in bulk using python glob module</p>\n<p>ex.</p>\n<pre><code>import glob\nsongs = glob.glob(\'*\')   # script should be in directory of songs.\nfor song in songs:\n    # do the above work.\n</code></pre>\n'}, {'answer_id': 49719777, 'author': 'Elijah', 'author_id': 7732434, 'author_profile': 'https://Stackoverflow.com/users/7732434', 'pm_score': 2, 'selected': False, 'text': '<p>The first answer that uses <a href="http://eyed3.nicfit.net/" rel="nofollow noreferrer">eyed3</a> is outdated so here is an updated version of it.</p>\n\n<p>Reading tags from an mp3 file:</p>\n\n<pre><code> import eyed3\n\n audiofile = eyed3.load("some/file.mp3")\n print(audiofile.tag.artist)\n print(audiofile.tag.album)\n print(audiofile.tag.album_artist)\n print(audiofile.tag.title)\n print(audiofile.tag.track_num)\n</code></pre>\n\n<p>An example from the website to modify tags:</p>\n\n<pre><code> import eyed3\n\n audiofile = eyed3.load("some/file.mp3")\n audiofile.tag.artist = u"Integrity"\n audiofile.tag.album = u"Humanity Is The Devil"\n audiofile.tag.album_artist = u"Integrity"\n audiofile.tag.title = u"Hollow"\n audiofile.tag.track_num = 2\n</code></pre>\n\n<p>An issue I encountered while trying to use eyed3 for the first time had to do with an import error of libmagic even though it was installed. To fix this install the magic-bin whl from <a href="https://pypi.python.org/pypi/python-magic-bin" rel="nofollow noreferrer">here</a></p>\n'}, {'answer_id': 49848525, 'author': 'Marc Maxmeister', 'author_id': 536538, 'author_profile': 'https://Stackoverflow.com/users/536538', 'pm_score': 3, 'selected': False, 'text': '<p>After trying the simple <code>pip install</code> route for eyeD3, pytaglib, and ID3 modules recommended here, I found this fourth option was the only one to work. The rest had import errors with missing dependencies in C++ or something magic or some other library that <code>pip</code> missed. So go with this one for basic reading of ID3 tags (all versions):</p>\n\n<p><a href="https://pypi.python.org/pypi/tinytag/0.18.0" rel="noreferrer">https://pypi.python.org/pypi/tinytag/0.18.0</a></p>\n\n<pre><code>from tinytag import TinyTag\ntag = TinyTag.get(\'/some/music.mp3\')\n</code></pre>\n\n<p>List of possible attributes you can get with TinyTag:</p>\n\n<pre><code>tag.album         # album as string\ntag.albumartist   # album artist as string\ntag.artist        # artist name as string\ntag.audio_offset  # number of bytes before audio data begins\ntag.bitrate       # bitrate in kBits/s\ntag.disc          # disc number\ntag.disc_total    # the total number of discs\ntag.duration      # duration of the song in seconds\ntag.filesize      # file size in bytes\ntag.genre         # genre as string\ntag.samplerate    # samples per second\ntag.title         # title of the song\ntag.track         # track number as string\ntag.track_total   # total number of tracks as string\ntag.year          # year or data as string\n</code></pre>\n\n<p>It was tiny and self-contained, as advertised.</p>\n'}, {'answer_id': 51044551, 'author': 'Ashish Shirodkar', 'author_id': 8920642, 'author_profile': 'https://Stackoverflow.com/users/8920642', 'pm_score': 2, 'selected': False, 'text': '<p>I would suggest <strong><a href="https://pypi.org/project/mp3-tagger/" rel="nofollow noreferrer">mp3-tagger</a></strong>. Best thing about this is it is distributed under <strong>MIT License</strong> and supports all the required attributes.</p>\n\n<pre><code>- artist;\n- album;\n- song;\n- track;\n- comment;\n- year;\n- genre;\n- band;\n- composer;\n- copyright;\n- url;\n- publisher.\n</code></pre>\n\n<p>Example:</p>\n\n<pre><code>from mp3_tagger import MP3File\n\n# Create MP3File instance.\nmp3 = MP3File(\'File_Name.mp3\')\n\n# Get all tags.\ntags = mp3.get_tags()\nprint(tags)\n</code></pre>\n\n<p>It supports set, get, update and delete attributes of mp3 files.</p>\n'}, {'answer_id': 60105280, 'author': 'apokhi', 'author_id': 12743260, 'author_profile': 'https://Stackoverflow.com/users/12743260', 'pm_score': 1, 'selected': False, 'text': '<p>using <a href="https://github.com/nicfit/eyeD3" rel="nofollow noreferrer">https://github.com/nicfit/eyeD3</a></p>\n\n<pre><code>import eyed3\nimport os\n\nfor root,  dirs, files in os.walk(folderp):\n    for file in files:\n        try:\n            if file.find(".mp3") &lt; 0:\n                continue\n            path = os.path.abspath(os.path.join(root , file))\n            t = eyed3.load(path)\n            print(t.tag.title , t.tag.artist)\n            #print(t.getArtist())\n        except Exception as e:\n            print(e)\n            continue\n</code></pre>\n'}, {'answer_id': 60625881, 'author': 'Love and peace - Joe Codeswell', 'author_id': 601770, 'author_profile': 'https://Stackoverflow.com/users/601770', 'pm_score': 3, 'selected': False, 'text': '<p>I used <a href="https://pypi.org/project/tinytag/" rel="noreferrer">tinytag 1.3.1</a> because</p>\n\n<ol>\n<li>It is actively supported:</li>\n</ol>\n\n<pre><code>1.3.0 (2020-03-09):\nadded option to ignore encoding errors ignore_errors #73\nImproved text decoding for many malformed files\n</code></pre>\n\n<ol start="2">\n<li>It supports the major formats:</li>\n</ol>\n\n<pre><code>MP3 (ID3 v1, v1.1, v2.2, v2.3+)\nWave/RIFF\nOGG\nOPUS\nFLAC\nWMA\nMP4/M4A/M4B\n</code></pre>\n\n<ol start="3">\n<li>The code WORKED in just a few minutes of development.</li>\n</ol>\n\n<pre class="lang-py prettyprint-override"><code>from tinytag import TinyTag\n\nfileNameL =\'\'\'0bd1ab5f-e42c-4e48-a9e6-b485664594c1.mp3\n0ea292c0-2c4b-42d4-a059-98192ac8f55c.mp3\n1c49f6b7-6f94-47e1-a0ea-dd0265eb516c.mp3\n5c706f3c-eea4-4882-887a-4ff71326d284.mp3\n\'\'\'.split()\n\nfor fn in fileNameL:\n    fpath = \'./data/\'+fn\n    tag = TinyTag.get(fpath)\n    print()\n    print(\'"artist": "%s",\' % tag.artist)\n    print(\'"album": "%s",\' % tag.album)\n    print(\'"title": "%s",\' % tag.title)\n    print(\'"duration(secs)": "%s",\' % tag.duration)\n\n</code></pre>\n\n<ul>\n<li>RESULT</li>\n</ul>\n\n<pre><code>JoeTagPj&gt;python joeTagTest.py\n\n"artist": "Conan O’Brien Needs A Friend",\n"album": "Conan O’Brien Needs A Friend",\n"title": "17. Thomas Middleditch and Ben Schwartz",\n"duration(secs)": "3565.1829583532785",\n\n"artist": "Conan O’Brien Needs A Friend",\n"album": "Conan O’Brien Needs A Friend",\n"title": "Are you ready to make friends?",\n"duration(secs)": "417.71840447045264",\n\n"artist": "Conan O’Brien Needs A Friend",\n"album": "Conan O’Brien Needs A Friend",\n"title": "Introducing Conan’s new podcast",\n"duration(secs)": "327.22187551899646",\n\n"artist": "Conan O’Brien Needs A Friend",\n"album": "Conan O’Brien Needs A Friend",\n"title": "19. Ray Romano",\n"duration(secs)": "3484.1986772305863",\n\nC:\\1d\\PodcastPjs\\JoeTagPj&gt;\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/8948', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/145/']