22 const String
email =
"music@mythtv.org";
35 (!forWriting || !
m_file->readOnly()))
40 LOG(VB_FILE, LOG_DEBUG,
41 QString(
"MetaIO switch file: %1 New File: %2 Type: %3")
53 QString extension =
m_filename.section(
'.', -1);
55 if (extension.toLower() ==
"flac")
57 else if (extension.toLower() ==
"mp3" || extension.toLower() ==
"mp2")
67 m_file =
new TagLib::MPEG::File(fname.constData());
70 m_file =
new TagLib::FLAC::File(fname.constData());
75 if (!
m_file->isOpen() || (forWriting &&
m_file->readOnly()))
79 LOG(VB_FILE, LOG_NOTICE,
80 QString(
"Could not open file for writing: %1").arg(
m_filename));
85 QString(
"Could not open file: %1").arg(
m_filename));
101 bool retval =
m_file->save();
109 LOG(VB_FILE, LOG_DEBUG, QString(
"MetaIO Close file: %1") .arg(
m_filename));
123 auto *
file =
dynamic_cast<TagLib::MPEG::File*
>(
m_file);
124 return (
file !=
nullptr) ?
file->ID3v2Tag(create) :
nullptr;
129 auto *
file =
dynamic_cast<TagLib::FLAC::File*
>(
m_file);
130 return (
file !=
nullptr) ?
file->ID3v2Tag(create) :
nullptr;
143 auto *
file =
dynamic_cast<TagLib::MPEG::File*
>(
m_file);
144 return (
file !=
nullptr) ?
file->ID3v1Tag(create) :
nullptr;
174 UserTextIdentificationFrame *musicbrainz =
nullptr;
175 musicbrainz =
find(tag,
"MusicBrainz Album Artist Id");
182 musicbrainz =
new UserTextIdentificationFrame(TagLib::String::UTF8);
183 tag->addFrame(musicbrainz);
184 musicbrainz->setDescription(
"MusicBrainz Album Artist Id");
189 else if (musicbrainz)
190 tag->removeFrame(musicbrainz);
195 TextIdentificationFrame *tpe4frame =
nullptr;
197 if (!tpelist.isEmpty())
198 tpe4frame =
dynamic_cast<TextIdentificationFrame *
>(tpelist.front());
202 tpe4frame =
new TextIdentificationFrame(TagLib::ByteVector(
"TPE4"),
203 TagLib::String::UTF8);
204 tag->addFrame(tpe4frame);
209 TextIdentificationFrame *tpe2frame =
nullptr;
210 tpelist = tag->frameListMap()[
"TPE2"];
211 if (!tpelist.isEmpty())
212 tpe2frame =
dynamic_cast<TextIdentificationFrame *
>(tpelist.front());
216 tpe2frame =
new TextIdentificationFrame(TagLib::ByteVector(
"TPE2"),
217 TagLib::String::UTF8);
218 tag->addFrame(tpe2frame);
245 if (!tag_v1->isEmpty())
247 tag->setTitle(tag_v1->title());
248 tag->setArtist(tag_v1->artist());
249 tag->setAlbum(tag_v1->album());
250 tag->setTrack(tag_v1->track());
251 tag->setYear(tag_v1->year());
252 tag->setGenre(tag_v1->genre());
260 bool compilation =
false;
266 TextIdentificationFrame *tpeframe =
nullptr;
268 if (tpelist.isEmpty() || tpelist.front()->toString().isEmpty())
269 tpelist = tag->frameListMap()[
"TPE2"];
270 if (!tpelist.isEmpty())
271 tpeframe =
dynamic_cast<TextIdentificationFrame *
>(tpelist.front());
273 if (tpeframe && !tpeframe->toString().isEmpty())
275 QString compilation_artist = TStringToQString(tpeframe->toString())
277 metadata->setCompilationArtist(compilation_artist);
281 PopularimeterFrame *popm =
findPOPM(tag,
"");
292 if (!tag->frameListMap()[
"POPM"].isEmpty())
293 popm =
dynamic_cast<PopularimeterFrame *
>
294 (tag->frameListMap()[
"POPM"].front());
299 int rating = popm->rating();
300 rating = lroundf(
static_cast<float>(
rating) / 255.0F * 10.0F);
301 metadata->setRating(
rating);
302 metadata->setPlaycount(popm->counter());
306 UserTextIdentificationFrame *musicbrainz =
find(tag,
307 "MusicBrainz Album Artist Id");
313 if (!compilation && !musicbrainz->fieldList().isEmpty())
315 for (
auto & field : musicbrainz->fieldList())
317 QString ID = TStringToQString(field);
333 if (!tag->frameListMap()[
"TLEN"].isEmpty())
335 int length = tag->frameListMap()[
"TLEN"].front()->toString().toInt();
336 LOG(VB_FILE, LOG_DEBUG,
337 QString(
"MetaIOID3::read: Length for '%1' from tag is '%2'\n").arg(
filename).arg(length));
340 metadata->setCompilation(compilation);
345 if (!tag->frameListMap()[
"TRCK"].isEmpty())
347 QString trackFrame = TStringToQString(
348 tag->frameListMap()[
"TRCK"].front()->toString())
350 int trackCount = trackFrame.section(
'/', -1).toInt();
352 metadata->setTrackCount(trackCount);
355 LOG(VB_FILE, LOG_DEBUG,
356 QString(
"MetaIOID3::read: Length for '%1' from properties is '%2'\n")
357 .arg(
filename).arg(metadata->Length().count()));
360 UserTextIdentificationFrame *lastplayed =
find(tag,
"MythTVLastPlayed");
363 QString lastPlayStr = TStringToQString(lastplayed->toString());
368 if (!tag->frameListMap()[
"TPOS"].isEmpty())
370 QString pos = TStringToQString(
371 tag->frameListMap()[
"TPOS"].front()->toString()).trimmed();
373 int discNumber = pos.section(
'/', 0, 0).toInt();
374 int discCount = pos.section(
'/', -1).toInt();
377 metadata->setDiscNumber(discNumber);
379 metadata->setDiscCount(discCount);
394 auto *picture =
new QImage();
396 AttachedPictureFrame::Type apicType
397 = AttachedPictureFrame::FrontCover;
402 apicType = AttachedPictureFrame::Other;
405 apicType = AttachedPictureFrame::FrontCover;
408 apicType = AttachedPictureFrame::BackCover;
411 apicType = AttachedPictureFrame::Media;
414 apicType = AttachedPictureFrame::LeafletPage;
417 apicType = AttachedPictureFrame::Artist;
426 if (tag && !tag->frameListMap()[
"APIC"].isEmpty())
430 for (
auto & apicframe : apicframes)
432 auto *frame =
dynamic_cast<AttachedPictureFrame *
>(apicframe);
433 if (frame && frame->type() == apicType)
435 picture->loadFromData((
const uchar *)frame->picture().data(),
436 frame->picture().size());
481 if (!tag->frameListMap()[
"APIC"].isEmpty())
485 for (
auto & apicframe : apicframes)
487 auto *frame =
dynamic_cast<AttachedPictureFrame *
>(apicframe);
488 if (frame ==
nullptr)
490 LOG(VB_GENERAL, LOG_DEBUG,
491 "Music Scanner - Cannot convert APIC frame");
497 if (frame->picture().size() < 100)
499 LOG(VB_GENERAL, LOG_NOTICE,
500 "Music Scanner - Discarding APIC frame "
501 "with size less than 100 bytes");
507 if (frame->description().isEmpty())
508 art->m_description.clear();
510 art->m_description = TStringToQString(frame->description());
512 art->m_embedded =
true;
516 TStringToQString(frame->mimeType()).toLower());
518 switch (frame->type())
520 case AttachedPictureFrame::FrontCover :
522 art->m_filename = QString(
"front") + ext;
524 case AttachedPictureFrame::BackCover :
526 art->m_filename = QString(
"back") + ext;
528 case AttachedPictureFrame::Media :
529 art->m_imageType =
IT_CD;
530 art->m_filename = QString(
"cd") + ext;
532 case AttachedPictureFrame::LeafletPage :
534 art->m_filename = QString(
"inlay") + ext;
536 case AttachedPictureFrame::Artist :
538 art->m_filename = QString(
"artist") + ext;
540 case AttachedPictureFrame::Other :
542 art->m_filename = QString(
"unknown") + ext;
545 LOG(VB_GENERAL, LOG_ERR,
"Music Scanner - APIC tag found "
546 "with unsupported type");
560 if (mimeType ==
"image/png")
562 if (mimeType ==
"image/jpeg" || mimeType ==
"image/jpg")
564 if (mimeType ==
"image/gif")
566 if (mimeType ==
"image/bmp")
569 LOG(VB_GENERAL, LOG_ERR,
570 "Music Scanner - Unknown image mimetype found - " + mimeType);
584 AttachedPictureFrame::Type
type,
585 const String &description)
588 for (
auto & frame : l)
590 auto *f =
dynamic_cast<AttachedPictureFrame *
>(frame);
591 if (f && f->type() ==
type &&
592 (description.isEmpty() || f->description() == description))
610 if (
filename.isEmpty() || !albumart)
615 QByteArray imageData;
616 QBuffer buffer(&imageData);
617 buffer.open(QIODevice::WriteOnly);
618 image.save(&buffer,
"JPEG");
620 AttachedPictureFrame::Type
type = AttachedPictureFrame::Other;
624 type = AttachedPictureFrame::FrontCover;
627 type = AttachedPictureFrame::BackCover;
630 type = AttachedPictureFrame::Media;
633 type = AttachedPictureFrame::LeafletPage;
636 type = AttachedPictureFrame::Artist;
639 type = AttachedPictureFrame::Other;
656 apic =
new AttachedPictureFrame();
661 QString mimetype =
"image/jpeg";
663 TagLib::ByteVector bytevector;
664 bytevector.setData(imageData.data(), imageData.size());
666 apic->setMimeType(QStringToTString(mimetype));
667 apic->setPicture(bytevector);
668 apic->setDescription(QStringToTString(albumart->
m_description));
683 if (
filename.isEmpty() || !albumart)
686 AttachedPictureFrame::Type
type = AttachedPictureFrame::Other;
690 type = AttachedPictureFrame::FrontCover;
693 type = AttachedPictureFrame::BackCover;
696 type = AttachedPictureFrame::Media;
699 type = AttachedPictureFrame::LeafletPage;
702 type = AttachedPictureFrame::Artist;
705 type = AttachedPictureFrame::Other;
722 tag->removeFrame(apic);
737 AttachedPictureFrame::Type
type = AttachedPictureFrame::Other;
741 type = AttachedPictureFrame::FrontCover;
744 type = AttachedPictureFrame::BackCover;
747 type = AttachedPictureFrame::Media;
750 type = AttachedPictureFrame::LeafletPage;
753 type = AttachedPictureFrame::Artist;
756 type = AttachedPictureFrame::Other;
777 apic->setType(AttachedPictureFrame::FrontCover);
780 apic->setType(AttachedPictureFrame::BackCover);
783 apic->setType(AttachedPictureFrame::Media);
786 apic->setType(AttachedPictureFrame::LeafletPage);
789 apic->setType(AttachedPictureFrame::Artist);
792 apic->setType(AttachedPictureFrame::Other);
810 const String &description)
813 for (
auto & frame : l)
815 auto *f =
dynamic_cast<UserTextIdentificationFrame *
>(frame);
816 if (f && f->description() == description)
830 const String &_email)
833 for (
auto & frame : l)
835 auto *f =
dynamic_cast<PopularimeterFrame *
>(frame);
836 if (f && f->email() == _email)
852 popm =
new PopularimeterFrame();
854 popm->setEmail(
email);
857 int prevCount = popm->counter();
858 int countDiff = playcount - prevCount;
862 popm->setCounter(playcount);
865 PopularimeterFrame *gpopm =
findPOPM(tag,
"");
868 gpopm =
new PopularimeterFrame();
869 tag->addFrame(gpopm);
872 gpopm->setCounter((gpopm->counter() > 0) ? gpopm->counter() + countDiff : playcount);
885 QDateTime lastPlay = mdata->
LastPlay();
909 int popmrating = lroundf(
static_cast<float>(
rating) / 10.0F * 255.0F);
916 popm =
new PopularimeterFrame();
918 popm->setEmail(
email);
920 popm->setRating(popmrating);
923 PopularimeterFrame *gpopm =
findPOPM(tag,
"");
926 gpopm =
new PopularimeterFrame();
927 tag->addFrame(gpopm);
930 gpopm->setRating(popmrating);
941 UserTextIdentificationFrame *txxx =
find(tag,
"MythTVLastPlayed");
945 txxx =
new UserTextIdentificationFrame();
947 txxx->setDescription(
"MythTVLastPlayed");
949 lastPlay.setTimeSpec(Qt::UTC);
950 txxx->setText(QStringToTString(lastPlay.toString(
Qt::ISODate)));
965 if ((v2_tag && !v2_tag->isEmpty()) ||
966 (v1_tag && !v1_tag->isEmpty()))