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 TagReader::IsMediaFile(const QString& filename) const { qLog(Debug) << "Checking for valid file" << filename; std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename)); return !fileref->isNull() && fileref->tag(); }
bool TagReader::SaveSongRatingToFile( const QString& filename, const pb::tagreader::SongMetadata& song) const { if (filename.isNull()) return false; qLog(Debug) << "Saving song rating tags to" << filename; if (song.rating() < 0) { // The FMPS spec says unrated == "tag not present". For us, no rating // results in rating being -1, so don't write anything in that case. // Actually, we should also remove tag set in this case, but in // Clementine it is not possible to unset rating i.e. make a song "unrated". qLog(Debug) << "Unrated: do nothing"; return true; } std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) // The file probably doesn't exist return false; if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) { TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true); // Save as FMPS SetUserTextFrame("FMPS_Rating", QString::number(song.rating()), tag); // Also save as POPM TagLib::ID3v2::PopularimeterFrame* frame = GetPOPMFrameFromTag(tag); frame->setRating(ConvertToPOPMRating(song.rating())); } else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) { TagLib::Ogg::XiphComment* vorbis_comments = file->xiphComment(true); SetFMPSRatingVorbisComments(vorbis_comments, song); } else if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>( fileref->file()->tag())) { SetFMPSRatingVorbisComments(tag, song); } #ifdef TAGLIB_WITH_ASF else if (TagLib::ASF::File* file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) { TagLib::ASF::Tag* tag = file->tag(); tag->addAttribute("FMPS/Rating", NumberToASFAttribute(song.rating())); } #endif else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) { TagLib::MP4::Tag* tag = file->tag(); tag->itemListMap()[kMP4_FMPS_Rating_ID] = TagLib::StringList( QStringToTaglibString(QString::number(song.rating()))); } else { // Nothing to save: stop now return true; } bool ret = fileref->save(); #ifdef Q_OS_LINUX if (ret) { // Linux: inotify doesn't seem to notice the change to the file unless we // change the timestamps as well. (this is what touch does) utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0); } #endif // Q_OS_LINUX return ret; }
bool TagReader::SaveSongStatisticsToFile( const QString& filename, const pb::tagreader::SongMetadata& song) const { if (filename.isNull()) return false; qLog(Debug) << "Saving song statistics tags to" << filename; std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) // The file probably doesn't exist return false; if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) { TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true); // Save as FMPS SetUserTextFrame("FMPS_PlayCount", QString::number(song.playcount()), tag); SetUserTextFrame("FMPS_Rating_Amarok_Score", QString::number(song.score() / 100.0), tag); // Also save as POPM TagLib::ID3v2::PopularimeterFrame* frame = GetPOPMFrameFromTag(tag); frame->setCounter(song.playcount()); } else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) { TagLib::Ogg::XiphComment* vorbis_comments = file->xiphComment(true); SetFMPSStatisticsVorbisComments(vorbis_comments, song); } else if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>( fileref->file()->tag())) { SetFMPSStatisticsVorbisComments(tag, song); } #ifdef TAGLIB_WITH_ASF else if (TagLib::ASF::File* file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) { TagLib::ASF::Tag* tag = file->tag(); tag->addAttribute("FMPS/Playcount", NumberToASFAttribute(song.playcount())); tag->addAttribute("FMPS/Rating_Amarok_Score", NumberToASFAttribute(song.score() / 100.0)); } #endif else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) { TagLib::MP4::Tag* tag = file->tag(); tag->itemListMap()[kMP4_FMPS_Score_ID] = TagLib::StringList( QStringToTaglibString(QString::number(song.score() / 100.0))); tag->itemListMap()[kMP4_FMPS_Playcount_ID] = TagLib::StringList(TagLib::String::number(song.playcount())); } else { // Nothing to save: stop now return true; } bool ret = fileref->save(); #ifdef Q_OS_LINUX if (ret) { // Linux: inotify doesn't seem to notice the change to the file unless we // change the timestamps as well. (this is what touch does) utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0); } #endif // Q_OS_LINUX return ret; }
bool TagReader::SaveFile(const QString& filename, const pb::tagreader::SongMetadata& song) const { if (filename.isNull()) return false; qLog(Debug) << "Saving tags to" << filename; std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename)); if (!fileref || fileref->isNull()) // The file probably doesn't exist return false; fileref->tag()->setTitle(StdStringToTaglibString(song.title())); fileref->tag()->setArtist(StdStringToTaglibString(song.artist())); // TPE1 fileref->tag()->setAlbum(StdStringToTaglibString(song.album())); fileref->tag()->setGenre(StdStringToTaglibString(song.genre())); fileref->tag()->setComment(StdStringToTaglibString(song.comment())); fileref->tag()->setYear(song.year()); fileref->tag()->setTrack(song.track()); if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) { TagLib::ID3v2::Tag* tag = file->ID3v2Tag(true); SetTextFrame( "TPOS", song.disc() <= 0 - 1 ? QString() : QString::number(song.disc()), tag); SetTextFrame("TBPM", song.bpm() <= 0 - 1 ? QString() : QString::number(song.bpm()), tag); SetTextFrame("TCOM", song.composer(), tag); SetTextFrame("TIT1", song.grouping(), tag); // Skip TPE1 (which is the artist) here because we already set it SetTextFrame("TPE2", song.albumartist(), tag); SetTextFrame("TCMP", std::string(song.compilation() ? "1" : "0"), tag); } else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) { TagLib::Ogg::XiphComment* tag = file->xiphComment(); SetVorbisComments(tag, song); } else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) { TagLib::MP4::Tag* tag = file->tag(); tag->itemListMap()["disk"] = TagLib::MP4::Item(song.disc() <= 0 - 1 ? 0 : song.disc(), 0); tag->itemListMap()["tmpo"] = TagLib::StringList( song.bpm() <= 0 - 1 ? "0" : TagLib::String::number(song.bpm())); tag->itemListMap()["\251wrt"] = TagLib::StringList(song.composer()); tag->itemListMap()["\251grp"] = TagLib::StringList(song.grouping()); tag->itemListMap()["aART"] = TagLib::StringList(song.albumartist()); tag->itemListMap()["cpil"] = TagLib::StringList(song.compilation() ? "1" : "0"); } // Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same // way; // apart, so we keep specific behavior for some formats by adding another // "else if" block above. if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) { SetVorbisComments(tag, song); } bool ret = fileref->save(); #ifdef Q_OS_LINUX if (ret) { // Linux: inotify doesn't seem to notice the change to the file unless we // change the timestamps as well. (this is what touch does) utimensat(0, QFile::encodeName(filename).constData(), nullptr, 0); } #endif // Q_OS_LINUX return ret; }
void TagReader::ReadFile(const QString& filename, pb::tagreader::SongMetadata* song) const { const QByteArray url(QUrl::fromLocalFile(filename).toEncoded()); const QFileInfo info(filename); qLog(Debug) << "Reading tags from" << filename; song->set_basefilename(DataCommaSizeFromQString(info.fileName())); song->set_url(url.constData(), url.size()); song->set_filesize(info.size()); song->set_mtime(info.lastModified().toTime_t()); song->set_ctime(info.created().toTime_t()); std::unique_ptr<TagLib::FileRef> fileref(factory_->GetFileRef(filename)); if (fileref->isNull()) { qLog(Info) << "TagLib hasn't been able to read " << filename << " file"; return; } TagLib::Tag* tag = fileref->tag(); if (tag) { Decode(tag->title(), nullptr, song->mutable_title()); Decode(tag->artist(), nullptr, song->mutable_artist()); // TPE1 Decode(tag->album(), nullptr, song->mutable_album()); Decode(tag->genre(), nullptr, song->mutable_genre()); song->set_year(tag->year()); song->set_track(tag->track()); song->set_valid(true); } QString disc; QString compilation; // Handle all the files which have VorbisComments (Ogg, OPUS, ...) in the same // way; // apart, so we keep specific behavior for some formats by adding another // "else if" block below. if (TagLib::Ogg::XiphComment* tag = dynamic_cast<TagLib::Ogg::XiphComment*>(fileref->file()->tag())) { ParseOggTag(tag->fieldListMap(), nullptr, &disc, &compilation, song); } if (TagLib::MPEG::File* file = dynamic_cast<TagLib::MPEG::File*>(fileref->file())) { if (file->ID3v2Tag()) { const TagLib::ID3v2::FrameListMap& map = file->ID3v2Tag()->frameListMap(); if (!map["TPOS"].isEmpty()) disc = TStringToQString(map["TPOS"].front()->toString()).trimmed(); if (!map["TBPM"].isEmpty()) song->set_bpm(TStringToQString(map["TBPM"].front()->toString()) .trimmed() .toFloat()); if (!map["TCOM"].isEmpty()) Decode(map["TCOM"].front()->toString(), nullptr, song->mutable_composer()); if (!map["TIT1"].isEmpty()) // content group Decode(map["TIT1"].front()->toString(), nullptr, song->mutable_grouping()); // Skip TPE1 (which is the artist) here because we already fetched it if (!map["TPE2"].isEmpty()) // non-standard: Apple, Microsoft Decode(map["TPE2"].front()->toString(), nullptr, song->mutable_albumartist()); if (!map["TCMP"].isEmpty()) compilation = TStringToQString(map["TCMP"].front()->toString()).trimmed(); if (!map["APIC"].isEmpty()) song->set_art_automatic(kEmbeddedCover); // Find a suitable comment tag. For now we ignore iTunNORM comments. for (int i = 0; i < map["COMM"].size(); ++i) { const TagLib::ID3v2::CommentsFrame* frame = dynamic_cast<const TagLib::ID3v2::CommentsFrame*>(map["COMM"][i]); if (frame && TStringToQString(frame->description()) != "iTunNORM") { Decode(frame->text(), nullptr, song->mutable_comment()); break; } } // Parse FMPS frames for (int i = 0; i < map["TXXX"].size(); ++i) { const TagLib::ID3v2::UserTextIdentificationFrame* frame = dynamic_cast<const TagLib::ID3v2::UserTextIdentificationFrame*>( map["TXXX"][i]); if (frame && frame->description().startsWith("FMPS_")) { ParseFMPSFrame(TStringToQString(frame->description()), TStringToQString(frame->fieldList()[1]), song); } } // Check POPM tags // We do this after checking FMPS frames, so FMPS have precedence, as we // will consider POPM tags iff song has no rating/playcount already set. if (!map["POPM"].isEmpty()) { const TagLib::ID3v2::PopularimeterFrame* frame = dynamic_cast<const TagLib::ID3v2::PopularimeterFrame*>( map["POPM"].front()); if (frame) { // Take a user rating only if there's no rating already set if (song->rating() <= 0 && frame->rating() > 0) { song->set_rating(ConvertPOPMRating(frame->rating())); } if (song->playcount() <= 0 && frame->counter() > 0) { song->set_playcount(frame->counter()); } } } } } else if (TagLib::FLAC::File* file = dynamic_cast<TagLib::FLAC::File*>(fileref->file())) { if (file->xiphComment()) { ParseOggTag(file->xiphComment()->fieldListMap(), nullptr, &disc, &compilation, song); #ifdef TAGLIB_HAS_FLAC_PICTURELIST if (!file->pictureList().isEmpty()) { song->set_art_automatic(kEmbeddedCover); } #endif } Decode(tag->comment(), nullptr, song->mutable_comment()); } else if (TagLib::MP4::File* file = dynamic_cast<TagLib::MP4::File*>(fileref->file())) { if (file->tag()) { TagLib::MP4::Tag* mp4_tag = file->tag(); const TagLib::MP4::ItemListMap& items = mp4_tag->itemListMap(); // Find album artists TagLib::MP4::ItemListMap::ConstIterator it = items.find("aART"); if (it != items.end()) { TagLib::StringList album_artists = it->second.toStringList(); if (!album_artists.isEmpty()) { Decode(album_artists.front(), nullptr, song->mutable_albumartist()); } } // Find album cover art if (items.find("covr") != items.end()) { song->set_art_automatic(kEmbeddedCover); } if (items.contains("disk")) { disc = TStringToQString( TagLib::String::number(items["disk"].toIntPair().first)); } if (items.contains(kMP4_FMPS_Rating_ID)) { float rating = TStringToQString(items[kMP4_FMPS_Rating_ID].toStringList().toString( '\n')).toFloat(); if (song->rating() <= 0 && rating > 0) { song->set_rating(rating); } } if (items.contains(kMP4_FMPS_Playcount_ID)) { int playcount = TStringToQString( items[kMP4_FMPS_Playcount_ID].toStringList().toString('\n')) .toFloat(); if (song->playcount() <= 0 && playcount > 0) { song->set_playcount(playcount); } } if (items.contains(kMP4_FMPS_Playcount_ID)) { int score = TStringToQString( items[kMP4_FMPS_Score_ID].toStringList().toString('\n')) .toFloat() * 100; if (song->score() <= 0 && score > 0) { song->set_score(score); } } if (items.contains("\251wrt")) { Decode(items["\251wrt"].toStringList().toString(", "), nullptr, song->mutable_composer()); } if (items.contains("\251grp")) { Decode(items["\251grp"].toStringList().toString(" "), nullptr, song->mutable_grouping()); } Decode(mp4_tag->comment(), nullptr, song->mutable_comment()); } } #ifdef TAGLIB_WITH_ASF else if (TagLib::ASF::File* file = dynamic_cast<TagLib::ASF::File*>(fileref->file())) { const TagLib::ASF::AttributeListMap& attributes_map = file->tag()->attributeListMap(); if (attributes_map.contains("FMPS/Rating")) { const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating"]; if (!attributes.isEmpty()) { float rating = TStringToQString(attributes.front().toString()).toFloat(); if (song->rating() <= 0 && rating > 0) { song->set_rating(rating); } } } if (attributes_map.contains("FMPS/Playcount")) { const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Playcount"]; if (!attributes.isEmpty()) { int playcount = TStringToQString(attributes.front().toString()).toInt(); if (song->playcount() <= 0 && playcount > 0) { song->set_playcount(playcount); } } } if (attributes_map.contains("FMPS/Rating_Amarok_Score")) { const TagLib::ASF::AttributeList& attributes = attributes_map["FMPS/Rating_Amarok_Score"]; if (!attributes.isEmpty()) { int score = TStringToQString(attributes.front().toString()).toFloat() * 100; if (song->score() <= 0 && score > 0) { song->set_score(score); } } } } #endif else if (tag) { Decode(tag->comment(), nullptr, song->mutable_comment()); } if (!disc.isEmpty()) { const int i = disc.indexOf('/'); if (i != -1) { // disc.right( i ).toInt() is total number of discs, we don't use this at // the moment song->set_disc(disc.left(i).toInt()); } else { song->set_disc(disc.toInt()); } } if (compilation.isEmpty()) { // well, it wasn't set, but if the artist is VA assume it's a compilation if (QStringFromStdString(song->artist()).toLower() == "various artists") { song->set_compilation(true); } } else { song->set_compilation(compilation.toInt() == 1); } if (fileref->audioProperties()) { song->set_bitrate(fileref->audioProperties()->bitrate()); song->set_samplerate(fileref->audioProperties()->sampleRate()); song->set_length_nanosec(fileref->audioProperties()->length() * kNsecPerSec); } // Get the filetype if we can song->set_type(GuessFileType(fileref.get())); // Set integer fields to -1 if they're not valid #define SetDefault(field) \ if (song->field() <= 0) { \ song->set_##field(-1); \ } SetDefault(track); SetDefault(disc); SetDefault(bpm); SetDefault(year); SetDefault(bitrate); SetDefault(samplerate); SetDefault(lastplayed); #undef SetDefault }
void CollectionScanner::popFromQueue() { if (stopped) return; if (fileQueue.isEmpty()) { complete(); return; } QFileInfo fileInfo = fileQueue.first(); // qDebug() << "Processing " << fileInfo.absoluteFilePath(); // parse metadata with TagLib QString filename = fileInfo.absoluteFilePath(); #ifdef Q_OS_WIN const wchar_t * encodedName = reinterpret_cast<const wchar_t*>(filename.utf16()); TagLib::FileRef fileref(encodedName); #else // const char * encodedName = QFile::encodeName(filename).constData(); TagLib::FileRef fileref((TagLib::FileName)filename.toUtf8()); #endif // if taglib cannot parse the file, drop it if (fileref.isNull()) { // qDebug() << "Taglib cannot parse" << fileInfo.absoluteFilePath(); fileQueue.removeAll(fileInfo); // add to nontracks table QString path = fileInfo.absoluteFilePath(); path.remove(this->rootDirectory.absolutePath() + "/"); insertOrUpdateNonTrack(path, QDateTime::currentDateTime().toTime_t()); QTimer::singleShot(0, this, SLOT(popFromQueue())); return; } // Ok this is an interesting file // This object will experience an incredible adventure, // facing countless perils and finally reaching its final destination FileInfo *file = new FileInfo(); file->setFileInfo(fileInfo); // Copy TagLib::FileRef in our Tags class. // TagLib::FileRef keeps files open and we would quickly reach the max open files limit Tags *tags = new Tags(); TagLib::Tag *tag = fileref.tag(); if (tag) { tags->title = Tags::toQString(tag->title()); tags->artist = Tags::toQString(tag->artist()); tags->album = Tags::toQString(tag->album()); tags->track = tag->track(); tags->year = tag->year(); TagLib::AudioProperties *audioProperties = fileref.audioProperties(); if (audioProperties) tags->length = audioProperties->length(); } file->setTags(tags); // get data from the internet giveThisFileAnArtist(file); }
void nuiMimeMultiPart::Dump(nglOStream* pStream) { nglString varname(_T("MyParam")); nglString value(_T("MyValue")); nglString fileref(_T("MyFile")); nglString filename(_T("prout.txt")); // nglString filename(_T("")); nglString mimetype("plain/text"); const uint8* data = (const uint8*)"YATTA!"; uint32 datalen = strlen((const char*)data); ////////////////////////////////////// nglString str; // prepare start and end boundaries: nglString start; start.CFormat(_T("--%s"), mBoundary.GetChars()); nglString end; end.Add(_T("\n")); end.Add(start); end.Add(_T("--\n")); start.Add(_T("\n")); { std::map<nglString, nglString>::const_iterator it = mVariables.begin(); std::map<nglString, nglString>::const_iterator end = mVariables.end(); while (it != end) { pStream->WriteText(start); str.CFormat(_T("Content-Disposition: form-data; name=\"%s\"\n\n"), it->first.GetChars()); pStream->WriteText(str); pStream->WriteText(it->second); pStream->WriteText(_T("\n")); ++it; } } { for (uint32 i = 0; i < mpFiles.size(); i++) { pStream->WriteText(start); str.CFormat(_T("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\n"), mpFiles[i]->mVarName.GetChars(), mpFiles[i]->mFileName.GetChars()); pStream->WriteText(str); str.CFormat(_T("Content-Transfer-Encoding: %s\n"), mpFiles[i]->mContentTransfertEncoding.GetChars()); pStream->WriteText(str); str.CFormat(_T("Content-Type: %s\n\n"), mpFiles[i]->mType.GetChars()); pStream->WriteText(str); pStream->WriteUInt8(&mpFiles[i]->mContents[0], mpFiles[i]->mContents.size()); } } if (mVariables.empty() && mpFiles.empty()) pStream->WriteText(start); pStream->WriteText(end); //mem.WriteUInt8((const uint8*)"\0", 1); // Add final 0 for printf //nglString enc(mem.GetBufferData(), mem.GetSize()); //NGL_OUT(_T("Mime encoded:\n%s\n"), enc.GetChars()); }
Tags *TagUtils::load(const QString &filename) { #ifdef Q_OS_WIN const wchar_t * encodedName = reinterpret_cast<const wchar_t*>(filename.utf16()); TagLib::FileStream readOnlyStream(encodedName, true); #else TagLib::FileStream readOnlyStream((TagLib::FileName)filename.toUtf8(), true); #endif TagLib::FileRef fileref(&readOnlyStream); if (fileref.isNull()) { qDebug() << "Taglib cannot parse" << filename; return nullptr; } Tags *tags = new Tags(); tags->setFilename(filename); TagLib::Tag *tag = fileref.tag(); if (tag) { tags->setTitle(TagUtils::qString(tag->title())); tags->setArtistString(TagUtils::qString(tag->artist())); tags->setAlbumString(TagUtils::qString(tag->album())); tags->setGenre(TagUtils::qString(tag->genre())); tags->setTrackNumber(tag->track()); tags->setYear(tag->year()); tags->setComment(TagUtils::qString(tag->comment())); TagLib::AudioProperties *audioProperties = fileref.audioProperties(); if (audioProperties) tags->setDuration(audioProperties->length()); } /* TagLib::PropertyMap map = tag->properties(); for (TagLib::PropertyMap::ConstIterator i = map.begin(); i != map.end(); ++i) { for (TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) { const QString tagName = TagLibUtils::toQString(i->first); qDebug() << "PropertyMap" << tagName << TagLibUtils::toQString(*j); if (tagName == QLatin1String("ALBUMARTIST")) tags->setAlbumArtist(TagLibUtils::toQString(*j)); else if (tagName == QLatin1String("DISCNUMBER")) tags->setDiskNumber(TagLibUtils::toQString(*j).toInt()); // else if (tagName == QLatin1String("COMPOSER")) // tags->setComposer(toQString(*j)); else if (tagName == QLatin1String("LYRICS")) tags->setLyrics(TagLibUtils::toQString(*j)); //else if (tagName == QLatin1String("BPM")) // tags->bpm = toQString(*j).toInt(); // else qDebug() << "Unused tag" << tagName << toQString(*j); } } */ // Handle file types where TagLibf:::File::tag() returns a "TagUnion" TagLib::File *file = fileref.file(); if (TagLib::MPEG::File *f = dynamic_cast<TagLib::MPEG::File*>(file)) { if (TagLib::ID3v2::Tag *t = f->ID3v2Tag()) Id3Utils::load(t, tags); } else if (TagLib::TrueAudio::File *f = dynamic_cast<TagLib::TrueAudio::File*>(file)) { if (TagLib::ID3v2::Tag *t = f->ID3v2Tag()) Id3Utils::load(t, tags); } else if (TagLib::FLAC::File *f = dynamic_cast<TagLib::FLAC::File*>(file)) { if (TagLib::Ogg::XiphComment *t = f->xiphComment()) VorbisUtils::load(t, tags); else if (TagLib::ID3v2::Tag *t = f->ID3v2Tag()) Id3Utils::load(t, tags); } else if (TagLib::APE::File *f = dynamic_cast<TagLib::APE::File*>(file)) { if (TagLib::APE::Tag *t = f->APETag()) ApeUtils::load(t, tags); } else if (TagLib::MPC::File *f = dynamic_cast<TagLib::MPC::File*>(file)) { if (TagLib::APE::Tag *t = f->APETag()) ApeUtils::load(t, tags); } else if (TagLib::WavPack::File *f = dynamic_cast<TagLib::WavPack::File*>(file)) { if (TagLib::APE::Tag *t = f->APETag()) ApeUtils::load(t, tags); } else { // Fallback to casting tag() for any other file type TagLib::Tag *tag = file->tag(); if (TagLib::ID3v2::Tag *t = dynamic_cast<TagLib::ID3v2::Tag*>(tag)) Id3Utils::load(t, tags); else if (TagLib::Ogg::XiphComment *t = dynamic_cast<TagLib::Ogg::XiphComment*>(tag)) VorbisUtils::load(t, tags); else if (TagLib::APE::Tag *t = dynamic_cast<TagLib::APE::Tag*>(tag)) ApeUtils::load(t, tags); else if (TagLib::MP4::Tag *t = dynamic_cast<TagLib::MP4::Tag*>(tag)) Mp4Utils::load(t, tags); else if (TagLib::ASF::Tag *t = dynamic_cast<TagLib::ASF::Tag*>(tag)) AsfUtils::load(t, tags); } return tags; }