quodlibet / mutagen

Python module for handling audio metadata

Home Page:https://mutagen.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Writing new ID3 tags to .aiff files

Daelnz opened this issue · comments

commented

I'm trying to copy ID3 tags from a .mp3 file to a .aiff file but am having issues with the tags for the .aiff file.

Currently I am able to use mutagen.File() to successfully access the .aiff file metadata. It doesn't show the tag attributes explicitly (e.g. 'title', 'artist') but I can access them via their ID3 tag names. A snippet of my code is shown below:

    mp3file = mutagen.File(mp3_file_patheasy=True)
    aifffile = mutagen.File(aiff_file_path)

    aifffile['TIT2'].text[0= mp3file['title'][0]
    aifffile['TPE1'].text[0= mp3file['artist'][0]
    aifffile['TALB'].text[0= mp3file['album'][0]
    aifffile['TPE2'].text[0= mp3file['albumartist'][0]

My issue occurs when I try to write a value to a tag that doesn't already have a value. Unless a tag already has a value, a key doesn't seem to exist in the .aiff mutagen file object and so it throws an error.

Next I've tried using other parts of the mutagen API in order to add this new key to the existing ID3 frame. Looking at the API I can see that the ID3Tags class has an 'add' method would should be able to achieve this. Unfortunately when I try to read the ID3 frame from the .aiff file using ID3(aiff_file_path) it produces an error saying that it it doesn't start with an ID3 tag. This makes sense as the ID3 frame is tucked away near the end of the file.

I've also tried creating a new ID3 frame instead, loading it up with a set of tags and then writing this to the .aiff file. When I open the modified file with mp3tag in shows no values for any of the ID3 tags - I assume this is due to the confusion of the file now having 2 sets of ID3 frames.

I've therefore been looking through the mutagen source code to try and determine why the tags can be retrieved when using File() and not ID3(). As far as I understand it's because ID3() uses the first line/chunk of the file when trying to find the ID3 frame but when using File() it instead establishes the offset that the ID3 frame exists at for .aiff files.

I discovered that in the mutagen ID3 module in the __pre_load_header function of the _file.py there is a comment about needing to adjust this offset for .aiff files

    def _pre_load_header(selffileobj):
        # XXX: for aiff to adjust the offset..
        pass

Is there any planned work to implement this feature? It seems that the library already has the capability to successfully find the ID3 frame when it knows that it's an .aiff file but the ID3 module simply doesn't make use of this.

You shouldn't use ID3 on AIFF files, use File() or the aiff.AIFF class. The ID3 classes have just the code to manipulate the ID3 tags. To do so in an AIFF file one needs to understand and update the AIFF structure, and the is exactly what is implemented in the format specific code.

My issue occurs when I try to write a value to a tag that doesn't already have a value. Unless a tag already has a value, a key doesn't seem to exist in the .aiff mutagen file object and so it throws an error.

Can you share the code and exception?

commented

The code that generates the error is the snippet I posted above. As mentioned, most of the time it works fine but when it tries to write to an ID3 tag that doesn't already have a value, the program throws a key access error.

Exception has occurred: KeyError X
'TALB'

You can easily replicate this by taking a .aiff file, removing a tag value and then attempting to access it - see below

.aiff with album tag value
tags_with_album
keys_with_album

.aiff without album tag value
tags_without_album
keys_without_album

That's because you try to read the value from aifffile['TALB'] but it does not exist. Simplest way way would be not to use easyid3 for the first file:

mp3file = mutagen.File(mp3_file_path)
aifffile = mutagen.File(aiff_file_path)

if 'TALB' in mp3file:
    aifffile['TALB'] = mp3file['TALB']

If you really want to use easyid3 then you would need to set proper frame classes, e.g.:

mp3file = mutagen.File(mp3_file_path, easy=True)
aifffile = mutagen.File(aiff_file_path)

f2['TALB'] = mutagen.id3.TALB(text=f1['album'])
commented

Ah, I see what I've been doing wrong. I've been trying to write a value to an existing key when I was supposed to be writing a new key & value pair. I have no explicit need for easyID3 so your first solution works for me.

Thank you very much helping me solve this issue.

Great it works for you now.

Just for completeness: adding EasyID3 support also for AIFF is tracked in #284