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