Using Python to Manage MP3 Tags

0
18182

The author loves to play around and experiment with software and share the results of his work with readers. He has wide and varied tastes and MP3 music is one of them.

It is nice to be able to play the songs you like more often. Amarok was the first player I came across that allowed the creation of dynamic playlists using a rating tag. For example, you could have a playlist with half the songs with a rating of 4 or more and the remaining could be any choice from your library. This was many years ago when it was Amarok version 3. The rating was kept in the database of the music player and I put in the effort to rate at least the songs I loved to hear often.

Somewhere down the line, the database was lost. I can’t remember whether it happened when upgrading the Amarok player to version 4 or when I switched the desktop. Anyway, I never got around to setting the ratings again.

There is now an ID3 tag that stores the rating. However, it is far too tedious to change MP3 tags using a music player, especially if the music library is a mess, with inconsistent file and directory names.

Can you use the ID3 tags to make the library better organised?

You may decide to name each music file using the artist and the song’s title. However, it is possible that not all songs in your library have the proper tags, especially if you have digitised them yourself from ancient Cds.

So, you could decide on the following strategy:

  1. Create a CSV file with the file name and the selected ID3 tags as columns.
  2. Use a spreadsheet to modify the columns.
  3. Update the ID3 tags using the modified CSV file.
  4. Rename all the MP3 files using the ID3 tags.

There are a number of Python modules to modify the tags in MP3 files. Two common packages are Mutagen and eyeD3. Mutagen has the advantage that it works with multiple file types, including MP3, OGG and FLAC, while eyeD3 is meant for MP3 files only.

Getting started

On Fedora, install the following packages:

$sudo dnf install python2-mutagen, python-eyed3

The following is the minimum code for running any of the three options. You pass the name of the option (get_tags, update_tags or rename) and the starting directory.

#!/usr/bin/python

import sys,os

from os.path import join

if __name__ == ‘__main__’:

try:

option = eval(sys.argv[1])

if len(sys.argv) > 2:

path = sys.argv[2]

else:

path = ‘.’

option(path)

except:

print(“Parameters: one of [get_tags,update_tags,rename] path(default .)”)

Creating the CSV file

The basic code for get_tags is as follows. You iterate over the files and select each MP3 file. You will need to call the function get_file_tags to get the tags you need. This function is the one that will depend on the Python module you use. Two other versions are given later.

def get_mp3_file(path):

“”” Walk through all files and select mp3 files.

Common for all options”””

for root,dirnames,filenames in os.walk(path):

for f in filenames:

if len(f) > 4 and f[-4:].lower() == ‘.mp3’:

yield join(root,f)

def get_tags(path):

“”” Create a dictionary with file name as the key

and values are a tuple of the desired tag values

Save the dictionary as csv file suitable for a spreadsheet”””

result = {}

for fn in get_mp3_file(path):

result[fn]=get_file_tags(fn)

out=open(‘mp3.csv’,’w’)

for f in result:

out.write(“%s;%s;%s;%s\n”%((f,) + result[f]))

Shown below is the code for get_file_tags if you’re using the Mutagen module:

from mutagen.mp3 import MP3

# If title is missing set it to the file name without the extension.

def get_file_tags(f):

mp3 = MP3(f)

try:

title=mp3['TIT2'][0]

except:

title=f.split('/')[-1][:-4]

try:

artist=mp3['TPE1'][0]

except:

artist="Unknown"

try:

rating=mp3['POPM:'].rating

except:

rating="0"

return (title, artist, rating)

The Mutagen module gives you the tags similar to the key and value pairs of a dictionary. The key is as per ID3 tag names. If the tag is missing, it raises a key error exception.

The corresponding function when using the eyeD3 module is as follows:

import eyed3

def get_file_tags(f):

mp3 = eyed3.load(f)

try:

title=mp3.tag.title

artist=mp3.tag.artist

except:

print f

title=f.split('/')[-1][:-4]

artist='Unknown'

rating = 0

for popm in mp3.tag.popularities:

if popm.rating:

rating = popm.rating

break

return (title, artist, rating)

This module gives us the values as a tag record with recognisable field names, e.g., tag.title. The popularities tag is a list of three values – email, rating and play-count. Multiple entries can be present, one for each email. This can be useful if many people are using a common music library.

The eyeD3 and the Mutagen modules behave differently if a tag like title or artist is missing. EyeD3 returns a value of None while Mutagen raises an exception.

Since the patents on MP3 have expired, there is no strong motive to avoid MP3 files and use OGG instead. Hence, you may decide to stick to eyeD3 module as that seems to be simpler to use.

Updating the MP3 tags

After correcting the artist and title tags and entering your ratings, you are ready to modify the file tags. The rating is a number between 0 and 255.

The following is the code for the update_tags option, using the eyeD3 module. The modified CSV file is converted into a dictionary with the file name as the key. You assign the revised values to the title and artist tags. The popularities tag is set by providing the email, rating and play-count values.

def set_file_tags(f,tags):

mp3 = eyed3.load(f)

mp3.tag.title=unicode(tags[0])

mp3.tag.artist=unicode(tags[1])

mp3.tag.popularities.set(‘’,int(tags[2]),0)

mp3.tag.save()

def update_tags(path):

“”” Convert the csv file into a dictionary

key is the file name, the 1st column

value is a list of values of the remaining columns”””

dtags={}

for line in open(‘mp3.csv’):

fields=line[:-1].split(‘;’)

dtags[fields[0]]=fields[1:]

for f in get_mp3_file(path):

set_file_tags(f,dtags[f])

Renaming the music files

The final option to rename the files as per your personal preferences using the tag values is as follows:

def rename_file(f):

“”” Standardise the file names as artist-title.mp3”””

mp3 = eyed3.load(f)

root,fold = split(f)

try:

fnew = “%s-%s.mp3”%(mp3.tag.artist, mp3.tag.title)

os.rename(f,join(root,fnew))

except:

print f

def rename(path):

for fn in get_mp3_file(path):

rename_file(fn)

All this can of course be done without coding, but by using a music application and the file manager. The time required will be less, unless your music library is really large. However, automation by coding is definitely more fun and saving time is just an excuse—https://xkcd.com/1205/.

To explore other interesting Apps and tools, click here.

LEAVE A REPLY

Please enter your comment!
Please enter your name here