MythTV  master
musicmetautils.cpp
Go to the documentation of this file.
1 // qt
2 #include <QDir>
3 #include <QDomDocument>
4 #include <QProcess>
5 
6 // libmyth* headers
7 #include "libmyth/mythcontext.h"
10 #include "libmythbase/mythconfig.h"
11 #include "libmythbase/mythdirs.h"
14 #include "libmythmetadata/metaio.h"
18 
19 extern "C" {
20 #include <libavformat/avformat.h>
21 #include <libavcodec/avcodec.h>
22 }
23 
24 // mythutils headers
25 #include "musicmetautils.h"
27 
29 {
30  bool ok = true;
31  int result = GENERIC_EXIT_OK;
32 
33  if (cmdline.toString("songid").isEmpty())
34  {
35  LOG(VB_GENERAL, LOG_ERR, "Missing --songid option");
37  }
38  int songID = cmdline.toInt("songid");
39 
41  if (!mdata)
42  {
43  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find metadata for trackid: %1").arg(songID));
44  return GENERIC_EXIT_NOT_OK;
45  }
46 
47  if (!cmdline.toString("title").isEmpty())
48  mdata->setTitle(cmdline.toString("title"));
49 
50  if (!cmdline.toString("artist").isEmpty())
51  mdata->setArtist(cmdline.toString("artist"));
52 
53  if (!cmdline.toString("album").isEmpty())
54  mdata->setAlbum(cmdline.toString("album"));
55 
56  if (!cmdline.toString("genre").isEmpty())
57  mdata->setGenre(cmdline.toString("genre"));
58 
59  if (!cmdline.toString("trackno").isEmpty())
60  mdata->setTrack(cmdline.toInt("trackno"));
61 
62  if (!cmdline.toString("year").isEmpty())
63  mdata->setYear(cmdline.toInt("year"));
64 
65  if (!cmdline.toString("rating").isEmpty())
66  mdata->setRating(cmdline.toInt("rating"));
67 
68  if (!cmdline.toString("playcount").isEmpty())
69  mdata->setPlaycount(cmdline.toInt("playcount"));
70 
71  if (!cmdline.toString("lastplayed").isEmpty())
72  mdata->setLastPlay(cmdline.toDateTime("lastplayed"));
73 
74  mdata->dumpToDatabase();
75 
76  MetaIO *tagger = mdata->getTagger();
77  if (tagger)
78  {
79  ok = tagger->write(mdata->getLocalFilename(), mdata);
80 
81  if (!ok)
82  LOG(VB_GENERAL, LOG_ERR, QString("Failed to write to tag for trackid: %1").arg(songID));
83  }
84 
85  // tell any clients that the metadata for this track has changed
86  gCoreContext->SendMessage(QString("MUSIC_METADATA_CHANGED %1").arg(songID));
87 
88  if (!ok)
89  result = GENERIC_EXIT_NOT_OK;
90 
91  return result;
92 }
93 
95 {
96  if (cmdline.toString("songid").isEmpty())
97  {
98  LOG(VB_GENERAL, LOG_ERR, "Missing --songid option");
100  }
101 
102  if (cmdline.toString("imagetype").isEmpty())
103  {
104  LOG(VB_GENERAL, LOG_ERR, "Missing --imagetype option");
106  }
107 
108  int songID = cmdline.toInt("songid");
109  ImageType type = (ImageType)cmdline.toInt("imagetype");
110 
112  if (!mdata)
113  {
114  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find metadata for trackid: %1").arg(songID));
115  return GENERIC_EXIT_NOT_OK;
116  }
117 
118  AlbumArtImage *image = mdata->getAlbumArtImages()->getImage(type);
119  if (!image)
120  {
121  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find image of type: %1").arg(type));
122  return GENERIC_EXIT_NOT_OK;
123  }
124 
125  MetaIO *tagger = mdata->getTagger();
126  if (!tagger)
127  {
128  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find a tagger for this file: %1").arg(mdata->Filename(false)));
129  return GENERIC_EXIT_NOT_OK;
130  }
131 
132 
133  if (!image->m_embedded || !tagger->supportsEmbeddedImages())
134  {
135  LOG(VB_GENERAL, LOG_ERR, QString("Either the image isn't embedded or the tagger doesn't support embedded images"));
136  delete tagger;
137  return GENERIC_EXIT_NOT_OK;
138  }
139 
140  // find the tracks actual filename
141  StorageGroup musicGroup("Music", gCoreContext->GetHostName(), false);
142  QString trackFilename = musicGroup.FindFile(mdata->Filename(false));
143 
144  // where are we going to save the image
145  QString path;
146  StorageGroup artGroup("MusicArt", gCoreContext->GetHostName(), false);
147  QStringList dirList = artGroup.GetDirList();
148  if (!dirList.empty())
149  path = artGroup.FindNextDirMostFree();
150 
151  if (!QDir(path).exists())
152  {
153  LOG(VB_GENERAL, LOG_ERR, "Cannot find a directory in the 'MusicArt' storage group to save to");
154  delete tagger;
155  return GENERIC_EXIT_NOT_OK;
156  }
157 
158  path += "/AlbumArt/";
159  QDir dir(path);
160 
161  QString filename = QString("%1-%2.jpg").arg(mdata->ID()).arg(AlbumArtImages::getTypeFilename(image->m_imageType));
162 
163  if (QFile::exists(path + filename))
164  QFile::remove(path + filename);
165 
166  if (!dir.exists())
167  dir.mkpath(path);
168 
169  QImage *saveImage = tagger->getAlbumArt(trackFilename, image->m_imageType);
170  if (saveImage)
171  {
172  saveImage->save(path + filename, "JPEG");
173  delete saveImage;
174  }
175 
176  delete tagger;
177 
178  // tell any clients that the albumart for this track has changed
179  gCoreContext->SendMessage(QString("MUSIC_ALBUMART_CHANGED %1 %2").arg(songID).arg(type));
180 
181  return GENERIC_EXIT_OK;
182 }
183 
185 {
186  auto *fscan = new MusicFileScanner(cmdline.toBool("musicforce"));
187  QStringList dirList;
188 
189  if (!StorageGroup::FindDirs("Music", gCoreContext->GetHostName(), &dirList))
190  {
191  LOG(VB_GENERAL, LOG_ERR, "Failed to find any directories in the 'Music' storage group");
192  delete fscan;
193  return GENERIC_EXIT_NOT_OK;
194  }
195 
196  fscan->SearchDirs(dirList);
197  delete fscan;
198 
199  return GENERIC_EXIT_OK;
200 }
201 
202 static int UpdateRadioStreams(const MythUtilCommandLineParser &/*cmdline*/)
203 {
204  // check we have the correct Music Schema Version (maybe the FE hasn't been run yet)
205  if (gCoreContext->GetNumSetting("MusicDBSchemaVer", 0) < 1024)
206  {
207  LOG(VB_GENERAL, LOG_ERR, "Can't update the radio streams the DB schema hasn't been updated yet! Aborting");
208  return GENERIC_EXIT_NOT_OK;
209  }
210 
212  return GENERIC_EXIT_NOT_OK;
213 
214  return GENERIC_EXIT_OK;
215 }
216 
218 {
219  if (cmdline.toString("songid").isEmpty())
220  {
221  LOG(VB_GENERAL, LOG_ERR, "Missing --songid option");
223  }
224 
225  int songID = cmdline.toInt("songid");
226 
228  if (!mdata)
229  {
230  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find metadata for trackid: %1").arg(songID));
231  return GENERIC_EXIT_NOT_OK;
232  }
233 
234  QString musicFile = mdata->getLocalFilename();
235 
236  if (musicFile.isEmpty() || !QFile::exists(musicFile))
237  {
238  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find file for trackid: %1").arg(songID));
239  return GENERIC_EXIT_NOT_OK;
240  }
241 
242  AVFormatContext *inputFC = nullptr;
243  AVInputFormat *fmt = nullptr;
244 
245  // Open track
246  LOG(VB_GENERAL, LOG_DEBUG, QString("CalcTrackLength: Opening '%1'")
247  .arg(musicFile));
248 
249  QByteArray inFileBA = musicFile.toLocal8Bit();
250 
251  int ret = avformat_open_input(&inputFC, inFileBA.constData(), fmt, nullptr);
252 
253  if (ret)
254  {
255  LOG(VB_GENERAL, LOG_ERR, "CalcTrackLength: Couldn't open input file" +
256  ENO);
257  return GENERIC_EXIT_NOT_OK;
258  }
259 
260  // Getting stream information
261  ret = avformat_find_stream_info(inputFC, nullptr);
262 
263  if (ret < 0)
264  {
265  LOG(VB_GENERAL, LOG_ERR,
266  QString("CalcTrackLength: Couldn't get stream info, error #%1").arg(ret));
267  avformat_close_input(&inputFC);
268  inputFC = nullptr;
269  return GENERIC_EXIT_NOT_OK;;
270  }
271 
272  std::chrono::seconds duration = 0s;
273  long long time = 0;
274 
275  for (uint i = 0; i < inputFC->nb_streams; i++)
276  {
277  AVStream *st = inputFC->streams[i];
278  std::array<char,256> buf {};
279 
280  const AVCodec *pCodec = avcodec_find_decoder(st->codecpar->codec_id);
281  if (!pCodec)
282  {
283  LOG(VB_GENERAL, LOG_WARNING,
284  QString("avcodec_find_decoder fail for %1").arg(st->codecpar->codec_id));
285  continue;
286  }
287  AVCodecContext *avctx = avcodec_alloc_context3(pCodec);
288  avcodec_parameters_to_context(avctx, st->codecpar);
289  avctx->pkt_timebase = st->time_base;
290 
291  avcodec_string(buf.data(), buf.size(), avctx, static_cast<int>(false));
292 
293  switch (inputFC->streams[i]->codecpar->codec_type)
294  {
295  case AVMEDIA_TYPE_AUDIO:
296  {
297  AVPacket *pkt = av_packet_alloc();
298  if (pkt == nullptr)
299  {
300  LOG(VB_GENERAL, LOG_ERR, "packet allocation failed");
301  break;
302  }
303 
304  while (av_read_frame(inputFC, pkt) >= 0)
305  {
306  if (pkt->stream_index == (int)i)
307  time = time + pkt->duration;
308 
309  av_packet_unref(pkt);
310  }
311 
312  av_packet_free(&pkt);
313 
314  duration = secondsFromFloat(time * av_q2d(inputFC->streams[i]->time_base));
315  break;
316  }
317 
318  default:
319  LOG(VB_GENERAL, LOG_ERR,
320  QString("Skipping unsupported codec %1 on stream %2")
321  .arg(inputFC->streams[i]->codecpar->codec_type).arg(i));
322  break;
323  }
324  avcodec_free_context(&avctx);
325  }
326 
327  // Close input file
328  avformat_close_input(&inputFC);
329  inputFC = nullptr;
330 
331  std::chrono::seconds dbLength = duration_cast<std::chrono::seconds>(mdata->Length());
332  if (dbLength != duration)
333  {
334  LOG(VB_GENERAL, LOG_INFO, QString("The length of this track in the database was %1s "
335  "it is now %2s").arg(dbLength.count()).arg(duration.count()));
336 
337  // update the track length in the database
338  mdata->setLength(duration);
339  mdata->dumpToDatabase();
340 
341  // tell any clients that the metadata for this track has changed
342  gCoreContext->SendMessage(QString("MUSIC_METADATA_CHANGED %1").arg(songID));
343  }
344  else
345  {
346  LOG(VB_GENERAL, LOG_INFO, QString("The length of this track is unchanged %1s")
347  .arg(dbLength.count()));
348  }
349 
350  return GENERIC_EXIT_OK;
351 }
352 
354 {
355 public:
356  QString m_name;
357  QString m_filename;
358  int m_priority {99};
359 };
360 
362 {
363  // make sure our lyrics cache directory exists
364  QString lyricsDir = GetConfDir() + "/MythMusic/Lyrics/";
365  QDir dir(lyricsDir);
366  if (!dir.exists())
367  dir.mkpath(lyricsDir);
368 
369  if (cmdline.toString("songid").isEmpty())
370  {
371  LOG(VB_GENERAL, LOG_ERR, "Missing --songid option");
373  }
374 
375  int songID = cmdline.toInt("songid");
376  QString grabberName = "ALL";
377  QString lyricsFile;
378  QString artist;
379  QString album;
380  QString title;
381  QString filename;
382 
383  if (!cmdline.toString("grabber").isEmpty())
384  grabberName = cmdline.toString("grabber");
385 
386  if (ID_TO_REPO(songID) == RT_Database)
387  {
389  if (!mdata)
390  {
391  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find metadata for trackid: %1").arg(songID));
392  return GENERIC_EXIT_NOT_OK;
393  }
394 
395  QString musicFile = mdata->getLocalFilename();
396 
397  if (musicFile.isEmpty() || !QFile::exists(musicFile))
398  {
399  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find file for trackid: %1").arg(songID));
400  //return GENERIC_EXIT_NOT_OK;
401  }
402 
403  // first check if we have already saved a lyrics file for this track
404  lyricsFile = GetConfDir() + QString("/MythMusic/Lyrics/%1.txt").arg(songID);
405  if (QFile::exists(lyricsFile))
406  {
407  // if the user specified a specific grabber assume they want to
408  // re-search for the lyrics using the given grabber
409  if (grabberName != "ALL")
410  QFile::remove(lyricsFile);
411  else
412  {
413  // load these lyrics to speed up future lookups
414  QFile file(QLatin1String(qPrintable(lyricsFile)));
415  QString lyrics;
416 
417  if (file.open(QIODevice::ReadOnly))
418  {
419  QTextStream stream(&file);
420 
421  while (!stream.atEnd())
422  {
423  lyrics.append(stream.readLine());
424  }
425 
426  file.close();
427  }
428 
429  // tell any clients that a lyrics file is available for this track
430  gCoreContext->SendMessage(QString("MUSIC_LYRICS_FOUND %1 %2").arg(songID).arg(lyrics));
431 
432  return GENERIC_EXIT_OK;
433  }
434  }
435 
436  artist = mdata->Artist();
437  album = mdata->Album();
438  title = mdata->Title();
439  filename = mdata->getLocalFilename();
440  }
441  else
442  {
443  // must be a CD or Radio Track
444  if (cmdline.toString("artist").isEmpty())
445  {
446  LOG(VB_GENERAL, LOG_ERR, "Missing --artist option");
448  }
449  artist = cmdline.toString("artist");
450 
451  if (cmdline.toString("album").isEmpty())
452  {
453  LOG(VB_GENERAL, LOG_ERR, "Missing --album option");
455  }
456  album = cmdline.toString("album");
457 
458  if (cmdline.toString("title").isEmpty())
459  {
460  LOG(VB_GENERAL, LOG_ERR, "Missing --title option");
462  }
463  title = cmdline.toString("title");
464  }
465 
466  // not found so try the grabbers
467  // first get a list of available grabbers
468  QString scriptDir = GetShareDir() + "metadata/Music/lyrics";
469  QDir d(scriptDir);
470 
471  if (!d.exists())
472  {
473  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find lyric scripts directory: %1").arg(scriptDir));
474  gCoreContext->SendMessage(QString("MUSIC_LYRICS_ERROR NO_SCRIPTS_DIR"));
475  return GENERIC_EXIT_NOT_OK;
476  }
477 
478  d.setFilter(QDir::Files | QDir::NoDotAndDotDot);
479  d.setNameFilters(QStringList("*.py"));
480  QFileInfoList list = d.entryInfoList();
481  if (list.isEmpty())
482  {
483  LOG(VB_GENERAL, LOG_ERR, QString("Cannot find any lyric scripts in: %1").arg(scriptDir));
484  gCoreContext->SendMessage(QString("MUSIC_LYRICS_ERROR NO_SCRIPTS_FOUND"));
485  return GENERIC_EXIT_NOT_OK;
486  }
487 
488  QStringList scripts;
489 
490  for (const auto& fi : std::as_const(list))
491  {
492  LOG(VB_GENERAL, LOG_NOTICE, QString("Found lyric script at: %1").arg(fi.filePath()));
493  scripts.append(fi.filePath());
494  }
495 
496  QMap<int, LyricsGrabber> grabberMap;
497 
498  // query the grabbers to get their priority
499  for (int x = 0; x < scripts.count(); x++)
500  {
501  QStringList args { scripts.at(x), "-v" };
502  QProcess p;
503  p.start(PYTHON_EXE, args);
504  p.waitForFinished(-1);
505  QString result = p.readAllStandardOutput();
506 
507  QDomDocument domDoc;
508  QString errorMsg;
509  int errorLine = 0;
510  int errorColumn = 0;
511 
512  if (!domDoc.setContent(result, false, &errorMsg, &errorLine, &errorColumn))
513  {
514  LOG(VB_GENERAL, LOG_ERR,
515  QString("FindLyrics: Could not parse version from %1").arg(scripts.at(x)) +
516  QString("\n\t\t\tError at line: %1 column: %2 msg: %3").arg(errorLine).arg(errorColumn).arg(errorMsg));
517  continue;
518  }
519 
520  QDomNodeList itemList = domDoc.elementsByTagName("grabber");
521  QDomNode itemNode = itemList.item(0);
522 
523  LyricsGrabber grabber;
524  grabber.m_name = itemNode.namedItem(QString("name")).toElement().text();
525  grabber.m_priority = itemNode.namedItem(QString("priority")).toElement().text().toInt();
526  grabber.m_filename = scripts.at(x);
527 
528  grabberMap.insert(grabber.m_priority, grabber);
529  }
530 
531  // try each grabber in turn until we find a match
532  QMap<int, LyricsGrabber>::const_iterator i = grabberMap.constBegin();
533  while (i != grabberMap.constEnd())
534  {
535  LyricsGrabber grabber = i.value();
536 
537  ++i;
538 
539  if (grabberName != "ALL" && grabberName != grabber.m_name)
540  continue;
541 
542  LOG(VB_GENERAL, LOG_NOTICE, QString("Trying grabber: %1, Priority: %2").arg(grabber.m_name).arg(grabber.m_priority));
543  QString statusMessage = QObject::tr("Searching '%1' for lyrics...").arg(grabber.m_name);
544  gCoreContext->SendMessage(QString("MUSIC_LYRICS_STATUS %1 %2").arg(songID).arg(statusMessage));
545 
546  QProcess p;
547  QStringList args { grabber.m_filename,
548  QString("--artist=%1").arg(artist),
549  QString("--album=%1").arg(album),
550  QString("--title=%1").arg(title),
551  QString("--filename=%1").arg(filename) };
552  p.start(PYTHON_EXE, args);
553  p.waitForFinished(-1);
554  QString result = p.readAllStandardOutput();
555 
556  LOG(VB_GENERAL, LOG_DEBUG, QString("Grabber: %1, Exited with code: %2").arg(grabber.m_name).arg(p.exitCode()));
557 
558  if (p.exitCode() == 0)
559  {
560  LOG(VB_GENERAL, LOG_NOTICE, QString("Lyrics Found using: %1").arg(grabber.m_name));
561 
562  // save these lyrics to speed up future lookups if it is a DB track
563  if (ID_TO_REPO(songID) == RT_Database)
564  {
565  QFile file(QLatin1String(qPrintable(lyricsFile)));
566 
567  if (file.open(QIODevice::WriteOnly))
568  {
569  QTextStream stream(&file);
570  stream << result;
571  file.close();
572  }
573  }
574 
575  gCoreContext->SendMessage(QString("MUSIC_LYRICS_FOUND %1 %2").arg(songID).arg(result));
576  return GENERIC_EXIT_OK;
577  }
578  }
579 
580  // if we got here we didn't find any lyrics
581  gCoreContext->SendMessage(QString("MUSIC_LYRICS_NOTFOUND %1").arg(songID));
582 
583  return GENERIC_EXIT_OK;
584 }
585 
587 {
588  utilMap["updatemeta"] = &UpdateMeta;
589  utilMap["extractimage"] = &ExtractImage;
590  utilMap["scanmusic"] = &ScanMusic;
591  utilMap["updateradiostreams"] = &UpdateRadioStreams;
592  utilMap["calctracklen"] = &CalcTrackLength;
593  utilMap["findlyrics"] = &FindLyrics;
594 }
UpdateRadioStreams
static int UpdateRadioStreams(const MythUtilCommandLineParser &)
Definition: musicmetautils.cpp:202
build_compdb.args
args
Definition: build_compdb.py:11
secondsFromFloat
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::seconds > secondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:80
MusicMetadata::Title
QString Title() const
Definition: musicmetadata.h:161
UpdateMeta
static int UpdateMeta(const MythUtilCommandLineParser &cmdline)
Definition: musicmetautils.cpp:28
MythCoreContext::SendMessage
void SendMessage(const QString &message)
Definition: mythcorecontext.cpp:1525
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:962
AlbumArtImage::m_imageType
ImageType m_imageType
Definition: musicmetadata.h:51
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:73
MusicMetadata::getAlbumArtImages
AlbumArtImages * getAlbumArtImages(void)
Definition: musicmetadata.cpp:1368
cmdline
MythCommFlagCommandLineParser cmdline
Definition: mythcommflag.cpp:72
MusicMetadata::createFromID
static MusicMetadata * createFromID(int trackid)
Definition: musicmetadata.cpp:255
MetaIO::write
virtual bool write(const QString &filename, MusicMetadata *mdata)=0
Writes all metadata back to a file.
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:597
musicmetautils.h
MusicMetadata::setTrack
void setTrack(int ltrack)
Definition: musicmetadata.h:199
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
MetaIO
Definition: metaio.h:17
MusicMetadata::ID
IdType ID() const
Definition: musicmetadata.h:217
MusicMetadata::setAlbum
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
Definition: musicmetadata.h:151
MusicMetadata::setRating
void setRating(int lrating)
Definition: musicmetadata.h:241
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MusicMetadata
Definition: musicmetadata.h:80
MusicMetadata::Length
std::chrono::milliseconds Length() const
Definition: musicmetadata.h:204
build_compdb.file
file
Definition: build_compdb.py:55
mythdirs.h
MusicMetadata::getLocalFilename
QString getLocalFilename(void)
try to find the track on the local file system
Definition: musicmetadata.cpp:1023
MythUtilCommandLineParser
Definition: mythutil_commandlineparser.h:8
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:125
ScanMusic
static int ScanMusic(const MythUtilCommandLineParser &cmdline)
Definition: musicmetautils.cpp:184
musicutils.h
AlbumArtImages::getImage
AlbumArtImage * getImage(ImageType type)
Definition: musicmetadata.cpp:2119
ID_TO_REPO
static constexpr uint32_t ID_TO_REPO(uint32_t x)
Definition: musicmetadata.h:71
musicfilescanner.h
MetaIO::supportsEmbeddedImages
virtual bool supportsEmbeddedImages(void)
Does the tag support embedded cover art.
Definition: metaio.h:58
GENERIC_EXIT_INVALID_CMDLINE
@ GENERIC_EXIT_INVALID_CMDLINE
Command line parse error.
Definition: exitcodes.h:18
mythlogging.h
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:256
StorageGroup::FindDirs
static bool FindDirs(const QString &group="Default", const QString &hostname="", QStringList *dirlist=nullptr)
Finds and and optionally initialize a directory list associated with a Storage Group.
Definition: storagegroup.cpp:532
MusicMetadata::setLength
void setLength(T llength)
Definition: musicmetadata.h:206
hardwareprofile.config.p
p
Definition: config.py:33
GENERIC_EXIT_OK
@ GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:13
mythutil_commandlineparser.h
MusicMetadata::setGenre
void setGenre(const QString &lgenre)
Definition: musicmetadata.h:175
GetShareDir
QString GetShareDir(void)
Definition: mythdirs.cpp:254
LyricsGrabber::m_priority
int m_priority
Definition: musicmetautils.cpp:358
MetaIO::getAlbumArt
virtual QImage * getAlbumArt([[maybe_unused]] const QString &filename, [[maybe_unused]] ImageType type)
Definition: metaio.h:93
MusicMetadata::setTitle
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
Definition: musicmetadata.h:163
MusicMetadata::updateStreamList
static bool updateStreamList(void)
Definition: musicmetadata.cpp:316
ExtractImage
static int ExtractImage(const MythUtilCommandLineParser &cmdline)
Definition: musicmetautils.cpp:94
AlbumArtImages::getTypeFilename
static QString getTypeFilename(ImageType type)
Definition: musicmetadata.cpp:2177
storagegroup.h
StorageGroup::GetDirList
QStringList GetDirList(void) const
Definition: storagegroup.h:23
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
MusicFileScanner
Definition: musicfilescanner.h:12
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:916
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:149
RT_Database
@ RT_Database
Definition: musicmetadata.h:60
LyricsGrabber::m_name
QString m_name
Definition: musicmetautils.cpp:356
MusicMetadata::dumpToDatabase
void dumpToDatabase(void)
Definition: musicmetadata.cpp:668
FindLyrics
static int FindLyrics(const MythUtilCommandLineParser &cmdline)
Definition: musicmetautils.cpp:361
MusicMetadata::setArtist
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
Definition: musicmetadata.h:127
UtilMap
QMap< QString, UtilFunc > UtilMap
Definition: mythutil.h:15
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2354
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2197
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:666
metaio.h
AlbumArtImage
Definition: musicmetadata.h:39
mythcontext.h
mythchrono.h
StorageGroup
Definition: storagegroup.h:11
GENERIC_EXIT_NOT_OK
@ GENERIC_EXIT_NOT_OK
Exited with error.
Definition: exitcodes.h:14
MusicMetadata::setPlaycount
void setPlaycount(int lplaycount)
Definition: musicmetadata.h:215
MusicMetadata::setLastPlay
void setLastPlay()
Definition: musicmetadata.cpp:1192
MusicMetadata::setYear
void setYear(int lyear)
Definition: musicmetadata.h:196
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:842
registerMusicUtils
void registerMusicUtils(UtilMap &utilMap)
Definition: musicmetautils.cpp:586
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
exitcodes.h
MythCommandLineParser::toInt
int toInt(const QString &key) const
Returns stored QVariant as an integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2219
build_compdb.filename
filename
Definition: build_compdb.py:21
ImageType
ImageType
Definition: musicmetadata.h:28
MusicMetadata::getTagger
MetaIO * getTagger(void)
Definition: musicmetadata.cpp:1392
MythCommandLineParser::toDateTime
QDateTime toDateTime(const QString &key) const
Returns stored QVariant as a QDateTime, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2453
CalcTrackLength
static int CalcTrackLength(const MythUtilCommandLineParser &cmdline)
Definition: musicmetautils.cpp:217
musicmetadata.h
LyricsGrabber
Definition: musicmetautils.cpp:353
LyricsGrabber::m_filename
QString m_filename
Definition: musicmetautils.cpp:357
AlbumArtImage::m_embedded
bool m_embedded
Definition: musicmetadata.h:53