/* GET ALBUM COVER */ const char * tag_data_get_cover (TagDatac * data, uint * len) { TagLib::ID3v2::AttachedPictureFrame * pic = NULL; if (!(reinterpret_cast<TagData *>(data))->id3v2 || (reinterpret_cast<TagData *>(data))->id3v2->frameListMap()["APIC"].isEmpty()) { *len = 0; return NULL; } TagLib::ID3v2::FrameList::ConstIterator it; TagLib::ID3v2::FrameList l = (reinterpret_cast<TagData *>(data))->id3v2->frameListMap()["APIC"]; for(it=l.begin(); it!=l.end(); ++it) { TagLib::ID3v2::AttachedPictureFrame * t = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it); if (pic == NULL) pic = t; if (t->type () == TagLib::ID3v2::AttachedPictureFrame::FrontCover) { pic = t; break; } } if (pic == NULL) { *len = 0; return NULL; } *len = pic->picture ().size (); const char * out = (const char *) malloc (*len); memcpy ((void *) out, pic->picture ().data(), *len); return out; }
ID3v2Tag::ID3v2Tag( TagLib::Tag *tag, TagLib::ID3v2::Tag *id3v2Tag ) : Tag( tag ) , m_id3v2Tag( id3v2Tag ) { TagLib::ID3v2::FrameList fList = m_id3v2Tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = fList.begin(); it != fList.end(); ++it ) { TagLib::String frameId = TagLib::String( (*it)->frameID() ); TagLib::ID3v2::TextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( *it ); if( frame ) { QString val = TStringToQString( frame->fieldList().toString( '\n' ) ); if( frameId == TagLib::String( "TPE2" ) ) //album artist { m_albumArtist = val; } else if( frameId == TagLib::String( "TCOM" ) ) //composer { m_composer = val; } else if( frameId == TagLib::String( "TPOS" ) ) //disc number { m_discNumber = processDiscNumber( val ); } } } }
/* GET REPLAY GAIN */ float tag_data_get_gain (TagDatac * data) { if ((reinterpret_cast<TagData *>(data))->xiph && !(reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].isEmpty()) return atof((reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["REPLAYGAIN_ALBUM_GAIN"].front().toCString(1)); if ((reinterpret_cast<TagData *>(data))->xiph && !(reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].isEmpty()) return atof((reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["REPLAYGAIN_TRACK_GAIN"].front().toCString(1)); if ((reinterpret_cast<TagData *>(data))->xiph && !(reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["RG_AUDIOPHILE"].isEmpty()) return atof((reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["RG_AUDIOPHILE"].front().toCString(1)); if ((reinterpret_cast<TagData *>(data))->xiph && !(reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["RG_RADIO"].isEmpty()) return atof((reinterpret_cast<TagData *>(data))->xiph->fieldListMap()["RG_RADIO"].front().toCString(1)); if ((reinterpret_cast<TagData *>(data))->id3v2 && !(reinterpret_cast<TagData *>(data))->id3v2->frameListMap()["RVA2"].isEmpty()) { TagLib::ID3v2::FrameList::ConstIterator it; TagLib::ID3v2::FrameList l = (reinterpret_cast<TagData *>(data))->id3v2->frameListMap()["RVA2"]; for(it=l.begin(); it!=l.end(); ++it) { TagLib::ID3v2::RelativeVolumeFrame * rva = dynamic_cast<TagLib::ID3v2::RelativeVolumeFrame*>(*it); if (rva->channelType () == TagLib::ID3v2::RelativeVolumeFrame::MasterVolume) return rva->volumeAdjustment (); } } return 0.0; }
Tag::Tag(const QString &filename) : m_filename(filename) { TagLib::MPEG::File mpegfile(filename.toLocal8Bit().constData()); TagLib::ID3v2::Tag* id3v2 = mpegfile.ID3v2Tag(); if (id3v2 && !id3v2->isEmpty()) { readRegularTag(id3v2, m_data); int picnum = 0; TagLib::ID3v2::FrameList frames = id3v2->frameListMap()["APIC"]; // attached picture TagLib::ID3v2::FrameList::ConstIterator it = frames.begin(); while (it != frames.end()) { TagLib::ID3v2::AttachedPictureFrame* apic = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it); TagLib::ByteVector bytes = apic->picture(); QImage img = QImage::fromData(reinterpret_cast<const uchar*>(bytes.data()), bytes.size()); if (!img.isNull()) { m_data[QLatin1String("picture") + QString::number(picnum++)] = QVariant(img); } ++it; } } else { TagLib::FileRef fileref(filename.toLocal8Bit().constData()); if (fileref.isNull()) return; TagLib::Tag* tag = fileref.tag(); if (!tag || tag->isEmpty()) return; readRegularTag(tag, m_data); } }
bool is_framelist_empty(const TagLib::ID3v2::FrameList &list) { for (auto it = list.begin(); it != list.end(); ++it) if ((*it)->toString() != TagLib::String::null) return false; return true; }
/*! * \brief Read the albumart image from the file * * \param filename The filename for which we want to find the length. * \param type The type of image we want - front/back etc * \returns A pointer to a QImage owned by the caller or NULL if not found. */ QImage* MetaIOID3::getAlbumArt(QString filename, ImageType type) { QImage *picture = new QImage(); AttachedPictureFrame::Type apicType = AttachedPictureFrame::FrontCover; switch (type) { case IT_UNKNOWN : apicType = AttachedPictureFrame::Other; break; case IT_FRONTCOVER : apicType = AttachedPictureFrame::FrontCover; break; case IT_BACKCOVER : apicType = AttachedPictureFrame::BackCover; break; case IT_CD : apicType = AttachedPictureFrame::Media; break; case IT_INLAY : apicType = AttachedPictureFrame::LeafletPage; break; default: return picture; } QByteArray fname = filename.toLocal8Bit(); TagLib::MPEG::File *mpegfile = new TagLib::MPEG::File(fname.constData()); if (mpegfile) { if (mpegfile->isOpen() && !mpegfile->ID3v2Tag()->frameListMap()["APIC"].isEmpty()) { TagLib::ID3v2::FrameList apicframes = mpegfile->ID3v2Tag()->frameListMap()["APIC"]; for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); it != apicframes.end(); ++it) { AttachedPictureFrame *frame = static_cast<AttachedPictureFrame *>(*it); if (frame && frame->type() == apicType) { picture->loadFromData((const uchar *)frame->picture().data(), frame->picture().size()); return picture; } } } delete mpegfile; } delete picture; return NULL; }
QImage ID3v2TagHelper::embeddedCover() const { TagLib::ID3v2::FrameList apicList = m_tag->frameListMap()[fieldName( Meta::valHasCover ).toCString()]; TagLib::ID3v2::AttachedPictureFrame *cover = NULL; TagLib::ID3v2::AttachedPictureFrame *otherCover = NULL; for( TagLib::ID3v2::FrameList::ConstIterator it = apicList.begin(); it != apicList.end(); ++it ) { TagLib::ID3v2::AttachedPictureFrame *currFrame = dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it ); if( currFrame->picture().size() < MIN_COVER_SIZE ) continue; if( currFrame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover ) { cover = currFrame; } else if( currFrame->type() == TagLib::ID3v2::AttachedPictureFrame::Other ) { otherCover = currFrame; } } if( !cover && otherCover ) cover = otherCover; if( !cover ) return QImage(); return QImage::fromData( ( uchar * )( cover->picture().data() ), cover->picture().size() ); }
bool MetaDSF::exportPictures(const char *prefix) const { std::map<std::string, unsigned int> counter; TagLib::ID3v2::FrameList l = _i->_file.ID3v2Tag()->frameList("APIC"); TagLib::ID3v2::FrameList::ConstIterator it; for (it = l.begin(); it != l.end(); ++it) { TagLib::ID3v2::AttachedPictureFrame *f = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(*it); std::string fname = prefix; std::string tname = picTypeDesc[f->type()].toCString(); std::string ext = MIMETypeToExtMap[f->mimeType()].toCString(); if (counter.find(tname) == counter.end()) counter[tname] = 1; else counter[tname] += 1; fname += "_"; fname += tname; fname += "_"; fname += std::to_string(counter[tname]); fname += "."; fname += ext; //std::cout << "fname = " << fname << std::endl; writeFileFromVector(fname.c_str(), f->picture()); } return true; }
//// Private //// void MetaDSF::MetaDSFImpl::deleteFrames(const TagLib::ID3v2::FrameList &l) { TagLib::ID3v2::FrameList::ConstIterator it; for (it = l.begin(); it != l.end(); it++) { _file.ID3v2Tag()->removeFrame(*it); } }
// Too bad can't use STL copy alogirthm.... // copy(src.begin(), src.end(), back_inserter(dest)); void MetaDSF::MetaDSFImpl::dupFrameList(const TagLib::ID3v2::FrameList &src, TagLib::ID3v2::FrameList &dest) { TagLib::ID3v2::FrameList::ConstIterator it; for (it = src.begin(); it != src.end(); it++) { dest.append(*it); } }
/*! * \brief Read the albumart image from the file * * \param filename The filename for which we want to find the albumart. * \param type The type of image we want - front/back etc * \returns A pointer to a QImage owned by the caller or nullptr if not found. */ QImage* MetaIOID3::getAlbumArt(const QString &filename, ImageType type) { QImage *picture = new QImage(); AttachedPictureFrame::Type apicType = AttachedPictureFrame::FrontCover; switch (type) { case IT_UNKNOWN : apicType = AttachedPictureFrame::Other; break; case IT_FRONTCOVER : apicType = AttachedPictureFrame::FrontCover; break; case IT_BACKCOVER : apicType = AttachedPictureFrame::BackCover; break; case IT_CD : apicType = AttachedPictureFrame::Media; break; case IT_INLAY : apicType = AttachedPictureFrame::LeafletPage; break; case IT_ARTIST : apicType = AttachedPictureFrame::Artist; break; default: return picture; } if (OpenFile(filename)) { TagLib::ID3v2::Tag *tag = GetID3v2Tag(); if (tag && !tag->frameListMap()["APIC"].isEmpty()) { TagLib::ID3v2::FrameList apicframes = tag->frameListMap()["APIC"]; for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); it != apicframes.end(); ++it) { AttachedPictureFrame *frame = static_cast<AttachedPictureFrame *>(*it); if (frame && frame->type() == apicType) { picture->loadFromData((const uchar *)frame->picture().data(), frame->picture().size()); return picture; } } } } delete picture; return nullptr; }
/*! * \brief Find the POPM tag associated with MythTV * * \param tag Pointer to TagLib::ID3v2::Tag object * \param email Email address associated with this POPM frame * \returns Pointer to frame */ PopularimeterFrame* MetaIOID3::findPOPM(TagLib::ID3v2::Tag *tag, const String &_email) { TagLib::ID3v2::FrameList l = tag->frameList("POPM"); for(TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it) { PopularimeterFrame *f = static_cast<PopularimeterFrame *>(*it); if (f && f->email() == _email) return f; } return nullptr; }
/*! * \brief Find the a custom comment tag by description. * This is a copy of the same function in the * TagLib::ID3v2::UserTextIdentificationFrame Class with a static * instead of dynamic cast. * * \param tag Pointer to TagLib::ID3v2::Tag object * \param description Description of tag to search for * \returns Pointer to frame */ UserTextIdentificationFrame* MetaIOID3::find(TagLib::ID3v2::Tag *tag, const String &description) { TagLib::ID3v2::FrameList l = tag->frameList("TXXX"); for(TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it) { UserTextIdentificationFrame *f = static_cast<UserTextIdentificationFrame *>(*it); if (f && f->description() == description) return f; } return nullptr; }
/*! * \brief Find an APIC tag by type and optionally description * * \param tag Pointer to TagLib::ID3v2::Tag object * \param type Type of picture to search for * \param description Description of picture to search for (optional) * \returns Pointer to frame */ AttachedPictureFrame* MetaIOID3::findAPIC(TagLib::ID3v2::Tag *tag, const AttachedPictureFrame::Type &type, const String &description) { TagLib::ID3v2::FrameList l = tag->frameList("APIC"); for(TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it) { AttachedPictureFrame *f = static_cast<AttachedPictureFrame *>(*it); if (f && f->type() == type && (description.isNull() || f->description() == description)) return f; } return nullptr; }
void MetaDSF::printTags(const char *prefix) const { if (_i->_file.ID3v2Tag()->isEmpty()) { return; } TagLib::ID3v2::FrameList l = _i->_file.ID3v2Tag()->frameList(); TagLib::ID3v2::FrameList::ConstIterator it; for (it = l.begin(); it != l.end(); it++) { std::cout << prefix; std::cout << (*it)->frameID() << "=" << (*it)->toString() << std::endl; } }
bool SoundSource::processID3v2Tag(TagLib::ID3v2::Tag* id3v2) { // Print every frame in the file. if (s_bDebugMetadata) { TagLib::ID3v2::FrameList::ConstIterator it = id3v2->frameList().begin(); for(; it != id3v2->frameList().end(); it++) { qDebug() << "ID3V2" << (*it)->frameID().data() << "-" << TStringToQString((*it)->toString()); } } TagLib::ID3v2::FrameList bpmFrame = id3v2->frameListMap()["TBPM"]; if (!bpmFrame.isEmpty()) { QString sBpm = TStringToQString(bpmFrame.front()->toString()); processBpmString("ID3v2", sBpm); } TagLib::ID3v2::FrameList keyFrame = id3v2->frameListMap()["TKEY"]; if (!keyFrame.isEmpty()) { QString sKey = TStringToQString(keyFrame.front()->toString()); setKey(sKey); } // Foobar2000-style ID3v2.3.0 tags // TODO: Check if everything is ok. TagLib::ID3v2::FrameList frames = id3v2->frameListMap()["TXXX"]; for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) { TagLib::ID3v2::UserTextIdentificationFrame* ReplayGainframe = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it ); if ( ReplayGainframe && ReplayGainframe->fieldList().size() >= 2 ) { QString desc = TStringToQString( ReplayGainframe->description() ).toLower(); if ( desc == "replaygain_album_gain" ){ QString sReplayGain = TStringToQString( ReplayGainframe->fieldList()[1]); parseReplayGainString(sReplayGain); } if ( desc == "replaygain_track_gain" ){ QString sReplayGain = TStringToQString( ReplayGainframe->fieldList()[1]); parseReplayGainString(sReplayGain); } } } TagLib::ID3v2::FrameList composerFrame = id3v2->frameListMap()["TCOM"]; if (!composerFrame.isEmpty()) { QString sComposer = TStringToQString(composerFrame.front()->toString()); setComposer(sComposer); } return true; }
QString extractMBIDFromFile(TagLib::MPEG::File *file) { TagLib::ID3v2::Tag *tag = file->ID3v2Tag(); TagLib::ID3v2::FrameList ufid = tag->frameListMap()["UFID"]; if (!ufid.isEmpty()) { for (TagLib::ID3v2::FrameList::Iterator i = ufid.begin(); i != ufid.end(); i++) { TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast<TagLib::ID3v2::UniqueFileIdentifierFrame *>(*i); if (frame && frame->owner() == "http://musicbrainz.org") { TagLib::ByteVector id = frame->identifier(); return QString::fromAscii(id.data(), id.size()); } } } return QString(); }
bool ID3v2TagHelper::hasEmbeddedCover() const { TagLib::ID3v2::FrameList apicList = m_tag->frameListMap()[fieldName( Meta::valHasCover ).toCString()]; for( TagLib::ID3v2::FrameList::ConstIterator it = apicList.begin(); it != apicList.end(); ++it ) { TagLib::ID3v2::AttachedPictureFrame *currFrame = dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it ); if( currFrame->picture().size() < MIN_COVER_SIZE ) continue; if( currFrame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover || currFrame->type() == TagLib::ID3v2::AttachedPictureFrame::Other ) return true; } return false; }
void ReplayGainReader::readID3v2(TagLib::ID3v2::Tag *tag) { TagLib::ID3v2::UserTextIdentificationFrame* frame = 0; TagLib::ID3v2::FrameList frames = tag->frameList("TXXX"); for(TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it) { frame = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>(*it); if(frame && frame->fieldList().size() >= 2) { TagLib::String desc = frame->description().upper(); if (desc == "REPLAYGAIN_TRACK_GAIN") setValue(Qmmp::REPLAYGAIN_TRACK_GAIN, TStringToQString(frame->fieldList()[1])); else if (desc == "REPLAYGAIN_TRACK_PEAK") setValue(Qmmp::REPLAYGAIN_TRACK_PEAK, TStringToQString(frame->fieldList()[1])); else if (desc == "REPLAYGAIN_ALBUM_GAIN") setValue(Qmmp::REPLAYGAIN_ALBUM_GAIN, TStringToQString(frame->fieldList()[1])); else if (desc == "REPLAYGAIN_ALBUM_PEAK") setValue(Qmmp::REPLAYGAIN_ALBUM_PEAK, TStringToQString(frame->fieldList()[1])); } } }
bool ID3v2TagHelper::setEmbeddedCover( const QImage &cover ) { QByteArray bytes; QBuffer buffer( &bytes ); buffer.open( QIODevice::WriteOnly ); if( !cover.save( &buffer, "JPEG" ) ) { buffer.close(); return false; } buffer.close(); TagLib::ByteVector field = fieldName( Meta::valHasCover ).toCString(); TagLib::ID3v2::FrameList apicList = m_tag->frameListMap()[field]; TagLib::ID3v2::AttachedPictureFrame *frontCover = NULL; // remove covers TagLib::List<TagLib::ID3v2::AttachedPictureFrame*> backedUpPictures; for( TagLib::ID3v2::FrameList::ConstIterator it = apicList.begin(); it != apicList.end(); ++it ) { TagLib::ID3v2::AttachedPictureFrame *currFrame = dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it ); m_tag->removeFrame( currFrame, false ); } // add new cover frontCover = new TagLib::ID3v2::AttachedPictureFrame( field ); frontCover->setMimeType( "image/jpeg" ); frontCover->setPicture( TagLib::ByteVector( bytes.data(), bytes.count() ) ); frontCover->setType( TagLib::ID3v2::AttachedPictureFrame::FrontCover ); m_tag->addFrame( frontCover ); return true; }
int MetaDSF::deletePictures(const TagLib::String &ptype) { TagLib::ID3v2::FrameList l = _i->_file.ID3v2Tag()->frameList("APIC"); TagLib::ID3v2::FrameList dl; // a list of frames to be deleted TagLib::ID3v2::FrameList::ConstIterator it; std::string pt = ptype.toCString(); // retrieve a list of frames that matches the given type for (it = l.begin(); it != l.end(); it++) { TagLib::ID3v2::AttachedPictureFrame *f = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(*it); TagLib::ID3v2::AttachedPictureFrame::Type t = static_cast<TagLib::ID3v2::AttachedPictureFrame::Type>(std::stoi(pt, 0, 16)); if (f->type() == t) { dl.append(f); } } _i->deleteFrames(dl); _i->_changed = true; return dl.size(); }
bool ID3v2TagHelper::setTags( const Meta::FieldHash &changes ) { bool modified = TagHelper::setTags( changes ); foreach( const qint64 key, changes.keys() ) { QVariant value = changes.value( key ); TagLib::ByteVector field( fieldName( key ).toCString() ); if( !field.isNull() && !field.isEmpty() ) { if( key == Meta::valHasCover ) continue; else if( key == Meta::valUniqueId ) { QPair< UIDType, QString > uidPair = splitUID( value.toString() ); if( uidPair.first == UIDInvalid ) continue; TagLib::String owner = uidFieldName( uidPair.first ); TagLib::ByteVector uid( uidPair.second.toAscii().data() ); TagLib::ID3v2::FrameList list = m_tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if( ( *it )->frameID() == field ) { TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it ); if( !frame ) continue; if( frame->owner() == owner ) { m_tag->removeFrame( frame ); modified = true; break; } } } if ( !uid.isEmpty() ) { m_tag->addFrame( new TagLib::ID3v2::UniqueFileIdentifierFrame( owner, uid ) ); modified = true; } continue; } TagLib::String tValue = Qt4QStringToTString( ( key == Meta::valCompilation ) ? QString::number( value.toInt() ) : value.toString() ); if( tValue.isEmpty() ) m_tag->removeFrames( field ); else { TagLib::ID3v2::TextIdentificationFrame *frame = NULL; if( !m_tag->frameListMap()[field].isEmpty() ) frame = dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( m_tag->frameListMap()[field].front() ); if( !frame ) { frame = new TagLib::ID3v2::TextIdentificationFrame( field ); m_tag->addFrame( frame ); } // note: TagLib is smart enough to automatically set UTF8 encoding if needed. frame->setText( tValue ); } modified = true; } else if( key == Meta::valScore || key == Meta::valRating || key == Meta::valPlaycount ) { TagLib::String description; TagLib::String tValue; if( key == Meta::valRating ) { description = fmpsFieldName( FMPSRating ); tValue = Qt4QStringToTString( QString::number( value.toFloat() / 10.0 ) ); } else if( key == Meta::valScore ) { description = fmpsFieldName( FMPSScore ); tValue = Qt4QStringToTString( QString::number( value.toFloat() / 100.0 ) ); } else if( key == Meta::valPlaycount ) { description = fmpsFieldName( FMPSPlayCount ); tValue = Qt4QStringToTString( QString::number( value.toInt() ) ); } if( key == Meta::valRating || key == Meta::valPlaycount ) { TagLib::ID3v2::PopularimeterFrame *popFrame = NULL; if( !m_tag->frameListMap()[POPM_Frame].isEmpty() ) popFrame = dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( m_tag->frameListMap()[POPM_Frame].front() ); if( !popFrame ) { popFrame = new TagLib::ID3v2::PopularimeterFrame( POPM_Frame ); m_tag->addFrame( popFrame ); } if( key == Meta::valRating ) popFrame->setRating( qBound(0, int(qRound(value.toDouble() / 10.0 * 256)), 255) ); else popFrame->setCounter( value.toInt() ); modified = true; } TagLib::ID3v2::FrameList list = m_tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it ) { if( ( *it )->frameID() == TXXX_Frame ) { TagLib::ID3v2::UserTextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it ); if( !frame ) continue; if( frame->description() == description ) { m_tag->removeFrame( frame ); modified = true; break; } } } if( value.toBool() ) { TagLib::ID3v2::UserTextIdentificationFrame *frame = new TagLib::ID3v2::UserTextIdentificationFrame( TXXX_Frame ); frame->setDescription( description ); frame->setText( tValue ); m_tag->addFrame( frame ); modified = true; } } } return modified; }
/*! * \brief Read the albumart images from the file * * \param tag The ID3v2 tag object in which to look for Album Art * \returns A QList containing a list of AlbumArtImage's * with the type and description of the APIC tag. */ AlbumArtList MetaIOID3::readAlbumArt(TagLib::ID3v2::Tag *tag) { AlbumArtList artlist; if (!tag->frameListMap()["APIC"].isEmpty()) { TagLib::ID3v2::FrameList apicframes = tag->frameListMap()["APIC"]; for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin(); it != apicframes.end(); ++it) { AttachedPictureFrame *frame = static_cast<AttachedPictureFrame *>(*it); // Assume a valid image would have at least // 100 bytes of data (1x1 indexed gif is 35 bytes) if (frame->picture().size() < 100) { LOG(VB_GENERAL, LOG_NOTICE, "Music Scanner - Discarding APIC frame " "with size less than 100 bytes"); continue; } AlbumArtImage *art = new AlbumArtImage(); if (frame->description().isEmpty()) art->m_description.clear(); else art->m_description = TStringToQString(frame->description()); art->m_embedded = true; art->m_hostname = gCoreContext->GetHostName(); QString ext = getExtFromMimeType( TStringToQString(frame->mimeType()).toLower()); switch (frame->type()) { case AttachedPictureFrame::FrontCover : art->m_imageType = IT_FRONTCOVER; art->m_filename = QString("front") + ext; break; case AttachedPictureFrame::BackCover : art->m_imageType = IT_BACKCOVER; art->m_filename = QString("back") + ext; break; case AttachedPictureFrame::Media : art->m_imageType = IT_CD; art->m_filename = QString("cd") + ext; break; case AttachedPictureFrame::LeafletPage : art->m_imageType = IT_INLAY; art->m_filename = QString("inlay") + ext; break; case AttachedPictureFrame::Artist : art->m_imageType = IT_ARTIST; art->m_filename = QString("artist") + ext; break; case AttachedPictureFrame::Other : art->m_imageType = IT_UNKNOWN; art->m_filename = QString("unknown") + ext; break; default: LOG(VB_GENERAL, LOG_ERR, "Music Scanner - APIC tag found " "with unsupported type"); delete art; continue; } artlist.append(art); } } return artlist; }
Meta::FieldHash ID3v2TagHelper::tags() const { Meta::FieldHash data = TagHelper::tags(); TagLib::ID3v2::FrameList list = m_tag->frameList(); for( TagLib::ID3v2::FrameList::ConstIterator it = list.begin(); it != list.end(); ++it ) { qint64 field; TagLib::String frameName = TagLib::String( ( *it )->frameID() ); if( ( field = fieldName( frameName ) ) ) { if( field == Meta::valUniqueId ) { TagLib::ID3v2::UniqueFileIdentifierFrame *frame = dynamic_cast< TagLib::ID3v2::UniqueFileIdentifierFrame * >( *it ); if( !frame ) continue; QString identifier = TStringToQString( TagLib::String( frame->identifier() ) ); if( identifier.isEmpty() ) continue; if( frame->owner() == uidFieldName( UIDAFT ) && isValidUID( identifier, UIDAFT ) ) data.insert( Meta::valUniqueId, identifier ); continue; } else if( field == Meta::valHasCover ) { TagLib::ID3v2::AttachedPictureFrame *frame = dynamic_cast< TagLib::ID3v2::AttachedPictureFrame * >( *it ); if( !frame ) continue; if( ( frame->type() == TagLib::ID3v2::AttachedPictureFrame::FrontCover || frame->type() == TagLib::ID3v2::AttachedPictureFrame::Other ) && frame->picture().size() > MIN_COVER_SIZE ) // must be at least 1kb { data.insert( Meta::valHasCover, true ); } continue; } TagLib::ID3v2::TextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::TextIdentificationFrame * >( *it ); if( !frame ) continue; QString value = TStringToQString( frame->fieldList().toString( '\n' ) ); if( field == Meta::valDiscNr ) { int disc; if( ( disc = splitDiscNr( value ).first ) ) data.insert( field, disc ); } else if( field == Meta::valBpm ) data.insert( field, value.toFloat() ); else data.insert( field, value ); } else if( frameName == POPM_Frame ) { TagLib::ID3v2::PopularimeterFrame *frame = dynamic_cast< TagLib::ID3v2::PopularimeterFrame * >( *it ); if( !frame ) continue; if( TStringToQString( frame->email() ).isEmpty() ) // only read anonymous ratings { // FMPS tags have precedence if( !data.contains( Meta::valRating ) && frame->rating() != 0 ) data.insert( Meta::valRating, qRound( frame->rating() / 256.0 * 10.0 ) ); if( !data.contains( Meta::valPlaycount ) && frame->counter() < 10000 ) data.insert( Meta::valPlaycount, frame->counter() ); } } else if( frameName == TXXX_Frame ) { TagLib::ID3v2::UserTextIdentificationFrame *frame = dynamic_cast< TagLib::ID3v2::UserTextIdentificationFrame * >( *it ); if( !frame ) continue; // the value of the user text frame is stored in the // second and following fields. TagLib::StringList fields = frame->fieldList(); if( fields.size() >= 2 ) { QString value = TStringToQString( fields[1] ); if( fields[0] == fmpsFieldName( FMPSRating ) ) data.insert( Meta::valRating, qRound( value.toFloat() * 10.0 ) ); else if( fields[0] == fmpsFieldName( FMPSScore ) ) data.insert( Meta::valScore, value.toFloat() * 100.0 ); else if( fields[0] == fmpsFieldName( FMPSPlayCount ) ) data.insert( Meta::valPlaycount, value.toFloat() ); } } } return data; }
void MediaScannerThread::run() { if (multiPass) { qDebug() << "MediaScannerThread: multi non-single pass selected"; multiPass = false; for (int i=0;i<multiPassFileNames.count();i++) { QString fullPath = multiPassFileNames.at(i); TagLib::FileRef testfile(fullPath.toStdString().c_str()); if (!testfile.isNull()) { ID3Tag *tmpTag = 0; if (!tmpTag) { tmpTag = new ID3Tag(); tmpTag->valid = false; } if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( testfile.file())) { if (file->ID3v2Tag(false)) { //Check to see if there are images in the tag #ifdef Q_OS_WIN32 //Currently this only works in the windows version of taglib?? if (!file->ID3v2Tag()->frameListMap()["APIC"].isEmpty()) { TagLib::ID3v2::FrameList frameList = file->ID3v2Tag()->frameListMap()["APIC"]; TagLib::ID3v2::FrameList::Iterator iter; for( iter = frameList.begin(); iter != frameList.end(); ++iter ) { TagLib::ID3v2::AttachedPictureFrame::Type t = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->type(); if (t == TagLib::ID3v2::AttachedPictureFrame::Type::FrontCover) { TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture(); QImage tmpPicture; tmpPicture.loadFromData((uchar*)pic.data(),pic.size()); tmpTag->frontcover = tmpPicture; } else if (t == TagLib::ID3v2::AttachedPictureFrame::Type::BackCover) { TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture(); QImage tmpPicture; tmpPicture.loadFromData((uchar*)pic.data(),pic.size()); tmpTag->backcover = tmpPicture; } } } #endif //Q_OS_WIN32 TagLib::Tag *tag = testfile.tag(); if (!tmpTag->valid) { tmpTag->artist = tag->artist().toCString(); tmpTag->title = tag->title().toCString(); tmpTag->filename = fullPath; emit tagReceived("",0,tmpTag); } } } else { TagLib::Tag *tag = testfile.tag(); if (!tmpTag->valid) { tmpTag->artist = tag->artist().toCString(); tmpTag->title = tag->title().toCString(); tmpTag->filename = fullPath; emit tagReceived("",0,tmpTag); } } } else { qDebug() << "MediaScannerThread: Invalid File in multipass" << fullPath; int stop = 1; } QThread::msleep(50); } multiPassFileNames.clear(); } else if (singlePass) { qDebug() << "MediaScannerThread: Non-multi single pass selected"; singlePass = false; QString fullPath = singlePassFileName; TagLib::FileRef testfile(fullPath.toStdString().c_str()); if (!testfile.isNull()) { TagLib::Tag *tag = testfile.tag(); //if (tag) //{ ID3Tag *tmpTag = 0; if (!tmpTag) { tmpTag = new ID3Tag(); tmpTag->valid = false; } if (!tmpTag->valid) { tmpTag->artist = tag->artist().toCString(); tmpTag->title = tag->title().toCString(); tmpTag->filename = fullPath; emit tagReceived("",0,tmpTag); } //ID3Tag *tmpTag = new ID3Tag(); } else { qDebug() << "MediaScannerThread: Invalid File in singlepass" << fullPath; } } else { qDebug() << "MediaScannerThread: Non-multi non-single pass selected"; bool firstScan = true; int delay=0; bool anyValid = true; while (anyValid) { anyValid = false; if (firstScan) { delay=0; //firstScan = false; } else { delay=20; } for (int i=0;i<m_playLists->count();i++) { for (int j=0;j<m_playLists->at(i)->size();j++) { QString fullPath = m_playLists->at(i)->getFileNum(j)->fullPath(); // qDebug() << fullPath; TagLib::FileRef testfile(fullPath.toStdString().c_str()); if (!testfile.isNull()) { ID3Tag *tmpTag = m_playLists->at(i)->getFileNum(j)->getId3Tag(); if (!tmpTag) { tmpTag = new ID3Tag(); tmpTag->valid = false; anyValid = true; } if (TagLib::MPEG::File *file = dynamic_cast<TagLib::MPEG::File *>( testfile.file())) { if (file->ID3v2Tag(false)) { //Check to see if there are images in the tag #ifdef Q_OS_WIN32 //Currently this only works in the windows version of taglib?? if (!file->ID3v2Tag()->frameListMap()["APIC"].isEmpty()) { TagLib::ID3v2::FrameList frameList = file->ID3v2Tag()->frameListMap()["APIC"]; TagLib::ID3v2::FrameList::Iterator iter; for( iter = frameList.begin(); iter != frameList.end(); ++iter ) { TagLib::ID3v2::AttachedPictureFrame::Type t = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->type(); if (t == TagLib::ID3v2::AttachedPictureFrame::Type::FrontCover) { TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture(); QImage tmpPicture; tmpPicture.loadFromData((uchar*)pic.data(),pic.size()); tmpTag->frontcover = tmpPicture; } else if (t == TagLib::ID3v2::AttachedPictureFrame::Type::BackCover) { TagLib::ByteVector pic = (((TagLib::ID3v2::AttachedPictureFrame*)*iter))->picture(); QImage tmpPicture; tmpPicture.loadFromData((uchar*)pic.data(),pic.size()); tmpTag->backcover = tmpPicture; } } } #endif TagLib::Tag *tag = testfile.tag(); if (!tmpTag->valid) { tmpTag->artist = tag->artist().toCString(); tmpTag->title = tag->title().toCString(); tmpTag->filename = fullPath; emit tagReceived(m_playLists->at(i)->title(),j,tmpTag); } } } else { TagLib::Tag *tag = testfile.tag(); if (!tmpTag->valid) { tmpTag->artist = tag->artist().toCString(); tmpTag->title = tag->title().toCString(); tmpTag->valid = true; tmpTag->filename = fullPath; m_playLists->at(i)->setId3(j,tmpTag); anyValid = true; emit tagReceived(m_playLists->at(i)->title(),j,tmpTag); } else { if (tmpTag->filename != fullPath) { tmpTag->artist = tag->artist().toCString(); tmpTag->title = tag->title().toCString(); tmpTag->filename = fullPath; tmpTag->valid = true; m_playLists->at(i)->setId3(j,tmpTag); anyValid = true; emit tagReceived(m_playLists->at(i)->title(),j,tmpTag); } } } //ID3Tag *tmpTag = new ID3Tag(); } else { qDebug() << "MediaScannerThread: Invalid File in standardpass" << fullPath; } QThread::msleep(delay); } } if (firstScan) { firstScan = false; qDebug() << "Initial scan of id3 tags completed. "; if (anyValid) { qDebug() << "Moving to background mode..."; } else { qDebug() << "All files scanned, exiting thread"; } } else { qDebug() << "Secondary id3 scan complete... continuing..."; } } } /* int done = 1; return; QFile tmpFile("music.conf"); if (!tmpFile.open(QIODevice::ReadOnly | QIODevice::Text)) { printf("Error opening configuration file!!!\n"); return; } QString musicDir(tmpFile.readLine()); printf("Music Directory from configuration file: %s\n",musicDir.toStdString().c_str()); tmpFile.close(); musicDir = musicDir.mid(0,musicDir.length()-1); QDir tmpDir(musicDir); tmpDir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot); QDir tmpFiles(musicDir); tmpFiles.setFilter(QDir::Files | QDir::NoDotAndDotDot); QStringList infoList = tmpDir.entryList(); foreach (QString info,infoList) { TagLib::FileRef testfile(info.toStdString().c_str()); TagLib::Tag *tag = testfile.tag(); ID3Tag *tmpTag = new ID3Tag(); tmpTag->artist = tag->artist().to8Bit().c_str(); tmpTag->title = tag->title().to8Bit().c_str(); //emit tagReceived(tmpTag); } bool inLoop = true; //while (inLoop) //{ //QThread:: // QThread::sleep(1); // ID3Tag *tmpTag = new ID3Tag(); //tmpTag->artist = //} */ }
static Meta::ReplayGainTagMap readID3v2Tags( TagLib::ID3v2::Tag *tag ) { Meta::ReplayGainTagMap map; { // ID3v2.4.0 native replay gain tag support (as written by Quod Libet, for example). TagLib::ID3v2::FrameList frames = tag->frameListMap()["RVA2"]; frames.append(tag->frameListMap()["XRVA"]); if ( !frames.isEmpty() ) { for ( unsigned int i = 0; i < frames.size(); ++i ) { // we have to parse this frame ourselves // ID3v2 frame header is 10 bytes, so skip that TagLib::ByteVector data = frames[i]->render().mid( 10 ); unsigned int offset = 0; QString desc( data.data() ); offset += desc.count() + 1; unsigned int channel = data.mid( offset, 1 ).toUInt( true ); // channel 1 is the main volume - the only one we care about if ( channel == 1 ) { ++offset; qint16 adjustment512 = data.mid( offset, 2 ).toShort( true ); qreal adjustment = ( (qreal)adjustment512 ) / 512.0; offset += 2; unsigned int peakBits = data.mid( offset, 1 ).toUInt( true ); ++offset; bool ok = false; qreal peak = readRVA2PeakValue( data.mid( offset ), peakBits, &ok ); if ( ok ) { if ( desc.toLower() == "album" ) { map[Meta::ReplayGain_Album_Gain] = adjustment; map[Meta::ReplayGain_Album_Peak] = peakToDecibels( peak ); } else if ( desc.toLower() == "track" || !map.contains( Meta::ReplayGain_Track_Gain ) ) { map[Meta::ReplayGain_Track_Gain] = adjustment; map[Meta::ReplayGain_Track_Peak] = peakToDecibels( peak ); } } } } if ( !map.isEmpty() ) return map; } } { // Foobar2000-style ID3v2.3.0 tags TagLib::ID3v2::FrameList frames = tag->frameListMap()["TXXX"]; for ( TagLib::ID3v2::FrameList::Iterator it = frames.begin(); it != frames.end(); ++it ) { TagLib::ID3v2::UserTextIdentificationFrame* frame = dynamic_cast<TagLib::ID3v2::UserTextIdentificationFrame*>( *it ); if ( frame && frame->fieldList().size() >= 2 ) { QString desc = TStringToQString( frame->description() ).toLower(); if ( desc == "replaygain_album_gain" ) maybeAddGain( frame->fieldList()[1], Meta::ReplayGain_Album_Gain, &map ); if ( desc == "replaygain_album_peak" ) maybeAddPeak( frame->fieldList()[1], Meta::ReplayGain_Album_Peak, &map ); if ( desc == "replaygain_track_gain" ) maybeAddGain( frame->fieldList()[1], Meta::ReplayGain_Track_Gain, &map ); if ( desc == "replaygain_track_peak" ) maybeAddPeak( frame->fieldList()[1], Meta::ReplayGain_Track_Peak, &map ); } } } return map; }