JeevanJames / Id3

Library to read, modify and write ID3 & Lyrics3 tags in MP3 files. Provides an extensible framework for retrieving ID3 information from online services.
Apache License 2.0
41 stars 17 forks source link

Adding Tags To a File with No Tags #19

Open wleader opened 5 years ago

wleader commented 5 years ago

Not sure if this is an issue or not, or just me not being able to figure out how to do it.

If I read in a file with no tags in it at all, and then attempt to add some 2x tags to it I get exceptions.

        using (var mp3 = new Mp3(mp3File, Mp3Permissions.ReadWrite))
        {
            Id3Tag tag = mp3.GetTag(Id3TagFamily.Version2X);
            if (tag == null)
            {
                tag = new Id3Tag();
            }

            tag.Artists.Value.Clear();
            tag.Artists.Value.Add(artistName);

            tag.Title.Value = trackTitle;

            mp3.WriteTag(tag, WriteConflictAction.Replace);
        }

System.InvalidOperationException: 'Sequence contains no matching element'

at System.Linq.Enumerable.First[TSource](IEnumerable1 source, Func2 predicate) at Id3.Id3Handler.GetHandler(Id3Version version) at Id3.Mp3.WriteTag(Id3Tag tag, WriteConflictAction conflictAction)

It looks to be that when I new an Id3Tag, its version property is not initialized, and since that property setter is internal, I can't just set it myself. However if I cheat and use reflection, as below to initialize the version, the file is saved out correctly with my tags in place:

        using (var mp3 = new Mp3(mp3File, Mp3Permissions.ReadWrite))
        {
            Id3Tag tag = mp3.GetTag(Id3TagFamily.Version2X);
            if (tag == null)
            {
                tag = new Id3Tag();
                //tag.Version = Id3Version.V23;
                // version is internal set, but if we use reflection to set it, the mp3.WriteTag below works.
                var propinfo = typeof(Id3Tag).GetProperty("Version", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
                propinfo.SetValue(tag, Id3Version.V23);
            }

            tag.Artists.Value.Clear();
            tag.Artists.Value.Add(artistName);

            tag.Title.Value = trackTitle;

            mp3.WriteTag(tag, WriteConflictAction.Replace);
        }
rodrigoce commented 4 years ago

@wleader , I used your tip

eFail commented 1 year ago

@wleader, I was hitting this same issue. Based on the information you provided above, I did a little searching through the code and I have a theory on what the issue is. I'm not 100% sure this is right, but it's what I've been able to deduce so far and it got me unblocked without having to use reflection.

It looks like the Version property never gets set to anything when a new Id3Tag instance is created. Instead, it's initialized to the first entry of the Id3Version enum, which is V1X. On top of that, it looks like the Id3Tag class represents all possible information that can be stored in an ID3 Tag. It isn't until you try writing an Id3Tag instance out that the data stored in the tag gets processed, according to the version number. So what I think is happening is this. We're creating a new tag, which sets itself to version 1. And then we're modifying something in the tag that ID3v1 doesn't support. So the call to WriteTag() ends up failing with error message "Sequence contains no matching element".

I ended up getting it to work by using the overloaded version of WriteTag() which takes in a version number:

string path = ""; // Set to actual path
using (Mp3 mp3 = new Mp3(path, Mp3Permissions.ReadWrite))
{
    Id3Tag tag = new Id3Tag();
    mp3.WriteTag(tag, Id3Version.V23, WriteConflictAction.Replace);
}

Hope this helps others like it did me.