void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const { if(tag->header()->majorVersion() < 4 && tag->frameList("TDRC").size() == 1 && tag->frameList("TDAT").size() == 1) { TextIdentificationFrame *tdrc = static_cast<TextIdentificationFrame *>(tag->frameList("TDRC").front()); UnknownFrame *tdat = static_cast<UnknownFrame *>(tag->frameList("TDAT").front()); if(tdrc->fieldList().size() == 1 && tdrc->fieldList().front().size() == 4 && tdat->data().size() >= 5) { String date(tdat->data().mid(1), String::Type(tdat->data()[0])); if(date.length() == 4) { tdrc->setText(tdrc->toString() + '-' + date.substr(2, 2) + '-' + date.substr(0, 2)); if(tag->frameList("TIME").size() == 1) { UnknownFrame *timeframe = static_cast<UnknownFrame *>(tag->frameList("TIME").front()); if(timeframe->data().size() >= 5) { String time(timeframe->data().mid(1), String::Type(timeframe->data()[0])); if(time.length() == 4) { tdrc->setText(tdrc->toString() + 'T' + time.substr(0, 2) + ':' + time.substr(2, 2)); } } } } } } }
String ID3v2::Tag::genre() const { // TODO: In the next major version (TagLib 2.0) a list of multiple genres // should be separated by " / " instead of " ". For the moment to keep // the behavior the same as released versions it is being left with " ". if(d->frameListMap["TCON"].isEmpty() || !dynamic_cast<TextIdentificationFrame *>(d->frameListMap["TCON"].front())) { return String::null; } // ID3v2.4 lists genres as the fields in its frames field list. If the field // is simply a number it can be assumed that it is an ID3v1 genre number. // Here was assume that if an ID3v1 string is present that it should be // appended to the genre string. Multiple fields will be appended as the // string is built. TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>( d->frameListMap["TCON"].front()); StringList fields = f->fieldList(); StringList genres; for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) { if((*it).isEmpty()) continue; bool isNumber = true; for(String::ConstIterator charIt = (*it).begin(); isNumber && charIt != (*it).end(); ++charIt) { isNumber = *charIt >= '0' && *charIt <= '9'; } if(isNumber) { int number = (*it).toInt(); if(number >= 0 && number <= 255) *it = ID3v1::genre(number); } if(std::find(genres.begin(), genres.end(), *it) == genres.end()) genres.append(*it); } return genres.toString(); }
String ID3v2::Tag::genre() const { // TODO: In the next major version (TagLib 2.0) a list of multiple genres // should be separated by " / " instead of " ". For the moment to keep // the behavior the same as released versions it is being left with " ". if(!d->frameListMap["TCON"].isEmpty() && dynamic_cast<TextIdentificationFrame *>(d->frameListMap["TCON"].front())) { Frame *frame = d->frameListMap["TCON"].front(); // ID3v2.4 lists genres as the fields in its frames field list. If the field // is simply a number it can be assumed that it is an ID3v1 genre number. // Here was assume that if an ID3v1 string is present that it should be // appended to the genre string. Multiple fields will be appended as the // string is built. if(d->header.majorVersion() == 4) { TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>(frame); StringList fields = f->fieldList(); String genreString; bool hasNumber = false; for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { bool isNumber = true; for(String::ConstIterator charIt = (*it).begin(); isNumber && charIt != (*it).end(); ++charIt) { isNumber = *charIt >= '0' && *charIt <= '9'; } if(!genreString.isEmpty()) genreString.append(' '); if(isNumber) { int number = (*it).toInt(); if(number >= 0 && number <= 255) { hasNumber = true; genreString.append(ID3v1::genre(number)); } } else genreString.append(*it); } if(hasNumber) return genreString; } String s = frame->toString(); // ID3v2.3 "content type" can contain a ID3v1 genre number in parenthesis at // the beginning of the field. If this is all that the field contains, do a // translation from that number to the name and return that. If there is a // string folloing the ID3v1 genre number, that is considered to be // authoritative and we return that instead. Or finally, the field may // simply be free text, in which case we just return the value. int closing = s.find(")"); if(s.substr(0, 1) == "(" && closing > 0) { if(closing == int(s.size() - 1)) return ID3v1::genre(s.substr(1, s.size() - 2).toInt()); else return s.substr(closing + 1); } return s; } return String::null; }