MythTV  master
metaio.cpp
Go to the documentation of this file.
1 
2 // POSIX C headers
3 #include <utime.h>
4 
5 // Qt
6 #include <QFileInfo>
7 
8 // libmythmetadata
9 #include "metaio.h"
10 #include "musicmetadata.h"
11 #include "metaioid3.h"
12 #include "metaiooggvorbis.h"
13 #include "metaioflacvorbis.h"
14 #include "metaiomp4.h"
15 #include "metaiowavpack.h"
16 #include "metaioavfcomment.h"
17 
18 // libmythbase
21 
22 const QString MetaIO::kValidFileExtensions(".mp3|.mp2|.ogg|.oga|.flac|.wma|.wav|.ac3|.oma|.omg|"
23  ".atp|.ra|.dts|.aac|.m4a|.aa3|.tta|.mka|.aiff|.swa|.wv");
24 
26  : m_filenameFormat(gCoreContext->GetSetting("NonID3FileNameFormat").toUpper())
27 {
28 }
29 
30 // static
32 {
33  QFileInfo fi(filename);
34  QString extension = fi.suffix().toLower();
35 
36  if (extension.isEmpty() || !MetaIO::kValidFileExtensions.contains(extension))
37  {
38  LOG(VB_FILE, LOG_WARNING, QString("MetaIO: unknown extension: '%1'").arg(extension));
39  return nullptr;
40  }
41 
42  if (extension == "mp3" || extension == "mp2")
43  return new MetaIOID3;
44  if (extension == "ogg" || extension == "oga")
45  return new MetaIOOggVorbis;
46  if (extension == "flac")
47  {
48  auto *tagger = new MetaIOFLACVorbis;
49  if (tagger->TagExists(filename))
50  return tagger;
51  delete tagger;
52  return new MetaIOID3;
53  }
54  if (extension == "m4a")
55  return new MetaIOMP4;
56  if (extension == "wv")
57  return new MetaIOWavPack;
58  return new MetaIOAVFComment;
59 }
60 
61 // static
63 {
64  MusicMetadata *mdata = nullptr;
66  bool ignoreID3 = (gCoreContext->GetNumSetting("Ignore_ID3", 0) == 1);
67 
68  if (tagger)
69  {
70  if (!ignoreID3)
71  mdata = tagger->read(filename);
72 
73  if (ignoreID3 || !mdata)
74  mdata = tagger->readFromFilename(filename);
75 
76  delete tagger;
77  }
78 
79  if (!mdata)
80  {
81  LOG(VB_GENERAL, LOG_ERR,
82  QString("MetaIO::readMetadata(): Could not read '%1'")
83  .arg(filename));
84  }
85 
86  return mdata;
87 }
88 
89 // static
91 {
92  //FIXME: we need a relative path for createFromFilename()
93  // but readMetadata() needs an absolute path
95  if (mdata)
96  return mdata;
97 
98  return readMetadata(filename);
99 }
100 
101 void MetaIO::readFromFilename(const QString &filename,
102  QString &artist, QString &album, QString &title,
103  QString &genre, int &tracknum)
104 {
105  QString lfilename = filename;
106  // Clear
107  artist.clear();
108  album.clear();
109  title.clear();
110  genre.clear();
111  tracknum = 0;
112 
113  int part_num = 0;
114  // Replace
115  lfilename.replace('_', ' ');
116  lfilename = lfilename.section('.', 0, -2);
117  QStringList fmt_list = m_filenameFormat.split("/");
118  QStringList::iterator fmt_it = fmt_list.begin();
119 
120  // go through loop once to get minimum part number
121  for (; fmt_it != fmt_list.end(); ++fmt_it, --part_num) {}
122 
123  // reset to go through loop for real
124  fmt_it = fmt_list.begin();
125  for(; fmt_it != fmt_list.end(); ++fmt_it, ++part_num)
126  {
127  QString part_str = lfilename.section( "/", part_num, part_num);
128 
129  if ( *fmt_it == "GENRE" )
130  genre = part_str;
131  else if ( *fmt_it == "ARTIST" )
132  artist = part_str;
133  else if ( *fmt_it == "ALBUM" )
134  album = part_str;
135  else if ( *fmt_it == "TITLE" )
136  title = part_str;
137  else if ( *fmt_it == "TRACK_TITLE" )
138  {
139  QStringList tracktitle_list = part_str.split("-");
140  if (tracktitle_list.size() > 1)
141  {
142  tracknum = tracktitle_list[0].toInt();
143  title = tracktitle_list[1].simplified();
144  }
145  else
146  {
147  title = part_str;
148  }
149  }
150  else if ( *fmt_it == "ARTIST_TITLE" )
151  {
152  QStringList artisttitle_list = part_str.split("-");
153  if (artisttitle_list.size() > 1)
154  {
155  artist = artisttitle_list[0].simplified();
156  title = artisttitle_list[1].simplified();
157  }
158  else
159  {
160  if (title.isEmpty())
161  title = part_str;
162  if (artist.isEmpty())
163  artist = part_str;
164  }
165  }
166  }
167 }
168 
169 MusicMetadata* MetaIO::readFromFilename(const QString &filename, bool blnLength)
170 {
171  QString artist;
172  QString album;
173  QString title;
174  QString genre;
175  int tracknum = 0;
176 
177  readFromFilename(filename, artist, album, title, genre, tracknum);
178 
179  std::chrono::milliseconds length = (blnLength) ? getTrackLength(filename) : 0ms;
180 
181  auto *retdata = new MusicMetadata(filename, artist, "", album, title, genre,
182  0, tracknum, length);
183 
184  return retdata;
185 }
186 
193 {
194  QString artist;
195  QString album;
196  QString title;
197  QString genre;
198  int tracknum = 0;
199 
200  const QString filename = metadata->Filename(false);
201 
202  if (filename.isEmpty())
203  return;
204 
205  readFromFilename(filename, artist, album, title, genre, tracknum);
206 
207  if (metadata->Artist().isEmpty())
208  metadata->setArtist(artist);
209 
210  if (metadata->Album().isEmpty())
211  metadata->setAlbum(album);
212 
213  if (metadata->Title().isEmpty())
214  metadata->setTitle(title);
215 
216  if (metadata->Genre().isEmpty())
217  metadata->setGenre(genre);
218 
219  if (metadata->Track() <= 0)
220  metadata->setTrack(tracknum);
221 }
222 
224 {
225  if (stat(m_filename.toLocal8Bit().constData(), &m_fileinfo) == -1)
226  {
227  LOG(VB_GENERAL, LOG_ERR,
228  QString("MetaIO::saveTimeStamps: failed to stat file: %1").arg(m_filename) + ENO);
229  }
230 }
231 
233 {
234  struct utimbuf new_times {m_fileinfo.st_atime, m_fileinfo.st_mtime};
235 
236  if (utime(m_filename.toLocal8Bit().constData(), &new_times) < 0)
237  {
238  LOG(VB_GENERAL, LOG_ERR,
239  QString("MetaIO::restoreTimeStamps: failed to utime file: %1").arg(m_filename) + ENO);
240  }
241 }
MusicMetadata::Title
QString Title() const
Definition: musicmetadata.h:161
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:977
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
MusicMetadata::Genre
QString Genre() const
Definition: musicmetadata.h:174
MetaIO::createTagger
static MetaIO * createTagger(const QString &filename)
Finds an appropriate tagger for the given file.
Definition: metaio.cpp:31
MusicMetadata::setTrack
void setTrack(int ltrack)
Definition: musicmetadata.h:199
MetaIO
Definition: metaio.h:17
MusicMetadata::setAlbum
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
Definition: musicmetadata.h:151
MusicMetadata::Track
int Track() const
Definition: musicmetadata.h:198
MetaIO::m_filename
QString m_filename
Definition: metaio.h:168
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MusicMetadata
Definition: musicmetadata.h:80
metaioflacvorbis.h
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:125
MetaIOAVFComment
Attempt to read metadata in files without a specific metadata reading implementation.
Definition: metaioavfcomment.h:19
MetaIO::readFromFilename
void readFromFilename(const QString &filename, QString &artist, QString &album, QString &title, QString &genre, int &tracknum)
Reads MusicMetadata based on the folder/filename.
Definition: metaio.cpp:101
MetaIO::restoreTimeStamps
void restoreTimeStamps(void)
Definition: metaio.cpp:232
mythlogging.h
MetaIO::m_fileinfo
Definition: metaio.h:171
MusicMetadata::setGenre
void setGenre(const QString &lgenre)
Definition: musicmetadata.h:175
MusicMetadata::setTitle
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
Definition: musicmetadata.h:163
MetaIOOggVorbis
Read and write Vorbis (Xiph) tags in an Ogg container.
Definition: metaiooggvorbis.h:18
metaioavfcomment.h
metaiowavpack.h
MetaIO::getTrackLength
virtual std::chrono::milliseconds getTrackLength(const QString &filename)=0
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:919
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:149
MusicMetadata::setArtist
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
Definition: musicmetadata.h:127
mythcorecontext.h
metaio.h
MetaIOFLACVorbis
Read and write Vorbis (Xiph) tags in a FLAC file.
Definition: metaioflacvorbis.h:18
MetaIOMP4
Read and write metadata in MP4 container tags.
Definition: metaiomp4.h:16
metaioid3.h
metaiomp4.h
MetaIO::MetaIO
MetaIO()
Definition: metaio.cpp:25
MetaIO::read
virtual MusicMetadata * read(const QString &filename)=0
Reads MusicMetadata from a file.
MetaIO::getMetadata
static MusicMetadata * getMetadata(const QString &filename)
Get the metadata for filename.
Definition: metaio.cpp:90
MusicMetadata::createFromFilename
static MusicMetadata * createFromFilename(const QString &filename)
Definition: musicmetadata.cpp:219
build_compdb.filename
filename
Definition: build_compdb.py:21
MetaIOID3
Read and write metadata in MPEG (mp3) ID3V2 tags.
Definition: metaioid3.h:33
MetaIO::kValidFileExtensions
static const QString kValidFileExtensions
Definition: metaio.h:160
MetaIO::readMetadata
static MusicMetadata * readMetadata(const QString &filename)
Read the metadata from filename directly.
Definition: metaio.cpp:62
MetaIO::m_filenameFormat
QString m_filenameFormat
Definition: metaio.h:169
musicmetadata.h
metaiooggvorbis.h
MetaIO::saveTimeStamps
void saveTimeStamps(void)
Definition: metaio.cpp:223
MetaIOWavPack
Read and write metadata in Wavpack APE tags.
Definition: metaiowavpack.h:20