ByteVector ID3v2::Tag::albumArt(TagLib::ID3v2::AttachedPictureFrame::Type arttype, TagLib::String &mimetype) { if(!d->frameListMap["APIC"].isEmpty()) { ID3v2::AttachedPictureFrame *f = (ID3v2::AttachedPictureFrame *)d->frameListMap["APIC"].front(); mimetype = f->mimeType(); if(f->type() == arttype) { return f->picture(); } else { // do nothing } } else { // do nothing } return ByteVector(); }
void testCompressedFrameWithBrokenLength() { MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false); CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC")); ID3v2::AttachedPictureFrame *frame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front()); CPPUNIT_ASSERT(frame); CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type()); CPPUNIT_ASSERT_EQUAL(String(""), frame->description()); CPPUNIT_ASSERT_EQUAL(TagLib::uint(86414), frame->picture().size()); }
bool updateTags(char *path, Metadata *meta) { MPEG::File file(path); if (!file.isValid() || file.readOnly()) { return false; } ID3v2::Tag *tag = file.ID3v2Tag(true); if (!tag) { return false; } if (meta->hasArtist) { setTextFrame(tag, "TPE1", meta->artist); } if (meta->hasAlbum) { setTextFrame(tag, "TALB", meta->album); } if (meta->hasAlbumArtist) { setTextFrame(tag, "TPE2", meta->albumartist); } if (meta->hasTitle) { setTextFrame(tag, "TIT2", meta->title); } if (meta->hasTrackNumber) { String text = String::number(meta->trackNumber); if (meta->hasTrackCount) { text += "/" + String::number(meta->trackCount); } setTextFrame(tag, "TRCK", text); } if (meta->hasGenre) { setTextFrame(tag, "TCON", meta->genre); } if (meta->hasPublisher) { setTextFrame(tag, "TPUB", meta->publisher); } if (meta->hasYear) { setTextFrame(tag, "TDRC", String::number(meta->year)); } if (meta->hasImage) { ID3v2::AttachedPictureFrame *f = new ID3v2::AttachedPictureFrame(); f->setType(ID3v2::AttachedPictureFrame::Other); f->setPicture(meta->image); f->setMimeType(detectImageMimeType(meta->image)); tag->removeFrames("APIC"); tag->addFrame(f); } return file.save(MPEG::File::ID3v1 | MPEG::File::ID3v2, false, 3); }
void testParseAPICv22() { ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); ByteVector data = ByteVector("PIC" "\x00\x00\x08" "\x00" "JPG" "\x01" "d\x00" "\x00", 18); ID3v2::AttachedPictureFrame *frame = static_cast<TagLib::ID3v2::AttachedPictureFrame*>(factory->createFrame(data, TagLib::uint(2))); CPPUNIT_ASSERT(frame); CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), frame->mimeType()); CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, frame->type()); CPPUNIT_ASSERT_EQUAL(String("d"), frame->description()); }
bool CTagLoaderTagLib::ParseTag(ID3v2::Tag *id3v2, MUSIC_INFO::EmbeddedArt *art, MUSIC_INFO::CMusicInfoTag& tag) { if (!id3v2) return false; ReplayGain replayGainInfo; ID3v2::AttachedPictureFrame *pictures[3] = {}; const ID3v2::FrameListMap& frameListMap = id3v2->frameListMap(); for (ID3v2::FrameListMap::ConstIterator it = frameListMap.begin(); it != frameListMap.end(); ++it) { // It is possible that the taglist is empty. In that case no useable values can be extracted. // and we should skip the tag. if (it->second.isEmpty()) continue; if (it->first == "TPE1") SetArtist(tag, GetID3v2StringList(it->second)); else if (it->first == "TALB") tag.SetAlbum(it->second.front()->toString().to8Bit(true)); else if (it->first == "TPE2") SetAlbumArtist(tag, GetID3v2StringList(it->second)); else if (it->first == "TIT2") tag.SetTitle(it->second.front()->toString().to8Bit(true)); else if (it->first == "TCON") SetGenre(tag, GetID3v2StringList(it->second)); else if (it->first == "TRCK") tag.SetTrackNumber(strtol(it->second.front()->toString().toCString(true), NULL, 10)); else if (it->first == "TPOS") tag.SetDiscNumber(strtol(it->second.front()->toString().toCString(true), NULL, 10)); else if (it->first == "TYER") tag.SetYear(strtol(it->second.front()->toString().toCString(true), NULL, 10)); else if (it->first == "TCMP") tag.SetCompilation((strtol(it->second.front()->toString().toCString(true), NULL, 10) == 0) ? false : true); else if (it->first == "TENC") {} // EncodedBy else if (it->first == "TCOP") {} // Copyright message else if (it->first == "TDRC") tag.SetYear(strtol(it->second.front()->toString().toCString(true), NULL, 10)); else if (it->first == "TDRL") tag.SetYear(strtol(it->second.front()->toString().toCString(true), NULL, 10)); else if (it->first == "TDTG") {} // Tagging time else if (it->first == "TLAN") {} // Languages else if (it->first == "TMOO") tag.SetMood(it->second.front()->toString().to8Bit(true)); else if (it->first == "USLT") // Loop through any lyrics frames. Could there be multiple frames, how to choose? for (ID3v2::FrameList::ConstIterator lt = it->second.begin(); lt != it->second.end(); ++lt) { ID3v2::UnsynchronizedLyricsFrame *lyricsFrame = dynamic_cast<ID3v2::UnsynchronizedLyricsFrame *> (*lt); if (lyricsFrame) tag.SetLyrics(lyricsFrame->text().to8Bit(true)); } else if (it->first == "COMM") // Loop through and look for the main (no description) comment for (ID3v2::FrameList::ConstIterator ct = it->second.begin(); ct != it->second.end(); ++ct) { ID3v2::CommentsFrame *commentsFrame = dynamic_cast<ID3v2::CommentsFrame *> (*ct); if (commentsFrame && commentsFrame->description().isEmpty()) tag.SetComment(commentsFrame->text().to8Bit(true)); } else if (it->first == "TXXX") // Loop through and process the UserTextIdentificationFrames for (ID3v2::FrameList::ConstIterator ut = it->second.begin(); ut != it->second.end(); ++ut) { ID3v2::UserTextIdentificationFrame *frame = dynamic_cast<ID3v2::UserTextIdentificationFrame *> (*ut); if (!frame) continue; // First field is the same as the description StringList stringList = frame->fieldList(); if (stringList.size() == 1) continue; stringList.erase(stringList.begin()); String desc = frame->description().upper(); if (desc == "MUSICBRAINZ ARTIST ID") tag.SetMusicBrainzArtistID(SplitMBID(StringListToVectorString(stringList))); else if (desc == "MUSICBRAINZ ALBUM ID") tag.SetMusicBrainzAlbumID(stringList.front().to8Bit(true)); else if (desc == "MUSICBRAINZ ALBUM ARTIST ID") tag.SetMusicBrainzAlbumArtistID(SplitMBID(StringListToVectorString(stringList))); else if (desc == "MUSICBRAINZ ALBUM ARTIST") SetAlbumArtist(tag, StringListToVectorString(stringList)); else if (desc == "REPLAYGAIN_TRACK_GAIN") replayGainInfo.ParseGain(ReplayGain::TRACK, stringList.front().toCString(true)); else if (desc == "REPLAYGAIN_ALBUM_GAIN") replayGainInfo.ParseGain(ReplayGain::ALBUM, stringList.front().toCString(true)); else if (desc == "REPLAYGAIN_TRACK_PEAK") replayGainInfo.ParsePeak(ReplayGain::TRACK, stringList.front().toCString(true)); else if (desc == "REPLAYGAIN_ALBUM_PEAK") replayGainInfo.ParsePeak(ReplayGain::ALBUM, stringList.front().toCString(true)); else if (desc == "ALBUMARTIST" || desc == "ALBUM ARTIST") SetAlbumArtist(tag, StringListToVectorString(stringList)); else if (desc == "ARTISTS") { if (id3v2->header()->majorVersion() < 4) tag.SetMusicBrainzArtistHints(StringListToVectorString(TagLib::StringList::split(stringList.front(), TagLib::String("/")))); else tag.SetMusicBrainzArtistHints(StringListToVectorString(stringList)); } else if (desc == "ALBUMARTISTS" || desc == "ALBUM ARTISTS") { if (id3v2->header()->majorVersion() < 4) tag.SetMusicBrainzAlbumArtistHints(StringListToVectorString(TagLib::StringList::split(stringList.front(), TagLib::String("/")))); else tag.SetMusicBrainzAlbumArtistHints(StringListToVectorString(stringList)); } else if (desc == "MOOD") tag.SetMood(stringList.front().to8Bit(true)); else if (g_advancedSettings.m_logLevel == LOG_LEVEL_MAX) CLog::Log(LOGDEBUG, "unrecognized user text tag detected: TXXX:%s", frame->description().toCString(true)); } else if (it->first == "UFID") // Loop through any UFID frames and set them for (ID3v2::FrameList::ConstIterator ut = it->second.begin(); ut != it->second.end(); ++ut) { ID3v2::UniqueFileIdentifierFrame *ufid = reinterpret_cast<ID3v2::UniqueFileIdentifierFrame*> (*ut); if (ufid->owner() == "http://musicbrainz.org") { // MusicBrainz pads with a \0, but the spec requires binary, be cautious char cUfid[64]; int max_size = std::min((int)ufid->identifier().size(), 63); strncpy(cUfid, ufid->identifier().data(), max_size); cUfid[max_size] = '\0'; tag.SetMusicBrainzTrackID(cUfid); } } else if (it->first == "APIC") // Loop through all pictures and store the frame pointers for the picture types we want for (ID3v2::FrameList::ConstIterator pi = it->second.begin(); pi != it->second.end(); ++pi) { ID3v2::AttachedPictureFrame *pictureFrame = dynamic_cast<ID3v2::AttachedPictureFrame *> (*pi); if (!pictureFrame) continue; if (pictureFrame->type() == ID3v2::AttachedPictureFrame::FrontCover) pictures[0] = pictureFrame; else if (pictureFrame->type() == ID3v2::AttachedPictureFrame::Other) pictures[1] = pictureFrame; else if (pi == it->second.begin()) pictures[2] = pictureFrame; } else if (it->first == "POPM") // Loop through and process ratings for (ID3v2::FrameList::ConstIterator ct = it->second.begin(); ct != it->second.end(); ++ct) { ID3v2::PopularimeterFrame *popFrame = dynamic_cast<ID3v2::PopularimeterFrame *> (*ct); if (!popFrame) continue; // @xbmc.org ratings trump others (of course) if (popFrame->email() == "*****@*****.**") tag.SetUserrating(popFrame->rating() / 51 + '0'); else if (tag.GetUserrating() == '0') { if (popFrame->email() != "Windows Media Player 9 Series" && popFrame->email() != "Banshee" && popFrame->email() != "no@email" && popFrame->email() != "*****@*****.**" && popFrame->email() != "*****@*****.**") CLog::Log(LOGDEBUG, "unrecognized ratings schema detected: %s", popFrame->email().toCString(true)); tag.SetUserrating(POPMtoXBMC(popFrame->rating())); } } else if (g_advancedSettings.m_logLevel == LOG_LEVEL_MAX) CLog::Log(LOGDEBUG, "unrecognized ID3 frame detected: %c%c%c%c", it->first[0], it->first[1], it->first[2], it->first[3]); } // for // Process the extracted picture frames; 0 = CoverArt, 1 = Other, 2 = First Found picture for (int i = 0; i < 3; ++i) if (pictures[i]) { std::string mime = pictures[i]->mimeType().to8Bit(true); TagLib::uint size = pictures[i]->picture().size(); tag.SetCoverArtInfo(size, mime); if (art) art->set((const uint8_t*)pictures[i]->picture().data(), size, mime); // Stop after we find the first picture for now. break; } tag.SetReplayGain(replayGainInfo); return true; }
bool TagEditor::save() { if ( fRef ) { bool mustSave = false, result = false; if ( !isChecked() ) clearValues(); File &file = *fRef->file(); Tag &tag = getTag( *fRef, file ); if ( titleE->text() != tag.title().toCString( true ) ) { tag.setTitle( String( titleE->text().toUtf8().data(), String::UTF8 ) ); mustSave = true; } if ( artistE->text() != tag.artist().toCString( true ) ) { tag.setArtist( String( artistE->text().toUtf8().data(), String::UTF8 ) ); mustSave = true; } if ( albumE->text() != tag.album().toCString( true ) ) { tag.setAlbum( String( albumE->text().toUtf8().data(), String::UTF8 ) ); mustSave = true; } if ( commentE->text() != tag.comment().toCString( true ) ) { tag.setComment( String( commentE->text().toUtf8().data(), String::UTF8 ) ); mustSave = true; } if ( genreE->text() != tag.genre().toCString( true ) ) { tag.setGenre( String( genreE->text().toUtf8().data(), String::UTF8 ) ); mustSave = true; } if ( ( uint )yearB->value() != tag.year() ) { tag.setYear( yearB->value() ); mustSave = true; } if ( ( uint )trackB->value() != tag.track() ) { tag.setTrack( trackB->value() ); mustSave = true; } if ( isChecked() && ( pictureModificated || pictureBChecked != pictureB->isChecked() ) ) { const bool hasPicture = pictureB->isChecked() && !picture->isEmpty(); if ( instanceOf( file, MPEG::File ) || instanceOf( file, RIFF::AIFF::File ) ) { ID3v2::Tag *id3v2 = NULL; if ( instanceOf( file, MPEG::File ) ) id3v2 = ( ( MPEG::File & )file ).ID3v2Tag( hasPicture ); else if ( instanceOf( file, RIFF::AIFF::File ) ) id3v2 = ( ( RIFF::AIFF::File & )file ).tag(); if ( id3v2 ) { id3v2->removeFrames( "APIC" ); if ( hasPicture ) { ID3v2::AttachedPictureFrame *pictureFrame = new ID3v2::AttachedPictureFrame; pictureFrame->setType( ID3v2::AttachedPictureFrame::FrontCover ); pictureFrame->setMimeType( pictureMimeType.data() ); pictureFrame->setPicture( *picture ); id3v2->addFrame( pictureFrame ); } mustSave = true; } } else if ( instanceOf( file, FLAC::File ) ) { FLAC::File &flacF = ( FLAC::File & )file; flacF.removePictures(); if ( hasPicture ) { FLAC::Picture *flacPicture = new FLAC::Picture; flacPicture->setMimeType( pictureMimeType.data() ); flacPicture->setType( FLAC::Picture::FrontCover ); flacPicture->setData( *picture ); flacF.addPicture( flacPicture ); } mustSave = true; } else if ( instanceOf( file, MP4::File ) ) { MP4::ItemListMap &itemListMap = ( ( MP4::File & )file ).tag()->itemListMap(); if ( itemListMap.contains( "covr" ) ) itemListMap.erase( "covr" ); if ( hasPicture ) { MP4::CoverArt::Format format = ( MP4::CoverArt::Format )0; if ( pictureMimeType == "image/jpeg" ) format = MP4::CoverArt::JPEG; else if ( pictureMimeType == "image/png" ) format = MP4::CoverArt::PNG; #if TAGLIB18 else if ( pictureMimeType == "image/bmp" ) format = MP4::CoverArt::BMP; else if ( pictureMimeType == "image/gif" ) format = MP4::CoverArt::GIF; #endif if ( format ) { MP4::CoverArtList coverArtList; coverArtList.append( MP4::CoverArt( format, *picture ) ); itemListMap.insert( "covr", coverArtList ); } } mustSave = true; } else if ( isOgg( file ) ) { Ogg::XiphComment *xiphComment = getXiphComment( file ); if ( xiphComment ) { xiphComment->removeField( "METADATA_BLOCK_PICTURE" ); if ( hasPicture ) { FLAC::Picture flacPicture; flacPicture.setMimeType( pictureMimeType.data() ); flacPicture.setType( FLAC::Picture::FrontCover ); flacPicture.setData( *picture ); const ByteVector pict_data = flacPicture.render(); xiphComment->addField( "METADATA_BLOCK_PICTURE", QByteArray::fromRawData( pict_data.data(), pict_data.size() ).toBase64().data() ); } mustSave = true; } } } else if ( !isChecked() ) //Usuwanie wszystkich znanych tagów { mustSave = true; if ( instanceOf( file, MPEG::File ) ) ( ( MPEG::File & )file ).strip(); else if ( instanceOf( file, MPC::File ) ) ( ( MPC::File & )file ).strip(); else if ( instanceOf( file, WavPack::File ) ) ( ( WavPack::File & )file ).strip(); else if ( instanceOf( file, TrueAudio::File ) ) ( ( TrueAudio::File & )file ).strip(); else if ( instanceOf( file, APE::File ) ) ( ( APE::File & )file ).strip(); else if ( instanceOf( file, MP4::File ) ) ( ( MP4::File & )file ).tag()->itemListMap().clear(); else if ( instanceOf( file, ASF::File ) ) ( ( ASF::File & )file ).tag()->attributeListMap().clear(); else if ( isOgg( file ) ) removeXiphComment( getXiphComment( file ) ); else if ( instanceOf( file, FLAC::File ) ) { FLAC::File &flacF = ( FLAC::File & )file; flacF.removePictures(); #if TAGLIB19 if ( flacF.hasXiphComment() ) #endif removeXiphComment( flacF.xiphComment() ); } else if ( instanceOf( file, RIFF::AIFF::File ) ) { ID3v2::Tag *id3v2 = ( ( RIFF::AIFF::File & )file ).tag(); if ( id3v2 ) { ID3v2::FrameList frameList = id3v2->frameList(); for ( ID3v2::FrameList::ConstIterator it = frameList.begin() ; it != frameList.end() ; ++it ) id3v2->removeFrame( *it ); } } #if TAGLIB18 else if ( instanceOf( file, Mod::File ) || instanceOf( file, S3M::File ) || instanceOf( file, IT::File ) || instanceOf( file, XM::File ) ) { Mod::Tag *modTag = NULL; if ( instanceOf( file, Mod::File ) ) modTag = ( ( Mod::File & )file ).tag(); else if ( instanceOf( file, S3M::File ) ) modTag = ( ( S3M::File & )file ).tag(); else if ( instanceOf( file, IT::File ) ) modTag = ( ( IT::File & )file ).tag(); else if ( instanceOf( file, XM::File ) ) modTag = ( ( XM::File & )file ).tag(); if ( modTag ) modTag->setTrackerName( String::null ); } #endif } /* FLAC::File writer BUG workaround - remove ID3 tags */ if ( mustSave && instanceOf( file, FLAC::File ) ) { FLAC::File &flacF = ( FLAC::File & )file; #if TAGLIB19 if ( flacF.hasID3v1Tag() || flacF.hasID3v2Tag() ) #else if ( flacF.ID3v1Tag() || flacF.ID3v2Tag() ) #endif { const FileName fName = fRef->file()->name(); result = fRef->save(); delete fRef; fRef = NULL; if ( result ) result = MPEG::File( fName, false ).save( MPEG::File::NoTags ); mustSave = false; } } #if TAGLIB19 /* No ID3v2 in WAV, only InfoTag */ if ( mustSave && instanceOf( file, RIFF::WAV::File ) ) { RIFF::WAV::File &wavF = ( RIFF::WAV::File & )file; wavF.save( wavF.InfoTag()->isEmpty() ? RIFF::WAV::File::NoTags : RIFF::WAV::File::Info ); mustSave = false; } #endif return mustSave ? fRef->save() : ( fRef ? true : result ); } return false; }
void QMPlay_Tag::save( bool clearID3 ) { if ( dontUse ) return; using namespace TagLib; //ID3v2 { Load_MPEG_File if ( !canWriteID3 || clearID3 ) f->save( MPEG::File::NoTags ); else { ID3v2::Tag *id3v2 = f->ID3v2Tag(); if ( id3v2 ) { ID3v2::FrameList pict = id3v2->frameList( "APIC" ); while ( pict.size() ) id3v2->removeFrame( pict[ 0 ] ); if ( !picture.isEmpty() ) { ID3v2::AttachedPictureFrame *pictFrame = new ID3v2::AttachedPictureFrame; pictFrame->setPicture( picture ); QString mimeType = "image/" + QImageReader( QDataStream( QByteArray( picture.data(), picture.size() ) ).device() ).format(); pictFrame->setMimeType( mimeType.toAscii().data() ); id3v2->addFrame( pictFrame ); } f->save(); } } delete f; } if ( isFLAC ) { Load_FLAC_File if ( f->pictureList().size() ) f->removePictures(); if ( !picture.isEmpty() ) { FLAC::Picture *pict = new FLAC::Picture; pict->setData( picture ); QString mimeType = "image/" + QImageReader( QDataStream( QByteArray( picture.data(), picture.size() ) ).device() ).format(); pict->setMimeType( mimeType.toAscii().data() ); f->addPicture( pict ); } f->save(); delete f; } //General tag { Load_FileRef if ( !f->isNull() && f->tag() ) { Tag *tag = f->tag(); tag->setTitle( title ); tag->setArtist( artist ); tag->setAlbum( album ); tag->setComment( comment ); tag->setGenre( genre ); tag->setYear( year ); tag->setTrack( track ); f->save(); } delete f; } }