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