Search code examples
pythonpython-3.xmutagen

Problem using mutagen to set custom tags for MP4 file


I am attempting to set custom ID3 tags on MP4 files using Python and Mutagen. So far I have been able to create custom tags for MP3 files without any issues, but MP4 seems to be another issue altogether.

The initial error message I received was a TypeError stating that "can't concat str to bytes". So instead of feeding the program a string I encoded it as a UTF-8 bytearray but it gave this error message:

TypeError: object of type 'int' has no len()

This error actually occurs within Mutagen itself.

Here is the code:

from mutagen.id3 import ID3
from mutagen.mp4 import MP4

def set_isbn(filename, isbn):
    if(filename.lower().endswith(".mp3")):
        tags = ID3(filename)
        tags.add(TXXX(encoding=3, desc=u'ISBN', text=str(isbn)))
        tags.save(filename)
    else:
        tags = MP4(filename)
        tags["----:TXXX:ISBN"] = bytearray(isbn, 'UTF-8')
        tags.save(filename)

The Mutagen docs are mostly very good but when it comes to custom MP4 tags all it states is the general setup of the mean:name:key. Has anyone else ever been able to successfully implement custom tags for MP4 files?


Solution

  • Important things first: the only problem in your code is the conversion from string to bytearray. Taking a look at the source code of mutagen, in the part concerning specifically the mp4 file type, there is a line that looks like this:

        ...
        if isinstance(x, bytes):
            x = [x]
            ...
    

    where x is the value you supply. When the above condition is met, the value you gave is inserted inside a list, which has a "dunder len" method, hence can be the argument of the len function, that in turn will not raise TypeError when used as argument.

    You should only edit your code by replacing the conversion to bytearray with the one to bytes as follows:

    from mutagen.id3 import ID3
    from mutagen.mp4 import MP4
    
    def set_isbn(filename, isbn):
        if(filename.lower().endswith(".mp3")):
            tags = ID3(filename)
            tags.add(TXXX(encoding=3, desc=u'ISBN', text=str(isbn)))
            tags.save(filename)
        else:
            tags = MP4(filename)
            tags["----:TXXX:ISBN"] = bytes(isbn, 'UTF-8')
            tags.save(filename)
    

    You will then avoid the above TypeError exception.