예제 #1
2
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();
}
예제 #2
0
 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());
 }
예제 #3
0
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);
}
예제 #4
0
  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());
  }
예제 #5
0
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;
}
예제 #6
0
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;
}
예제 #7
0
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;
	}
}