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)
191 tag->removeFrame(musicbrainz);
197 TextIdentificationFrame *tpe4frame =
nullptr;
199 if (!tpelist.isEmpty())
200 tpe4frame =
dynamic_cast<TextIdentificationFrame *
>(tpelist.front());
204 tpe4frame =
new TextIdentificationFrame(TagLib::ByteVector(
"TPE4"),
205 TagLib::String::UTF8);
206 tag->addFrame(tpe4frame);
211 TextIdentificationFrame *tpe2frame =
nullptr;
212 tpelist = tag->frameListMap()[
"TPE2"];
213 if (!tpelist.isEmpty())
214 tpe2frame =
dynamic_cast<TextIdentificationFrame *
>(tpelist.front());
218 tpe2frame =
new TextIdentificationFrame(TagLib::ByteVector(
"TPE2"),
219 TagLib::String::UTF8);
220 tag->addFrame(tpe2frame);
247 if (!tag_v1->isEmpty())
249 tag->setTitle(tag_v1->title());
250 tag->setArtist(tag_v1->artist());
251 tag->setAlbum(tag_v1->album());
252 tag->setTrack(tag_v1->track());
253 tag->setYear(tag_v1->year());
254 tag->setGenre(tag_v1->genre());
262 bool compilation =
false;
268 TextIdentificationFrame *tpeframe =
nullptr;
270 if (tpelist.isEmpty() || tpelist.front()->toString().isEmpty())
271 tpelist = tag->frameListMap()[
"TPE2"];
272 if (!tpelist.isEmpty())
273 tpeframe =
dynamic_cast<TextIdentificationFrame *
>(tpelist.front());
275 if (tpeframe && !tpeframe->toString().isEmpty())
277 QString compilation_artist = TStringToQString(tpeframe->toString())
279 metadata->setCompilationArtist(compilation_artist);
283 PopularimeterFrame *popm =
findPOPM(tag,
"");
294 if (!tag->frameListMap()[
"POPM"].isEmpty())
295 popm =
dynamic_cast<PopularimeterFrame *
>
296 (tag->frameListMap()[
"POPM"].front());
301 int rating = popm->rating();
302 rating = lroundf(
static_cast<float>(
rating) / 255.0F * 10.0F);
303 metadata->setRating(
rating);
304 metadata->setPlaycount(popm->counter());
308 UserTextIdentificationFrame *musicbrainz =
find(tag,
309 "MusicBrainz Album Artist Id");
315 if (!compilation && !musicbrainz->fieldList().isEmpty())
317 for (
auto & field : musicbrainz->fieldList())
319 QString ID = TStringToQString(field);
335 if (!tag->frameListMap()[
"TLEN"].isEmpty())
337 int length = tag->frameListMap()[
"TLEN"].front()->toString().toInt();
338 LOG(VB_FILE, LOG_DEBUG,
339 QString(
"MetaIOID3::read: Length for '%1' from tag is '%2'\n").arg(
filename).arg(length));
342 metadata->setCompilation(compilation);
347 if (!tag->frameListMap()[
"TRCK"].isEmpty())
349 QString trackFrame = TStringToQString(
350 tag->frameListMap()[
"TRCK"].front()->toString())
352 int trackCount = trackFrame.section(
'/', -1).toInt();
354 metadata->setTrackCount(trackCount);
357 LOG(VB_FILE, LOG_DEBUG,
358 QString(
"MetaIOID3::read: Length for '%1' from properties is '%2'\n")
359 .arg(
filename).arg(metadata->Length().count()));
362 UserTextIdentificationFrame *lastplayed =
find(tag,
"MythTVLastPlayed");
365 QString lastPlayStr = TStringToQString(lastplayed->toString());
370 if (!tag->frameListMap()[
"TPOS"].isEmpty())
372 QString pos = TStringToQString(
373 tag->frameListMap()[
"TPOS"].front()->toString()).trimmed();
375 int discNumber = pos.section(
'/', 0, 0).toInt();
376 int discCount = pos.section(
'/', -1).toInt();
379 metadata->setDiscNumber(discNumber);
381 metadata->setDiscCount(discCount);
396 auto *picture =
new QImage();
398 AttachedPictureFrame::Type apicType
399 = AttachedPictureFrame::FrontCover;
404 apicType = AttachedPictureFrame::Other;
407 apicType = AttachedPictureFrame::FrontCover;
410 apicType = AttachedPictureFrame::BackCover;
413 apicType = AttachedPictureFrame::Media;
416 apicType = AttachedPictureFrame::LeafletPage;
419 apicType = AttachedPictureFrame::Artist;
428 if (tag && !tag->frameListMap()[
"APIC"].isEmpty())
432 for (
auto & apicframe : apicframes)
434 auto *frame =
dynamic_cast<AttachedPictureFrame *
>(apicframe);
435 if (frame && frame->type() == apicType)
437 picture->loadFromData((
const uchar *)frame->picture().data(),
438 frame->picture().size());
483 if (!tag->frameListMap()[
"APIC"].isEmpty())
487 for (
auto & apicframe : apicframes)
489 auto *frame =
dynamic_cast<AttachedPictureFrame *
>(apicframe);
490 if (frame ==
nullptr)
492 LOG(VB_GENERAL, LOG_DEBUG,
493 "Music Scanner - Cannot convert APIC frame");
499 if (frame->picture().size() < 100)
501 LOG(VB_GENERAL, LOG_NOTICE,
502 "Music Scanner - Discarding APIC frame "
503 "with size less than 100 bytes");
509 if (frame->description().isEmpty())
510 art->m_description.clear();
512 art->m_description = TStringToQString(frame->description());
514 art->m_embedded =
true;
518 TStringToQString(frame->mimeType()).toLower());
520 switch (frame->type())
522 case AttachedPictureFrame::FrontCover :
524 art->m_filename = QString(
"front") + ext;
526 case AttachedPictureFrame::BackCover :
528 art->m_filename = QString(
"back") + ext;
530 case AttachedPictureFrame::Media :
531 art->m_imageType =
IT_CD;
532 art->m_filename = QString(
"cd") + ext;
534 case AttachedPictureFrame::LeafletPage :
536 art->m_filename = QString(
"inlay") + ext;
538 case AttachedPictureFrame::Artist :
540 art->m_filename = QString(
"artist") + ext;
542 case AttachedPictureFrame::Other :
544 art->m_filename = QString(
"unknown") + ext;
547 LOG(VB_GENERAL, LOG_ERR,
"Music Scanner - APIC tag found "
548 "with unsupported type");
562 if (mimeType ==
"image/png")
564 if (mimeType ==
"image/jpeg" || mimeType ==
"image/jpg")
566 if (mimeType ==
"image/gif")
568 if (mimeType ==
"image/bmp")
571 LOG(VB_GENERAL, LOG_ERR,
572 "Music Scanner - Unknown image mimetype found - " + mimeType);
586 AttachedPictureFrame::Type
type,
587 const String &description)
590 for (
auto & frame : l)
592 auto *f =
dynamic_cast<AttachedPictureFrame *
>(frame);
593 if (f && f->type() ==
type &&
594 (description.isEmpty() || f->description() == description))
612 if (
filename.isEmpty() || !albumart)
617 QByteArray imageData;
618 QBuffer buffer(&imageData);
619 buffer.open(QIODevice::WriteOnly);
620 image.save(&buffer,
"JPEG");
622 AttachedPictureFrame::Type
type = AttachedPictureFrame::Other;
626 type = AttachedPictureFrame::FrontCover;
629 type = AttachedPictureFrame::BackCover;
632 type = AttachedPictureFrame::Media;
635 type = AttachedPictureFrame::LeafletPage;
638 type = AttachedPictureFrame::Artist;
641 type = AttachedPictureFrame::Other;
658 apic =
new AttachedPictureFrame();
663 QString mimetype =
"image/jpeg";
665 TagLib::ByteVector bytevector;
666 bytevector.setData(imageData.data(), imageData.size());
668 apic->setMimeType(QStringToTString(mimetype));
669 apic->setPicture(bytevector);
670 apic->setDescription(QStringToTString(albumart->
m_description));
685 if (
filename.isEmpty() || !albumart)
688 AttachedPictureFrame::Type
type = AttachedPictureFrame::Other;
692 type = AttachedPictureFrame::FrontCover;
695 type = AttachedPictureFrame::BackCover;
698 type = AttachedPictureFrame::Media;
701 type = AttachedPictureFrame::LeafletPage;
704 type = AttachedPictureFrame::Artist;
707 type = AttachedPictureFrame::Other;
724 tag->removeFrame(apic);
739 AttachedPictureFrame::Type
type = AttachedPictureFrame::Other;
743 type = AttachedPictureFrame::FrontCover;
746 type = AttachedPictureFrame::BackCover;
749 type = AttachedPictureFrame::Media;
752 type = AttachedPictureFrame::LeafletPage;
755 type = AttachedPictureFrame::Artist;
758 type = AttachedPictureFrame::Other;
779 apic->setType(AttachedPictureFrame::FrontCover);
782 apic->setType(AttachedPictureFrame::BackCover);
785 apic->setType(AttachedPictureFrame::Media);
788 apic->setType(AttachedPictureFrame::LeafletPage);
791 apic->setType(AttachedPictureFrame::Artist);
794 apic->setType(AttachedPictureFrame::Other);
812 const String &description)
815 for (
auto & frame : l)
817 auto *f =
dynamic_cast<UserTextIdentificationFrame *
>(frame);
818 if (f && f->description() == description)
832 const String &_email)
835 for (
auto & frame : l)
837 auto *f =
dynamic_cast<PopularimeterFrame *
>(frame);
838 if (f && f->email() == _email)
854 popm =
new PopularimeterFrame();
856 popm->setEmail(
email);
859 int prevCount = popm->counter();
860 int countDiff = playcount - prevCount;
864 popm->setCounter(playcount);
867 PopularimeterFrame *gpopm =
findPOPM(tag,
"");
870 gpopm =
new PopularimeterFrame();
871 tag->addFrame(gpopm);
874 gpopm->setCounter((gpopm->counter() > 0) ? gpopm->counter() + countDiff : playcount);
887 QDateTime lastPlay = mdata->
LastPlay();
911 int popmrating = lroundf(
static_cast<float>(
rating) / 10.0F * 255.0F);
918 popm =
new PopularimeterFrame();
920 popm->setEmail(
email);
922 popm->setRating(popmrating);
925 PopularimeterFrame *gpopm =
findPOPM(tag,
"");
928 gpopm =
new PopularimeterFrame();
929 tag->addFrame(gpopm);
932 gpopm->setRating(popmrating);
943 UserTextIdentificationFrame *txxx =
find(tag,
"MythTVLastPlayed");
947 txxx =
new UserTextIdentificationFrame();
949 txxx->setDescription(
"MythTVLastPlayed");
951 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
952 lastPlay.setTimeSpec(Qt::UTC);
954 lastPlay.setTimeZone(QTimeZone(QTimeZone::UTC));
956 txxx->setText(QStringToTString(lastPlay.toString(
Qt::ISODate)));
971 if ((v2_tag && !v2_tag->isEmpty()) ||
972 (v1_tag && !v1_tag->isEmpty()))