Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt to new iTunes ID3 mappings for "grouping" and "work" #15

Open
sampsyo opened this issue Jun 13, 2019 · 5 comments
Open

Adapt to new iTunes ID3 mappings for "grouping" and "work" #15

sampsyo opened this issue Jun 13, 2019 · 5 comments

Comments

@sampsyo
Copy link
Member

sampsyo commented Jun 13, 2019

Apparently, some iTunes version around 12.5 changed the "grouping" field to map to the ID3 tag GRP1, while it was previously TIT1. It now uses TIT1 for the work title. Picard apparently has a special config option just to deal with this mapping. There's more info in a post on the mp3tag forum.

@sandreas
Copy link

sandreas commented Jun 13, 2019

Thank you... In case someone needs sample files see beetbox/beets#1515 (comment)

@sandreas
Copy link

I took a closer look at the code:

mediafile/mediafile.py

Lines 1651 to 1656 in deb597f

grouping = MediaField(
MP3StorageStyle('TIT1'),
MP4StorageStyle('\xa9grp'),
StorageStyle('GROUPING'),
ASFStorageStyle('WM/ContentGroupDescription'),
)

In my opinion ALWAYS writing TIT1 and GRP1 is not reasonable... i think a specific setting would be needed, like in Picard (e.g. itunes_compatible_grouping=1), to decide which field should be used - but i did not see a way to pass such a setting to MediaFile.

Since a StorageStyle can have only one single key, its difficult to decide how to fix this. I would have prepared a pull request, but my python is not good enough to touch such a sensitive area without further instructions.

Any Suggestions?

@sampsyo
Copy link
Member Author

sampsyo commented Jun 22, 2019

That’s troubling. Making it a config option would actually be pretty disappointing—a nice thing about MediaFile as it currently stands is that it basically works, most of the time, for most software. It maximizes compatibility without fuss on the part of the user.

Maybe there’s some policy we can devise that would do the right thing in most cases? For example, maybe we could flip the implementation of “work” depending on the presence of GRP1?

@sandreas
Copy link

Did you mean something like this?:

class MP3StorageStyle(StorageStyle):
    """Store data in ID3 frames.
    """
    formats = ['MP3', 'AIFF', 'DSF']

    def __init__(self, key, id3_lang=None, **kwargs):
        """Create a new ID3 storage style. `id3_lang` is the value for
        the language field of newly created frames.
        """
        self.id3_lang = id3_lang
        super(MP3StorageStyle, self).__init__(key, **kwargs)

    def fetch(self, mutagen_file):
        try:
            return mutagen_file[self.key].text[0]
        except (KeyError, IndexError):
            """Switch missing TIT1 key to GRP1 if present for iTunes compatibility"""
            if self.key == 'TIT1' and 'GRP1' in mutagen_file:
                self.key = 'GRP1'
                return mutagen_file[self.key]
            return None

    def store(self, mutagen_file, value):
        frame = mutagen.id3.Frames[self.key](encoding=3, text=[value])
        mutagen_file.tags.setall(self.key, [frame])

Would that work in every case? Event when converting files in beets for example?

Or did you mean, that store should also have such a check and only overwrite the tag if its present and leave self.key?, e.g.:

class MP3StorageStyle(StorageStyle):
    """Store data in ID3 frames.
    """
    formats = ['MP3', 'AIFF', 'DSF']

    def __init__(self, key, id3_lang=None, **kwargs):
        """Create a new ID3 storage style. `id3_lang` is the value for
        the language field of newly created frames.
        """
        self.id3_lang = id3_lang
        super(MP3StorageStyle, self).__init__(key, **kwargs)

    def fetch(self, mutagen_file):
        try:
            return mutagen_file[self.key].text[0]
        except (KeyError, IndexError):
            """Switch missing TIT1 key to GRP1 if present for iTunes compatibility"""
            if self.key == 'TIT1' and 'GRP1' in mutagen_file:
                return mutagen_file['GRP1']
            return None

    def store(self, mutagen_file, value):
        if self.key == 'TIT1' and 'GRP1' in mutagen_file:
            frame = mutagen.id3.Frames['GRP1'](encoding=3, text=[value])
            mutagen_file.tags.setall('GRP1', [frame])
                
        frame = mutagen.id3.Frames[self.key](encoding=3, text=[value])
        mutagen_file.tags.setall(self.key, [frame])

@sampsyo
Copy link
Member Author

sampsyo commented Jun 25, 2019

Something like this! I guess it would be useful to think through the right policy and what each option’s positives and negatives are. We can code up any policy we like, even if it requires some changes to the MediaField interfaces...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants