UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static { ID3v2::FrameList lyrics = tag->frameList("USLT"); for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){ UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it); if(frame && frame->description() == d) return frame; } return 0; }
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static { ID3v2::FrameList comments = tag->frameList("COMM"); for(ID3v2::FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it); if(frame && frame->description() == d) return frame; } return 0; }
ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static { ID3v2::FrameList comments = tag->frameList("CHAP"); for(ID3v2::FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it); if(frame && frame->elementID() == eID) return frame; } return 0; }
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static { ID3v2::FrameList tablesOfContents = tag->frameList("CTOC"); for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin(); it != tablesOfContents.end(); ++it) { TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it); if(frame && frame->isTopLevel() == true) return frame; } return 0; }
UniqueFileIdentifierFrame *UniqueFileIdentifierFrame::findByOwner(const ID3v2::Tag *tag, const String &o) // static { ID3v2::FrameList comments = tag->frameList("UFID"); for(ID3v2::FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) { UniqueFileIdentifierFrame *frame = dynamic_cast<UniqueFileIdentifierFrame *>(*it); if(frame && frame->owner() == o) return frame; } return 0; }
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static { ID3v2::FrameList tablesOfContents = tag->frameList("CTOC"); for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin(); it != tablesOfContents.end(); ++it) { TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it); if(frame && frame->elementID() == eID) return frame; } return 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; }
/** * Read meta information from id3v2 tags * @param tag: the id3v2 tag * @param p_demux; the demux object * @param p_demux_meta: the demuxer meta * @param p_meta: the meta */ static void ReadMetaFromId3v2( ID3v2::Tag* tag, demux_t* p_demux, demux_meta_t* p_demux_meta, vlc_meta_t* p_meta ) { // Get the unique file identifier ID3v2::FrameList list = tag->frameListMap()["UFID"]; ID3v2::FrameList::Iterator iter; for( iter = list.begin(); iter != list.end(); iter++ ) { ID3v2::UniqueFileIdentifierFrame* p_ufid = dynamic_cast<ID3v2::UniqueFileIdentifierFrame*>(*iter); const char *owner = p_ufid->owner().toCString(); if (!strcmp( owner, "http://musicbrainz.org" )) { /* ID3v2 UFID contains up to 64 bytes binary data * but in our case it will be a '\0' * terminated string */ char psz_ufid[64]; int max_size = __MIN( p_ufid->identifier().size(), 63); strncpy( psz_ufid, p_ufid->identifier().data(), max_size ); psz_ufid[max_size] = '\0'; vlc_meta_SetTrackID( p_meta, psz_ufid ); } } // Get the use text list = tag->frameListMap()["TXXX"]; for( iter = list.begin(); iter != list.end(); iter++ ) { ID3v2::UserTextIdentificationFrame* p_txxx = dynamic_cast<ID3v2::UserTextIdentificationFrame*>(*iter); vlc_meta_AddExtra( p_meta, p_txxx->description().toCString( true ), p_txxx->fieldList().toString().toCString( true ) ); } // Get some more informations #define SET( tagName, metaName ) \ list = tag->frameListMap()[tagName]; \ if( !list.isEmpty() ) \ vlc_meta_Set##metaName( p_meta, \ (*list.begin())->toString().toCString( true ) ); SET( "TCOP", Copyright ); SET( "TENC", EncodedBy ); SET( "TLAN", Language ); SET( "TPUB", Publisher ); #undef SET /* Preferred type of image * The 21 types are defined in id3v2 standard: * http://www.id3.org/id3v2.4.0-frames */ static const int pi_cover_score[] = { 0, /* Other */ 5, /* 32x32 PNG image that should be used as the file icon */ 4, /* File icon of a different size or format. */ 20, /* Front cover image of the album. */ 19, /* Back cover image of the album. */ 13, /* Inside leaflet page of the album. */ 18, /* Image from the album itself. */ 17, /* Picture of the lead artist or soloist. */ 16, /* Picture of the artist or performer. */ 14, /* Picture of the conductor. */ 15, /* Picture of the band or orchestra. */ 9, /* Picture of the composer. */ 8, /* Picture of the lyricist or text writer. */ 7, /* Picture of the recording location or studio. */ 10, /* Picture of the artists during recording. */ 11, /* Picture of the artists during performance. */ 6, /* Picture from a movie or video related to the track. */ 1, /* Picture of a large, coloured fish. */ 12, /* Illustration related to the track. */ 3, /* Logo of the band or performer. */ 2 /* Logo of the publisher (record company). */ }; int i_score = -1; // Try now to get embedded art list = tag->frameListMap()[ "APIC" ]; if( list.isEmpty() ) return; TAB_INIT( p_demux_meta->i_attachments, p_demux_meta->attachments ); for( iter = list.begin(); iter != list.end(); iter++ ) { ID3v2::AttachedPictureFrame* p_apic = dynamic_cast<ID3v2::AttachedPictureFrame*>(*iter); input_attachment_t *p_attachment; const char *psz_mime; char *psz_name, *psz_description; // Get the mime and description of the image. // If the description is empty, take the type as a description psz_mime = p_apic->mimeType().toCString( true ); if( p_apic->description().size() > 0 ) psz_description = strdup( p_apic->description().toCString( true ) ); else { if( asprintf( &psz_description, "%i", p_apic->type() ) == -1 ) psz_description = NULL; } if( !psz_description ) continue; psz_name = psz_description; /* some old iTunes version not only sets incorrectly the mime type * or the description of the image, * but also embeds incorrectly the image. * Recent versions seem to behave correctly */ if( !strncmp( psz_mime, "PNG", 3 ) || !strncmp( psz_name, "\xC2\x89PNG", 5 ) ) { msg_Warn( p_demux, "Invalid picture embedded by broken iTunes version" ); free( psz_description ); continue; } const ByteVector picture = p_apic->picture(); const char *p_data = picture.data(); const unsigned i_data = picture.size(); msg_Dbg( p_demux, "Found embedded art: %s (%s) is %u bytes", psz_name, psz_mime, i_data ); p_attachment = vlc_input_attachment_New( psz_name, psz_mime, psz_description, p_data, i_data ); if( p_attachment ) TAB_APPEND_CAST( (input_attachment_t**), p_demux_meta->i_attachments, p_demux_meta->attachments, p_attachment ); free( psz_description ); if( pi_cover_score[p_apic->type()] > i_score ) { i_score = pi_cover_score[p_apic->type()]; char *psz_url; if( asprintf( &psz_url, "attachment://%s", p_attachment->psz_name ) == -1 ) continue; vlc_meta_SetArtURL( p_meta, psz_url ); free( psz_url ); } } }