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::kValidFileExtensions(".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 }
30 
31 // static
33 {
34  QFileInfo fi(filename);
35  QString extension = fi.suffix().toLower();
36 
37  if (extension.isEmpty() || !MetaIO::kValidFileExtensions.contains(extension))
38  {
39  LOG(VB_FILE, LOG_WARNING, QString("MetaIO: unknown extension: '%1'").arg(extension));
40  return nullptr;
41  }
42 
43  if (extension == "mp3" || extension == "mp2")
44  return new MetaIOID3;
45  if (extension == "ogg" || extension == "oga")
46  return new MetaIOOggVorbis;
47  if (extension == "flac")
48  {
49  auto *tagger = new MetaIOFLACVorbis;
50  if (tagger->TagExists(filename))
51  return tagger;
52  delete tagger;
53  return new MetaIOID3;
54  }
55  if (extension == "m4a")
56  return new MetaIOMP4;
57  if (extension == "wv")
58  return new MetaIOWavPack;
59  return new MetaIOAVFComment;
60 }
61 
62 // static
64 {
65  MusicMetadata *mdata = nullptr;
67  bool ignoreID3 = (gCoreContext->GetNumSetting("Ignore_ID3", 0) == 1);
68 
69  if (tagger)
70  {
71  if (!ignoreID3)
72  mdata = tagger->read(filename);
73 
74  if (ignoreID3 || !mdata)
75  mdata = tagger->readFromFilename(filename);
76 
77  delete tagger;
78  }
79 
80  if (!mdata)
81  {
82  LOG(VB_GENERAL, LOG_ERR,
83  QString("MetaIO::readMetadata(): Could not read '%1'")
84  .arg(filename));
85  }
86 
87  return mdata;
88 }
89 
90 // static
92 {
93  //FIXME: we need a relative path for createFromFilename()
94  // but readMetadata() needs an absolute path
96  if (mdata)
97  return mdata;
98 
99  return readMetadata(filename);
100 }
101 
102 void MetaIO::readFromFilename(const QString &filename,
103  QString &artist, QString &album, QString &title,
104  QString &genre, int &tracknum)
105 {
106  QString lfilename = filename;
107  // Clear
108  artist.clear();
109  album.clear();
110  title.clear();
111  genre.clear();
112  tracknum = 0;
113 
114  int part_num = 0;
115  // Replace
116  lfilename.replace('_', ' ');
117  lfilename = lfilename.section('.', 0, -2);
118  QStringList fmt_list = m_filenameFormat.split("/");
119  QStringList::iterator fmt_it = fmt_list.begin();
120 
121  // go through loop once to get minimum part number
122  for (; fmt_it != fmt_list.end(); ++fmt_it, --part_num) {}
123 
124  // reset to go through loop for real
125  fmt_it = fmt_list.begin();
126  for(; fmt_it != fmt_list.end(); ++fmt_it, ++part_num)
127  {
128  QString part_str = lfilename.section( "/", part_num, part_num);
129 
130  if ( *fmt_it == "GENRE" )
131  genre = part_str;
132  else if ( *fmt_it == "ARTIST" )
133  artist = part_str;
134  else if ( *fmt_it == "ALBUM" )
135  album = part_str;
136  else if ( *fmt_it == "TITLE" )
137  title = part_str;
138  else if ( *fmt_it == "TRACK_TITLE" )
139  {
140  QStringList tracktitle_list = part_str.split("-");
141  if (tracktitle_list.size() > 1)
142  {
143  tracknum = tracktitle_list[0].toInt();
144  title = tracktitle_list[1].simplified();
145  }
146  else
147  title = part_str;
148  }
149  else if ( *fmt_it == "ARTIST_TITLE" )
150  {
151  QStringList artisttitle_list = part_str.split("-");
152  if (artisttitle_list.size() > 1)
153  {
154  artist = artisttitle_list[0].simplified();
155  title = artisttitle_list[1].simplified();
156  }
157  else
158  {
159  if (title.isEmpty())
160  title = part_str;
161  if (artist.isEmpty())
162  artist = part_str;
163  }
164  }
165  }
166 }
167 
168 MusicMetadata* MetaIO::readFromFilename(const QString &filename, bool blnLength)
169 {
170  QString artist;
171  QString album;
172  QString title;
173  QString genre;
174  int tracknum = 0;
175 
176  readFromFilename(filename, artist, album, title, genre, tracknum);
177 
178  int length = (blnLength) ? getTrackLength(filename) : 0;
179 
180  auto *retdata = new MusicMetadata(filename, artist, "", album, title, genre,
181  0, tracknum, length);
182 
183  return retdata;
184 }
185 
192 {
193  QString artist;
194  QString album;
195  QString title;
196  QString genre;
197  int tracknum = 0;
198 
199  const QString filename = metadata->Filename(false);
200 
201  if (filename.isEmpty())
202  return;
203 
204  readFromFilename(filename, artist, album, title, genre, tracknum);
205 
206  if (metadata->Artist().isEmpty())
207  metadata->setArtist(artist);
208 
209  if (metadata->Album().isEmpty())
210  metadata->setAlbum(album);
211 
212  if (metadata->Title().isEmpty())
213  metadata->setTitle(title);
214 
215  if (metadata->Genre().isEmpty())
216  metadata->setGenre(genre);
217 
218  if (metadata->Track() <= 0)
219  metadata->setTrack(tracknum);
220 }
221 
223 {
224  if (stat(m_filename.toLocal8Bit().constData(), &m_fileinfo) == -1)
225  {
226  LOG(VB_GENERAL, LOG_ERR,
227  QString("MetaIO::saveTimeStamps: failed to stat file: %1").arg(m_filename) + ENO);
228  }
229 }
230 
232 {
233  struct utimbuf new_times {m_fileinfo.st_atime, m_fileinfo.st_mtime};
234 
235  if (utime(m_filename.toLocal8Bit().constData(), &new_times) < 0)
236  {
237  LOG(VB_GENERAL, LOG_ERR,
238  QString("MetaIO::restoreTimeStamps: failed to utime file: %1").arg(m_filename) + ENO);
239  }
240 }
void setTrack(int ltrack)
QString Genre() const
static MetaIO * createTagger(const QString &filename)
Finds an appropriate tagger for the given file.
Definition: metaio.cpp:32
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:91
static const QString kValidFileExtensions
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:63
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:102
void saveTimeStamps(void)
Definition: metaio.cpp:222
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
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:231
void setGenre(const QString &lgenre)