/** Set or remove any rating. */ void FileHelper::setRating(int rating) { switch (_fileType) { case EXT_MP3: { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile->hasID3v2Tag()) { this->setRatingForID3v2(rating, mpegFile->ID3v2Tag()); } else if (mpegFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented for ID3v1Tag"; } break; } case EXT_FLAC: { TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file); if (flacFile->hasID3v2Tag()) { this->setRatingForID3v2(rating, flacFile->ID3v2Tag()); } else if (flacFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "hasID3v1Tag"; } else if (flacFile->hasXiphComment()) { TagLib::Ogg::XiphComment *xiph = flacFile->xiphComment(); if (rating == 0) { xiph->removeField("RATING"); } else { xiph->addField("RATING", QString::number(rating).toStdString()); } } break; } default: break; } this->save(); }
/** Convert the existing rating number into a smaller range from 1 to 5. */ int FileHelper::rating() const { int r = -1; /// TODO other types? switch (_fileType) { case EXT_MP3: { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile && mpegFile->hasID3v2Tag()) { r = this->ratingForID3v2(mpegFile->ID3v2Tag()); } break; } case EXT_FLAC: { if (TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file)) { if (flacFile->hasID3v2Tag()) { r = this->ratingForID3v2(flacFile->ID3v2Tag()); } else if (flacFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented (FLAC ID3v1)"; } else if (flacFile->hasXiphComment()) { TagLib::StringList list = flacFile->xiphComment()->fieldListMap()["RATING"]; if (!list.isEmpty()) { r = list.front().toInt(); } } } break; } default: break; } return r; }
/** Check if file has an inner picture. */ bool FileHelper::hasCover() const { bool atLeastOnePicture = false; switch (_fileType) { case EXT_MP3: { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile && mpegFile->hasID3v2Tag()) { // Look for picture frames only TagLib::ID3v2::FrameList listOfMp3Frames = mpegFile->ID3v2Tag()->frameListMap()["APIC"]; // It's possible to have more than one picture per file! if (!listOfMp3Frames.isEmpty()) { for (TagLib::ID3v2::FrameList::ConstIterator it = listOfMp3Frames.begin(); it != listOfMp3Frames.end() ; it++) { // Cast a Frame* to AttachedPictureFrame* TagLib::ID3v2::AttachedPictureFrame *pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it); atLeastOnePicture = atLeastOnePicture || (pictureFrame != nullptr && !pictureFrame->picture().isEmpty()); } } } break; } case EXT_FLAC: { if (TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file)) { atLeastOnePicture = !flacFile->pictureList().isEmpty(); } } default: break; } return atLeastOnePicture; }
bool CTagBase::exportImage(const wchar_t* s) { if (!s) return false; if (_tagFile) { //get picture TagLib::MPEG::File *f = (TagLib::MPEG::File *)_tagFile.get(); if (!f->hasID3v2Tag() || f->ID3v2Tag()->isEmpty()) return false; /* TagLib::ID3v2::FrameList::ConstIterator it = f->ID3v2Tag()->frameList().begin(); for (; it != f->ID3v2Tag()->frameList().end(); it++) { if ((*it)->frameID().operator == (TagLib::ByteVector("APIC"))) { HANDLE hFile = CreateFile(s, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) return false; int nWriteBytes = 0; size_t size = (*it)->size(); ::WriteFile(hFile, (*it)->render().data(), (*it)->size(), (LPDWORD)&nWriteBytes, NULL); ::CloseHandle(hFile); if (nWriteBytes != size) return false; return true; } }*/ if (f->ID3v2Tag()->frameListMap().size() == 0) return false; if (f->ID3v2Tag()->frameListMap().find("APIC") == f->ID3v2Tag()->frameListMap().end()) return false; TagLib::ID3v2::FrameList Flist = f->ID3v2Tag()->frameListMap()["APIC"]; if (Flist.isEmpty()) return false; TagLib::ID3v2::AttachedPictureFrame *p = static_cast<TagLib::ID3v2::AttachedPictureFrame *>(Flist.front()); size_t size = p->picture().size(); CString strPicType = p->mimeType().toCString(true); int nPos = strPicType.Find('/'); CString strTemp = strPicType.Right(strPicType.GetLength() - nPos - 1); //CString strPicPath = s; //if (strTemp == _T("png")) // strPicPath.Append(_T(".png")); //else // strPicPath.Append(_T(".jpg")); HANDLE hFile = CreateFile(s, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) return false; int nWriteBytes = 0; ::WriteFile(hFile, p->picture().data(), size, (LPDWORD)&nWriteBytes, NULL); ::CloseHandle(hFile); if (nWriteBytes != size) return false; return true; } return false; }
bool FileHelper::save() { if (_fileType == EXT_MP3) { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); // TagLib updates tags with the latest version (ID3v2.4) // We just want to save the file with the exact same version! if (mpegFile->hasID3v2Tag()) { return mpegFile->save(TagLib::MPEG::File::AllTags, false, mpegFile->ID3v2Tag()->header()->majorVersion()); } } else if (_fileType != EXT_UNKNOWN) { return _file->save(); } return false; }
void FileHelper::setArtistAlbum(const QString &artistAlbum) { switch (_fileType) { case EXT_FLAC: { this->setFlacAttribute("ALBUMARTIST", artistAlbum); break; } case EXT_MP4:{ TagLib::StringList l; l.append(artistAlbum.toStdString().data()); TagLib::MP4::Item item(l); this->setMp4Attribute("aART", item); break; } case EXT_MPC: //mpcFile = static_cast<MPC::File*>(f); qDebug() << Q_FUNC_INFO << "Not implemented for MPC"; break; case EXT_MP3:{ TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile->hasID3v2Tag()) { TagLib::ID3v2::Tag *tag = mpegFile->ID3v2Tag(); QString convertedKey = this->convertKeyToID3v2Key("ARTISTALBUM"); TagLib::ID3v2::FrameList l = tag->frameListMap()[convertedKey.toStdString().data()]; if (!l.isEmpty()) { tag->removeFrame(l.front()); } TagLib::ID3v2::TextIdentificationFrame *tif = new TagLib::ID3v2::TextIdentificationFrame(TagLib::ByteVector(convertedKey.toStdString().data())); tif->setText(artistAlbum.toStdString().data()); tag->addFrame(tif); } else if (mpegFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented for ID3v1Tag"; } break; } case EXT_OGG: { TagLib::Ogg::XiphComment *xiphComment = static_cast<TagLib::Ogg::XiphComment*>(_file->tag()); if (xiphComment) { xiphComment->addField("ALBUMARTIST", artistAlbum.toStdString().data()); } else { qDebug() << Q_FUNC_INFO << "Not implemented for this OGG file"; } break; } default: qDebug() << Q_FUNC_INFO << "Not implemented for this type of file"; break; } }
Cover* FileHelper::extractCover() { Cover *cover = nullptr; switch (_fileType) { case EXT_MP3: { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile && mpegFile->hasID3v2Tag()) { // Look for picture frames only TagLib::ID3v2::FrameList listOfMp3Frames = mpegFile->ID3v2Tag()->frameListMap()["APIC"]; // It's possible to have more than one picture per file! if (!listOfMp3Frames.isEmpty()) { for (TagLib::ID3v2::FrameList::ConstIterator it = listOfMp3Frames.begin(); it != listOfMp3Frames.end() ; it++) { // Cast a Frame* to AttachedPictureFrame* TagLib::ID3v2::AttachedPictureFrame *pictureFrame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(*it); if (pictureFrame) { // Performs a deep copy of the cover QByteArray b = QByteArray(pictureFrame->picture().data(), pictureFrame->picture().size()); cover = new Cover(b, QString(pictureFrame->mimeType().toCString(true))); } } } } else if (mpegFile && mpegFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented for ID3v1Tag"; } break; } case EXT_FLAC: { if (TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file)) { auto list = flacFile->pictureList(); for (auto it = list.begin(); it != list.end() ; it++) { TagLib::FLAC::Picture *p = *it; if (p->type() == TagLib::FLAC::Picture::FrontCover) { // Performs a deep copy of the cover QByteArray b = QByteArray(p->data().data(), p->data().size()); cover = new Cover(b, QString(p->mimeType().toCString(true))); break; } } } break; } default: qDebug() << Q_FUNC_INFO << "Not implemented for this file type" << _fileType << _file << _fileInfo.absoluteFilePath(); break; } return cover; }
/** Sets the inner picture. */ void FileHelper::setCover(Cover *cover) { switch (_fileType) { case EXT_MP3: { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile->hasID3v2Tag()) { // Look for picture frames only TagLib::ID3v2::FrameList mp3Frames = mpegFile->ID3v2Tag()->frameListMap()["APIC"]; if (!mp3Frames.isEmpty()) { for (TagLib::ID3v2::FrameList::Iterator it = mp3Frames.begin(); it != mp3Frames.end() ; it++) { // Removing a frame will invalidate any pointers on the list mpegFile->ID3v2Tag()->removeFrame(*it); break; } } if (cover != nullptr) { TagLib::ByteVector bv(cover->byteArray().data(), cover->byteArray().length()); TagLib::ID3v2::AttachedPictureFrame *pictureFrame = new TagLib::ID3v2::AttachedPictureFrame(); pictureFrame->setMimeType(cover->mimeType()); pictureFrame->setPicture(bv); pictureFrame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover); mpegFile->ID3v2Tag()->addFrame(pictureFrame); } } else if (mpegFile->hasID3v1Tag()) { qDebug() << Q_FUNC_INFO << "Not implemented for ID3v1Tag"; } break; } case EXT_FLAC: { TagLib::FLAC::File *flacFile = static_cast<TagLib::FLAC::File*>(_file); flacFile->removePictures(); if (cover != nullptr) { TagLib::FLAC::Picture *picture = new TagLib::FLAC::Picture; picture->setType(TagLib::FLAC::Picture::FrontCover); TagLib::ByteVector bv(cover->byteArray().data(), cover->byteArray().length()); picture->setData(bv); flacFile->addPicture(picture); } break; } default: qDebug() << Q_FUNC_INFO << "Not implemented for" << _fileType; break; } }
/** Set or remove any disc number. */ void FileHelper::setDiscNumber(const QString &disc) { switch (_fileType) { case EXT_FLAC: { this->setFlacAttribute("DISCNUMBER", disc); break; } case EXT_OGG: { TagLib::Ogg::XiphComment *xiphComment = static_cast<TagLib::Ogg::XiphComment*>(_file->tag()); if (xiphComment) { xiphComment->addField("DISCNUMBER", disc.toStdString().data()); } else { qDebug() << Q_FUNC_INFO << "Not implemented for this OGG file"; } break; } case EXT_MP3: { TagLib::MPEG::File *mpegFile = static_cast<TagLib::MPEG::File*>(_file); if (mpegFile && mpegFile->hasID3v2Tag()) { // Remove existing disc number if one has set an empty string if (disc.isEmpty()) { mpegFile->ID3v2Tag()->removeFrames(TagLib::ByteVector("TPOS")); } else { TagLib::ID3v2::TextIdentificationFrame *f = new TagLib::ID3v2::TextIdentificationFrame(TagLib::ByteVector("TPOS")); f->setText(disc.toStdString()); mpegFile->ID3v2Tag()->addFrame(f); } } break; } case EXT_MP4: { TagLib::MP4::Item item(disc.toUInt()); this->setMp4Attribute("disk", item); break; } default: qDebug() << Q_FUNC_INFO << "Not implemented for this file type"; break; } }