Search code examples
c++mp3taglibid3v2

Remove all tags except APIC with TagLib in C++


I wrote a function that is supposed to remove all tags from an MPEG file, except the APIC tag(s), but I'm getting mixed and unpredictable results. Sometimes, all tags except the "year" are correctly removed (this happens most of the time), sometimes, one or more other tags stay additionally to the "year" tag.

I'm certainly doing something wrong. Here is my function:

void stripTags(const char* path) {
    MPEG::File m(path);
    m.strip(MPEG::File::ID3v1 | MPEG::File::APE, true); //I added this because otherwise, all tags would stay the first time I executed stripTags(). The second time I would execute it then the tags would be mostly gone (except for "year" as mentioned)
    ByteVector handle = "APIC";
    ID3v2::Tag *t = m.ID3v2Tag();
    if (t) {
        for (ID3v2::FrameList::ConstIterator it = t->frameList().begin(); it != t->frameList().end(); it++) {
            if ((*it)->frameID() != handle) {
                t->removeFrames((*it)->frameID());
                it = t->frameList().begin(); //since the doc says that removeFrames invalidates the pointer returned by frameList, I update this pointer after each removal
            }
        }
        m.save();
    }
    m.strip(MPEG::File::ID3v1 | MPEG::File::APE, true);
}

Thanks for the help


Solution

  • In the loop, when you have removed a tag, you reset the iterator. However then the loop continues and the first thing it does is it++, meaning your loop will skip one entry.

    You could modify your loop like e.g.

    for (ID3v2::FrameList::ConstIterator it = t->frameList().begin(); it != t->frameList().end(); /* nothing here */) {
        if ((*it)->frameID() != handle) {
            t->removeFrames((*it)->frameID());
            it = t->frameList().begin();
        } else {
            ++it;
        }
    }