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
22const 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
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
169MusicMetadata* 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}
Attempt to read metadata in files without a specific metadata reading implementation.
Read and write Vorbis (Xiph) tags in a FLAC file.
Read and write metadata in MPEG (mp3) ID3V2 tags.
Definition: metaioid3.h:34
Read and write metadata in MP4 container tags.
Definition: metaiomp4.h:17
Read and write Vorbis (Xiph) tags in an Ogg container.
Read and write metadata in Wavpack APE tags.
Definition: metaiowavpack.h:21
Definition: metaio.h:18
void restoreTimeStamps(void)
Definition: metaio.cpp:232
static MusicMetadata * getMetadata(const QString &filename)
Get the metadata for filename.
Definition: metaio.cpp:90
virtual MusicMetadata * read(const QString &filename)=0
Reads MusicMetadata from a file.
void saveTimeStamps(void)
Definition: metaio.cpp:223
QString m_filenameFormat
Definition: metaio.h:169
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
static const QString kValidFileExtensions
Definition: metaio.h:160
MetaIO()
Definition: metaio.cpp:25
static MusicMetadata * readMetadata(const QString &filename)
Read the metadata from filename directly.
Definition: metaio.cpp:62
QString m_filename
Definition: metaio.h:168
virtual std::chrono::milliseconds getTrackLength(const QString &filename)=0
static MetaIO * createTagger(const QString &filename)
Finds an appropriate tagger for the given file.
Definition: metaio.cpp:31
static MusicMetadata * createFromFilename(const QString &filename)
void setGenre(const QString &lgenre)
QString Title() const
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
int Track() const
QString Filename(bool find=true)
QString Artist() const
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
void setTrack(int ltrack)
QString Genre() const
QString Album() const
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
int GetNumSetting(const QString &key, int defaultval=0)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39