00001 #include <math.h>
00002
00003 #include "metaiotaglib.h"
00004 #include "metadata.h"
00005
00006 #include <mythtv/mythcontext.h>
00007
00008 MetaIOTagLib::MetaIOTagLib(void)
00009 : MetaIO(".mp3")
00010 {
00011 }
00012
00013 MetaIOTagLib::~MetaIOTagLib(void)
00014 {
00015 }
00016
00026 bool MetaIOTagLib::write(Metadata* mdata, bool exclusive)
00027 {
00028 (void) exclusive;
00029
00030 if (!mdata)
00031 return false;
00032
00033 File *taglib = new TagLib::MPEG::File(mdata->Filename().local8Bit());
00034
00035 Tag *tag = taglib->tag();
00036
00037 if (!tag)
00038 {
00039 if (taglib)
00040 delete taglib;
00041 return false;
00042 }
00043
00044 if (!mdata->Artist().isEmpty())
00045 tag->setArtist(QStringToTString(mdata->Artist()));
00046
00047
00048 UserTextIdentificationFrame *musicbrainz = NULL;
00049 musicbrainz = find(taglib->ID3v2Tag(), "MusicBrainz Album Artist Id");
00050
00051
00052 TextIdentificationFrame *tpeframe = NULL;
00053 TagLib::ID3v2::FrameList tpelist = taglib->ID3v2Tag()->frameListMap()["TPE4"];
00054 if (!tpelist.isEmpty())
00055 tpeframe = (TextIdentificationFrame *)tpelist.front();
00056
00057 if (mdata->Compilation())
00058 {
00059
00060 if (!musicbrainz)
00061 {
00062 musicbrainz = new UserTextIdentificationFrame(TagLib::String::UTF8);
00063 taglib->ID3v2Tag()->addFrame(musicbrainz);
00064 musicbrainz->setDescription("MusicBrainz Album Artist Id");
00065 }
00066
00067 musicbrainz->setText(MYTH_MUSICBRAINZ_ALBUMARTIST_UUID);
00068
00069 if (!mdata->CompilationArtist().isEmpty())
00070 {
00071 if (!tpeframe) {
00072 tpeframe = new TextIdentificationFrame(TagLib::ByteVector("TPE4"), TagLib::String::UTF8);
00073 taglib->ID3v2Tag()->addFrame(tpeframe);
00074 }
00075
00076 tpeframe->setText(QStringToTString(mdata->CompilationArtist()));
00077 }
00078 }
00079 else
00080 {
00081 if (tpeframe)
00082 taglib->ID3v2Tag()->removeFrame(tpeframe);
00083 if (musicbrainz)
00084 taglib->ID3v2Tag()->removeFrame(musicbrainz);
00085 }
00086
00087 if (!mdata->Title().isEmpty())
00088 tag->setTitle(QStringToTString(mdata->Title()));
00089
00090 if (!mdata->Album().isEmpty())
00091 tag->setAlbum(QStringToTString(mdata->Album()));
00092
00093 if (mdata->Year() > 999 && mdata->Year() < 10000)
00094 tag->setYear(mdata->Year());
00095
00096 if (mdata->Rating() > 0 || mdata->PlayCount() > 0)
00097 {
00098
00099
00100 }
00101
00102 if (!mdata->Genre().isEmpty())
00103 tag->setGenre(QStringToTString(mdata->Genre()));
00104
00105 if (0 != mdata->Track())
00106 tag->setTrack(mdata->Track());
00107
00108 bool result = taglib->save();
00109
00110 if (taglib)
00111 delete taglib;
00112
00113 return (result);
00114 }
00115
00116
00123 Metadata* MetaIOTagLib::read(QString filename)
00124 {
00125 QString artist = "", compilation_artist = "", album = "", title = "",
00126 genre = "";
00127 int year = 0, tracknum = 0, length = 0, playcount = 0, rating = 0, id = 0;
00128 bool compilation = false;
00129 QValueList<struct AlbumArtImage> albumart;
00130
00131 QString extension = filename.section( '.', -1 ) ;
00132
00133 File *taglib = new TagLib::MPEG::File(filename.local8Bit());
00134
00135 Tag *tag = taglib->tag();
00136
00137 if (!tag)
00138 {
00139 if (taglib)
00140 delete taglib;
00141 return NULL;
00142 }
00143
00144
00145 if (! tag->isEmpty())
00146 {
00147 title = TStringToQString(tag->title()).stripWhiteSpace();
00148 artist = TStringToQString(tag->artist()).stripWhiteSpace();
00149 album = TStringToQString(tag->album()).stripWhiteSpace();
00150 tracknum = tag->track();
00151 year = tag->year();
00152 genre = TStringToQString(tag->genre()).stripWhiteSpace();
00153 }
00154
00155
00156 if (taglib->ID3v2Tag())
00157 {
00158
00159 if(!taglib->ID3v2Tag()->frameListMap()["TPE4"].isEmpty())
00160 {
00161 compilation_artist = TStringToQString(
00162 taglib->ID3v2Tag()->frameListMap()["TPE4"].front()->toString())
00163 .stripWhiteSpace();
00164 }
00165
00166
00167 UserTextIdentificationFrame *musicbrainz = find(taglib->ID3v2Tag(),
00168 "MusicBrainz Album Artist Id");
00169
00170 if (musicbrainz)
00171 {
00172
00173
00174 if (! musicbrainz->fieldList().isEmpty())
00175 compilation = (MYTH_MUSICBRAINZ_ALBUMARTIST_UUID
00176 == TStringToQString(musicbrainz->fieldList().front()));
00177 }
00178
00179
00180 if(!taglib->ID3v2Tag()->frameListMap()["TLEN"].isEmpty())
00181 length = taglib->ID3v2Tag()->frameListMap()["TLEN"].front()->toString().toInt();
00182
00183
00184 if(!taglib->ID3v2Tag()->frameListMap()["APIC"].isEmpty())
00185 {
00186 albumart = readAlbumArt(taglib->ID3v2Tag());
00187 }
00188 }
00189
00190
00191 if (title.isEmpty())
00192 {
00193 readFromFilename(filename, artist, album, title, genre, tracknum);
00194 }
00195
00196 if (length <= 0 && taglib->audioProperties())
00197 length = taglib->audioProperties()->length() * 1000;
00198
00199 if (taglib)
00200 delete taglib;
00201
00202
00203 if (length <= 0)
00204 VERBOSE(VB_GENERAL, QString("MetaIOTagLib: Failed to read length "
00205 "from '%1'. It may be corrupt.").arg(filename));
00206
00207
00208 if (title.isEmpty() && artist.isEmpty())
00209 {
00210 VERBOSE(VB_IMPORTANT, QString("MetaIOTagLib: Failed to read metadata from '%1'")
00211 .arg(filename));
00212 return NULL;
00213 }
00214
00215 Metadata *retdata = new Metadata(filename, artist, compilation_artist, album,
00216 title, genre, year, tracknum, length,
00217 id, rating, playcount);
00218
00219 retdata->setCompilation(compilation);
00220 retdata->setEmbeddedAlbumArt(albumart);
00221
00222 return retdata;
00223 }
00224
00231 int MetaIOTagLib::getTrackLength(QString filename)
00232 {
00233 int seconds = 0;
00234 File *taglib = new TagLib::MPEG::File(filename.local8Bit());
00235
00236 if (taglib)
00237 {
00238 seconds = taglib->audioProperties()->length();
00239 delete taglib;
00240 }
00241
00242 return seconds;
00243 }
00244
00252 QImage MetaIOTagLib::getAlbumArt(QString filename, ImageType type)
00253 {
00254 QImage picture;
00255
00256 AttachedPictureFrame::Type apicType
00257 = AttachedPictureFrame::FrontCover;
00258
00259 switch (type)
00260 {
00261 case IT_UNKNOWN :
00262 apicType = AttachedPictureFrame::Other;
00263 break;
00264 case IT_FRONTCOVER :
00265 apicType = AttachedPictureFrame::FrontCover;
00266 break;
00267 case IT_BACKCOVER :
00268 apicType = AttachedPictureFrame::BackCover;
00269 break;
00270 case IT_CD :
00271 apicType = AttachedPictureFrame::Media;
00272 break;
00273 case IT_INLAY :
00274 apicType = AttachedPictureFrame::LeafletPage;
00275 break;
00276 default:
00277 return picture;
00278 }
00279
00280 File *taglib = new TagLib::MPEG::File(filename.local8Bit());
00281
00282 if (taglib)
00283 {
00284 if (taglib->isOpen()
00285 && !taglib->ID3v2Tag()->frameListMap()["APIC"].isEmpty())
00286 {
00287 TagLib::ID3v2::FrameList apicframes =
00288 taglib->ID3v2Tag()->frameListMap()["APIC"];
00289
00290 for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin();
00291 it != apicframes.end(); ++it)
00292 {
00293 AttachedPictureFrame *frame =
00294 static_cast<AttachedPictureFrame *>(*it);
00295 if(frame && frame->type() == apicType)
00296 {
00297 QImage picture;
00298 picture.loadFromData((const uchar *)frame->picture().data(),
00299 frame->picture().size());
00300 return picture;
00301 }
00302 }
00303 }
00304
00305 delete taglib;
00306 }
00307
00308 return picture;
00309 }
00310
00318 AlbumArtList MetaIOTagLib::readAlbumArt(TagLib::ID3v2::Tag *tag)
00319 {
00320
00321 QValueList<struct AlbumArtImage> artlist;
00322
00323 if (!tag->frameListMap()["APIC"].isEmpty())
00324 {
00325 TagLib::ID3v2::FrameList apicframes = tag->frameListMap()["APIC"];
00326
00327 for(TagLib::ID3v2::FrameList::Iterator it = apicframes.begin();
00328 it != apicframes.end(); ++it)
00329 {
00330
00331 AttachedPictureFrame *frame =
00332 static_cast<AttachedPictureFrame *>(*it);
00333
00334
00335
00336 if (frame->picture().size() < 100)
00337 {
00338 VERBOSE(VB_GENERAL, "Music Scanner - Discarding APIC frame "
00339 "with size less than 100 bytes");
00340 continue;
00341 }
00342
00343 AlbumArtImage art;
00344
00345 if (frame->description().isEmpty())
00346 {
00347 art.description = "";
00348 }
00349 else {
00350 art.description = TStringToQString(frame->description());
00351 }
00352
00353 art.embedded = true;
00354
00355 switch (frame->type())
00356 {
00357 case AttachedPictureFrame::FrontCover :
00358 art.imageType = IT_FRONTCOVER;
00359 break;
00360 case AttachedPictureFrame::BackCover :
00361 art.imageType = IT_BACKCOVER;
00362 break;
00363 case AttachedPictureFrame::Media :
00364 art.imageType = IT_CD;
00365 break;
00366 case AttachedPictureFrame::LeafletPage :
00367 art.imageType = IT_INLAY;
00368 break;
00369 case AttachedPictureFrame::Other :
00370 art.imageType = IT_UNKNOWN;
00371 break;
00372 default:
00373 VERBOSE(VB_GENERAL, "Music Scanner - APIC tag found "
00374 "with unsupported type");
00375 continue;
00376 }
00377
00378 artlist.append(art);
00379 }
00380 }
00381
00382 return artlist;
00383 }
00384
00395 UserTextIdentificationFrame* MetaIOTagLib::find(TagLib::ID3v2::Tag *tag,
00396 const String &description)
00397 {
00398 TagLib::ID3v2::FrameList l = tag->frameList("TXXX");
00399 for(TagLib::ID3v2::FrameList::Iterator it = l.begin(); it != l.end(); ++it)
00400 {
00401 UserTextIdentificationFrame *f =
00402 static_cast<UserTextIdentificationFrame *>(*it);
00403 if(f && f->description() == description)
00404 return f;
00405 }
00406 return 0;
00407 }