MythTV  master
musicmetadata.cpp
Go to the documentation of this file.
1 
2 #include "musicmetadata.h"
3 
4 // qt
5 #include <QApplication>
6 #include <QDateTime>
7 #include <QDir>
8 #include <QDomDocument>
9 #include <QRegExp>
10 #include <QScopedPointer>
11 #include <utility>
12 
13 // mythtv
14 #include "mythcontext.h"
15 #include "mythdate.h"
16 #include "mythdb.h"
17 #include "mythdirs.h"
18 #include "mythdownloadmanager.h"
19 #include "mythlogging.h"
20 #include "mythdate.h"
21 #include "remotefile.h"
22 #include "storagegroup.h"
23 #include "mythsystem.h"
24 #include "mythcoreutil.h"
25 #include "mythmiscutil.h"
26 
27 // mythbase
28 #include "mythsorthelper.h"
29 
30 // libmythui
31 #include "mythprogressdialog.h"
32 #include "mythmainwindow.h"
33 
34 // libmythmetadata
35 #include "metaio.h"
36 #include "metaioid3.h"
37 #include "metaiomp4.h"
38 #include "metaioavfcomment.h"
39 #include "metaiooggvorbis.h"
40 #include "metaioflacvorbis.h"
41 #include "metaiowavpack.h"
42 #include "musicutils.h"
43 #include "lyricsdata.h"
44 
45 using namespace std;
46 
47 static QString thePrefix = "the ";
48 
50 {
51  return a.Filename() == b.Filename();
52 }
53 
55 {
56  return a.Filename() != b.Filename();
57 }
58 
59 // this ctor is for radio streams
60 MusicMetadata::MusicMetadata(int lid, QString lbroadcaster, QString lchannel, QString ldescription,
61  UrlList lurls, QString llogourl, QString lgenre, QString lmetaformat,
62  QString lcountry, QString llanguage, QString lformat)
63  : m_genre(std::move(lgenre)),
64  m_format(std::move(lformat)),
65  m_id(lid),
66  m_filename(lurls[0]),
67  m_broadcaster(std::move(lbroadcaster)),
68  m_channel(std::move(lchannel)),
69  m_description(std::move(ldescription)),
70  m_logoUrl(std::move(llogourl)),
71  m_metaFormat(std::move(lmetaformat)),
72  m_country(std::move(lcountry)),
73  m_language(std::move(llanguage))
74 {
75  for (int x = 0; x < STREAMURLCOUNT; x++)
76  m_urls[x] = lurls[x];
77 
80 }
81 
83 {
84  if (m_albumArt)
85  {
86  delete m_albumArt;
87  m_albumArt = nullptr;
88  }
89 
90  if (m_lyricsData)
91  {
92  delete m_lyricsData;
93  m_lyricsData = nullptr;
94  }
95 }
96 
97 
99 {
100  if (this == &rhs)
101  return *this;
102 
103  m_artist = rhs.m_artist;
107  m_album = rhs.m_album;
108  m_albumSort = rhs.m_albumSort;
109  m_title = rhs.m_title;
110  m_titleSort = rhs.m_titleSort;
113  m_genre = rhs.m_genre;
114  m_year = rhs.m_year;
115  m_trackNum = rhs.m_trackNum;
117  m_discNum = rhs.m_discNum;
118  m_discCount = rhs.m_discCount;
119  m_length = rhs.m_length;
120  m_rating = rhs.m_rating;
121  m_lastPlay = rhs.m_lastPlay;
123  m_dateAdded = rhs.m_dateAdded;
124  m_playCount = rhs.m_playCount;
127  m_id = rhs.m_id;
128  m_filename = rhs.m_filename;
130  m_hostname = rhs.m_hostname;
132  m_artistId = rhs.m_artistId;
134  m_albumId = rhs.m_albumId;
135  m_genreId = rhs.m_genreId;
136  m_albumArt = nullptr;
137  m_lyricsData = nullptr;
138  m_format = rhs.m_format;
139  m_changed = rhs.m_changed;
140  m_fileSize = rhs.m_fileSize;
142  m_channel = rhs.m_channel;
144 
145  for (int x = 0; x < 5; x++)
146  m_urls[x] = rhs.m_urls[x];
147  m_logoUrl = rhs.m_logoUrl;
149  m_country = rhs.m_country;
150  m_language = rhs.m_language;
151 
152  return *this;
153 }
154 
155 // return true if this == mdata
157 {
158  return (
159  m_artist == mdata->m_artist &&
161  m_album == mdata->m_album &&
162  m_title == mdata->m_title &&
163  m_year == mdata->m_year &&
164  m_trackNum == mdata->m_trackNum &&
165  m_trackCount == mdata->m_trackCount &&
166  m_discNum == mdata->m_discNum &&
167  m_discCount == mdata->m_discCount &&
168  //m_length == mdata->m_length &&
169  m_rating == mdata->m_rating &&
170  m_lastPlay == mdata->m_lastPlay &&
171  m_playCount == mdata->m_playCount &&
172  m_compilation == mdata->m_compilation &&
173  m_filename == mdata->m_filename &&
174  m_directoryId == mdata->m_directoryId &&
175  m_artistId == mdata->m_artistId &&
176  m_compartistId == mdata->m_compartistId &&
177  m_albumId == mdata->m_albumId &&
178  m_genreId == mdata->m_genreId &&
179  m_format == mdata->m_format &&
180  m_fileSize == mdata->m_fileSize
181  );
182 }
183 
185 {
186  if (m_id < 1)
187  return;
188 
189  if (m_tempLastPlay.isValid())
190  {
193 
194  m_tempLastPlay = QDateTime();
195  }
196 
198  query.prepare("UPDATE music_songs set rating = :RATING , "
199  "numplays = :PLAYCOUNT , lastplay = :LASTPLAY "
200  "where song_id = :ID ;");
201  query.bindValue(":RATING", m_rating);
202  query.bindValue(":PLAYCOUNT", m_playCount);
203  query.bindValue(":LASTPLAY", m_lastPlay);
204  query.bindValue(":ID", m_id);
205 
206  if (!query.exec())
207  MythDB::DBError("music persist", query);
208 
209  m_changed = false;
210 }
211 
213 {
214  if (m_id < 1)
215  return;
216 
218  query.prepare("UPDATE music_songs SET hostname = :HOSTNAME "
219  "WHERE song_id = :ID ;");
220  query.bindValue(":HOSTNAME", m_hostname);
221  query.bindValue(":ID", m_id);
222 
223  if (!query.exec())
224  MythDB::DBError("music save hostname", query);
225 }
226 
227 // static
229 {
230  // find the trackid for this filename
231  QString sqldir = filename.section('/', 0, -2);
232 
233  QString sqlfilename = filename.section('/', -1);
234 
236  query.prepare(
237  "SELECT song_id FROM music_songs "
238  "LEFT JOIN music_directories ON music_songs.directory_id=music_directories.directory_id "
239  "WHERE music_songs.filename = :FILENAME "
240  "AND music_directories.path = :DIRECTORY ;");
241  query.bindValue(":FILENAME", sqlfilename);
242  query.bindValue(":DIRECTORY", sqldir);
243 
244  if (!query.exec())
245  {
246  MythDB::DBError("MusicMetadata::createFromFilename", query);
247  return nullptr;
248  }
249 
250  if (!query.next())
251  {
252  LOG(VB_GENERAL, LOG_WARNING,
253  QString("MusicMetadata::createFromFilename: Could not find '%1'")
254  .arg(filename));
255  return nullptr;
256  }
257 
258  int songID = query.value(0).toInt();
259 
260  return MusicMetadata::createFromID(songID);
261 }
262 
263 // static
265 {
267  query.prepare("SELECT music_artists.artist_name, "
268  "music_comp_artists.artist_name AS compilation_artist, "
269  "music_albums.album_name, music_songs.name, music_genres.genre, "
270  "music_songs.year, music_songs.track, music_songs.length, "
271  "music_songs.song_id, music_songs.rating, music_songs.numplays, "
272  "music_songs.lastplay, music_albums.compilation, music_songs.format, "
273  "music_songs.track_count, music_songs.size, music_songs.date_entered, "
274  "music_songs.disc_number, music_songs.disc_count, "
275  "CONCAT_WS('/', music_directories.path, music_songs.filename) AS filename, "
276  "music_songs.hostname "
277  "FROM music_songs "
278  "LEFT JOIN music_directories ON music_songs.directory_id=music_directories.directory_id "
279  "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
280  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
281  "LEFT JOIN music_artists AS music_comp_artists ON music_albums.artist_id=music_comp_artists.artist_id "
282  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
283  "WHERE music_songs.song_id = :SONGID; ");
284  query.bindValue(":SONGID", trackid);
285 
286  if (query.exec() && query.next())
287  {
288  auto *mdata = new MusicMetadata();
289  mdata->m_artist = query.value(0).toString();
290  mdata->m_compilationArtist = query.value(1).toString();
291  mdata->m_album = query.value(2).toString();
292  mdata->m_title = query.value(3).toString();
293  mdata->m_genre = query.value(4).toString();
294  mdata->m_year = query.value(5).toInt();
295  mdata->m_trackNum = query.value(6).toInt();
296  mdata->m_length = query.value(7).toInt();
297  mdata->m_id = query.value(8).toUInt();
298  mdata->m_rating = query.value(9).toInt();
299  mdata->m_playCount = query.value(10).toInt();
300  mdata->m_lastPlay = query.value(11).toDateTime();
301  mdata->m_compilation = (query.value(12).toInt() > 0);
302  mdata->m_format = query.value(13).toString();
303  mdata->m_trackCount = query.value(14).toInt();
304  mdata->m_fileSize = query.value(15).toULongLong();
305  mdata->m_dateAdded = query.value(16).toDateTime();
306  mdata->m_discNum = query.value(17).toInt();
307  mdata->m_discCount = query.value(18).toInt();
308  mdata->m_filename = query.value(19).toString();
309  mdata->m_hostname = query.value(20).toString();
310  mdata->ensureSortFields();
311 
312  if (!QHostAddress(mdata->m_hostname).isNull()) // A bug caused an IP to replace hostname, reset and it will fix itself
313  {
314  mdata->m_hostname = "";
315  mdata->saveHostname();
316  }
317 
318  return mdata;
319  }
320 
321  return nullptr;
322 }
323 
324 // static
326 {
327  // we are only interested in the global setting so remove any local host setting just in case
328  GetMythDB()->ClearSetting("MusicStreamListModified");
329 
330  // make sure we are not already doing an update
331  if (gCoreContext->GetSetting("MusicStreamListModified") == "Updating")
332  {
333  LOG(VB_GENERAL, LOG_ERR, "MusicMetadata: looks like we are already updating the radio streams list");
334  return false;
335  }
336 
337  QByteArray compressedData;
338  QByteArray uncompressedData;
339 
340  // check if the streamlist has been updated since we last checked
341  QDateTime lastModified = GetMythDownloadManager()->GetLastModified(QString(STREAMUPDATEURL));
342 
343  QDateTime lastUpdate = QDateTime::fromString(gCoreContext->GetSetting("MusicStreamListModified"), Qt::ISODate);
344 
345  if (lastModified <= lastUpdate)
346  {
347  LOG(VB_GENERAL, LOG_INFO, "MusicMetadata: radio streams list is already up to date");
348  return true;
349  }
350 
351  gCoreContext->SaveSettingOnHost("MusicStreamListModified", "Updating", nullptr);
352 
353  LOG(VB_GENERAL, LOG_INFO, "MusicMetadata: downloading radio streams list");
354 
355  // download compressed stream file
356  if (!GetMythDownloadManager()->download(QString(STREAMUPDATEURL), &compressedData), false)
357  {
358  LOG(VB_GENERAL, LOG_ERR, "MusicMetadata: failed to download radio stream list");
359  gCoreContext->SaveSettingOnHost("MusicStreamListModified", "", nullptr);
360  return false;
361  }
362 
363  // uncompress the data
364  uncompressedData = gzipUncompress(compressedData);
365 
366  QString errorMsg;
367  int errorLine = 0;
368  int errorColumn = 0;
369 
370  // load the xml
371  QDomDocument domDoc;
372 
373  if (!domDoc.setContent(uncompressedData, false, &errorMsg,
374  &errorLine, &errorColumn))
375  {
376  LOG(VB_GENERAL, LOG_ERR,
377  "MusicMetadata: Could not read content of streams.xml" +
378  QString("\n\t\t\tError parsing %1").arg(STREAMUPDATEURL) +
379  QString("\n\t\t\tat line: %1 column: %2 msg: %3")
380  .arg(errorLine).arg(errorColumn).arg(errorMsg));
381  gCoreContext->SaveSettingOnHost("MusicStreamListModified", "", nullptr);
382  return false;
383  }
384 
386  query.prepare("DELETE FROM music_streams;");
387  if (!query.exec() || !query.isActive() || query.numRowsAffected() < 0)
388  {
389  MythDB::DBError("music delete radio streams", query);
390  gCoreContext->SaveSettingOnHost("MusicStreamListModified", "", nullptr);
391  return false;
392  }
393 
394  LOG(VB_GENERAL, LOG_INFO, "MusicMetadata: processing radio streams list");
395 
396  QDomNodeList itemList = domDoc.elementsByTagName("item");
397 
398  QDomNode itemNode;
399  for (int i = 0; i < itemList.count(); i++)
400  {
401  itemNode = itemList.item(i);
402 
403  query.prepare("INSERT INTO music_streams (broadcaster, channel, description, url1, url2, url3, url4, url5,"
404  " logourl, genre, metaformat, country, language) "
405  "VALUES (:BROADCASTER, :CHANNEL, :DESC, :URL1, :URL2, :URL3, :URL4, :URL5,"
406  " :LOGOURL, :GENRE, :META, :COUNTRY, :LANG);");
407 
408  query.bindValue(":BROADCASTER", itemNode.namedItem(QString("broadcaster")).toElement().text());
409  query.bindValue(":CHANNEL", itemNode.namedItem(QString("channel")).toElement().text());
410  query.bindValue(":DESC", itemNode.namedItem(QString("description")).toElement().text());
411  query.bindValue(":URL1", itemNode.namedItem(QString("url1")).toElement().text());
412  query.bindValue(":URL2", itemNode.namedItem(QString("url2")).toElement().text());
413  query.bindValue(":URL3", itemNode.namedItem(QString("url3")).toElement().text());
414  query.bindValue(":URL4", itemNode.namedItem(QString("url4")).toElement().text());
415  query.bindValue(":URL5", itemNode.namedItem(QString("url5")).toElement().text());
416  query.bindValue(":LOGOURL", itemNode.namedItem(QString("logourl")).toElement().text());
417  query.bindValue(":GENRE", itemNode.namedItem(QString("genre")).toElement().text());
418  query.bindValue(":META", itemNode.namedItem(QString("metadataformat")).toElement().text());
419  query.bindValue(":COUNTRY", itemNode.namedItem(QString("country")).toElement().text());
420  query.bindValue(":LANG", itemNode.namedItem(QString("language")).toElement().text());
421 
422  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
423  {
424  MythDB::DBError("music insert radio stream", query);
425  gCoreContext->SaveSettingOnHost("MusicStreamListModified", "", nullptr);
426  return false;
427  }
428  }
429 
430  gCoreContext->SaveSettingOnHost("MusicStreamListModified", lastModified.toString(Qt::ISODate), nullptr);
431 
432  LOG(VB_GENERAL, LOG_INFO, "MusicMetadata: updating radio streams list completed OK");
433 
434  return true;
435 }
436 
438 {
440 
441  if (!mdata)
442  {
443  LOG(VB_GENERAL, LOG_ERR, QString("MusicMetadata: Asked to reload metadata "
444  "for trackID: %1 but not found!").arg(m_id));
445 
446  return;
447  }
448 
449  *this = *mdata;
450 
451  delete mdata;
452 
453  m_directoryId = -1;
454  m_artistId = -1;
455  m_compartistId = -1;
456  m_albumId = -1;
457  m_genreId = -1;
458 }
459 
461 {
462  if (m_directoryId < 0)
463  {
464  QString sqldir = m_filename.section('/', 0, -2);
465  QString sqlfilename = m_filename.section('/', -1);
466 
468 
470 
471  if (sqldir.isEmpty())
472  {
473  m_directoryId = 0;
474  }
475  else if (m_directoryId < 0)
476  {
477  // Load the directory id
478  query.prepare("SELECT directory_id FROM music_directories "
479  "WHERE path = :DIRECTORY ;");
480  query.bindValue(":DIRECTORY", sqldir);
481 
482  if (!query.exec() || !query.isActive())
483  {
484  MythDB::DBError("music select directory id", query);
485  return -1;
486  }
487  if (query.next())
488  {
489  m_directoryId = query.value(0).toInt();
490  }
491  else
492  {
493  query.prepare("INSERT INTO music_directories (path) VALUES (:DIRECTORY);");
494  query.bindValue(":DIRECTORY", sqldir);
495 
496  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
497  {
498  MythDB::DBError("music insert directory", query);
499  return -1;
500  }
501  m_directoryId = query.lastInsertId().toInt();
502  }
503  }
504  }
505 
506  return m_directoryId;
507 }
508 
510 {
511  if (m_artistId < 0)
512  {
514 
515  // Load the artist id
516  query.prepare("SELECT artist_id FROM music_artists "
517  "WHERE artist_name = :ARTIST ;");
518  query.bindValueNoNull(":ARTIST", m_artist);
519 
520  if (!query.exec() || !query.isActive())
521  {
522  MythDB::DBError("music select artist id", query);
523  return -1;
524  }
525  if (query.next())
526  {
527  m_artistId = query.value(0).toInt();
528  }
529  else
530  {
531  query.prepare("INSERT INTO music_artists (artist_name) VALUES (:ARTIST);");
532  query.bindValueNoNull(":ARTIST", m_artist);
533 
534  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
535  {
536  MythDB::DBError("music insert artist", query);
537  return -1;
538  }
539  m_artistId = query.lastInsertId().toInt();
540  }
541  }
542 
543  return m_artistId;
544 }
545 
547 {
548  if (m_compartistId < 0) {
550 
551  // Compilation Artist
553  {
555  }
556  else
557  {
558  query.prepare("SELECT artist_id FROM music_artists "
559  "WHERE artist_name = :ARTIST ;");
561  if (!query.exec() || !query.isActive())
562  {
563  MythDB::DBError("music select compilation artist id", query);
564  return -1;
565  }
566  if (query.next())
567  {
568  m_compartistId = query.value(0).toInt();
569  }
570  else
571  {
572  query.prepare("INSERT INTO music_artists (artist_name) VALUES (:ARTIST);");
574 
575  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
576  {
577  MythDB::DBError("music insert compilation artist", query);
578  return -1 ;
579  }
580  m_compartistId = query.lastInsertId().toInt();
581  }
582  }
583  }
584 
585  return m_compartistId;
586 }
587 
589 {
590  if (m_albumId < 0)
591  {
593 
594  query.prepare("SELECT album_id FROM music_albums "
595  "WHERE artist_id = :COMP_ARTIST_ID "
596  " AND album_name = :ALBUM ;");
597  query.bindValueNoNull(":COMP_ARTIST_ID", m_compartistId);
598  query.bindValueNoNull(":ALBUM", m_album);
599  if (!query.exec() || !query.isActive())
600  {
601  MythDB::DBError("music select album id", query);
602  return -1;
603  }
604  if (query.next())
605  {
606  m_albumId = query.value(0).toInt();
607  }
608  else
609  {
610  query.prepare("INSERT INTO music_albums (artist_id, album_name, compilation, year) "
611  "VALUES (:COMP_ARTIST_ID, :ALBUM, :COMPILATION, :YEAR);");
612  query.bindValueNoNull(":COMP_ARTIST_ID", m_compartistId);
613  query.bindValueNoNull(":ALBUM", m_album);
614  query.bindValue(":COMPILATION", m_compilation);
615  query.bindValue(":YEAR", m_year);
616 
617  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
618  {
619  MythDB::DBError("music insert album", query);
620  return -1;
621  }
622  m_albumId = query.lastInsertId().toInt();
623  }
624  }
625 
626  return m_albumId;
627 }
628 
630 {
631  if (m_genreId < 0)
632  {
634 
635  query.prepare("SELECT genre_id FROM music_genres "
636  "WHERE genre = :GENRE ;");
637  query.bindValueNoNull(":GENRE", m_genre);
638  if (!query.exec() || !query.isActive())
639  {
640  MythDB::DBError("music select genre id", query);
641  return -1;
642  }
643  if (query.next())
644  {
645  m_genreId = query.value(0).toInt();
646  }
647  else
648  {
649  query.prepare("INSERT INTO music_genres (genre) VALUES (:GENRE);");
650  query.bindValueNoNull(":GENRE", m_genre);
651 
652  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
653  {
654  MythDB::DBError("music insert genre", query);
655  return -1;
656  }
657  m_genreId = query.lastInsertId().toInt();
658  }
659  }
660 
661  return m_genreId;
662 }
663 
664 void MusicMetadata::setUrl(const QString& url, uint index)
665 {
666  if (index < STREAMURLCOUNT)
667  m_urls[index] = url;
668 }
669 
670 QString MusicMetadata::Url(uint index)
671 {
672  if (index < STREAMURLCOUNT)
673  return m_urls[index];
674 
675  return QString();
676 }
677 
679 {
681 
682  if (m_directoryId < 0)
683  getDirectoryId();
684 
685  if (m_artistId < 0)
686  getArtistId();
687 
688  if (m_compartistId < 0)
690 
691  if (m_albumId < 0)
692  getAlbumId();
693 
694  if (m_genreId < 0)
695  getGenreId();
696 
697  // We have all the id's now. We can insert it.
698  QString strQuery;
699  if (m_id < 1)
700  {
701  strQuery = "INSERT INTO music_songs ( directory_id,"
702  " artist_id, album_id, name, genre_id,"
703  " year, track, length, filename,"
704  " rating, format, date_entered, date_modified,"
705  " numplays, track_count, disc_number, disc_count,"
706  " size, hostname) "
707  "VALUES ( "
708  " :DIRECTORY, "
709  " :ARTIST, :ALBUM, :TITLE, :GENRE,"
710  " :YEAR, :TRACKNUM, :LENGTH, :FILENAME,"
711  " :RATING, :FORMAT, :DATE_ADD, :DATE_MOD,"
712  " :PLAYCOUNT,:TRACKCOUNT, :DISC_NUMBER, :DISC_COUNT,"
713  " :SIZE, :HOSTNAME );";
714  }
715  else
716  {
717  strQuery = "UPDATE music_songs SET"
718  " directory_id = :DIRECTORY"
719  ", artist_id = :ARTIST"
720  ", album_id = :ALBUM"
721  ", name = :TITLE"
722  ", genre_id = :GENRE"
723  ", year = :YEAR"
724  ", track = :TRACKNUM"
725  ", length = :LENGTH"
726  ", filename = :FILENAME"
727  ", rating = :RATING"
728  ", format = :FORMAT"
729  ", date_modified = :DATE_MOD "
730  ", numplays = :PLAYCOUNT "
731  ", track_count = :TRACKCOUNT "
732  ", disc_number = :DISC_NUMBER "
733  ", disc_count = :DISC_COUNT "
734  ", size = :SIZE "
735  ", hostname = :HOSTNAME "
736  "WHERE song_id= :ID ;";
737  }
738 
739  QString sqldir = m_filename.section('/', 0, -2);
740  QString sqlfilename = m_filename.section('/', -1);
741 
743 
744  query.prepare(strQuery);
745 
746  query.bindValue(":DIRECTORY", m_directoryId);
747  query.bindValue(":ARTIST", m_artistId);
748  query.bindValue(":ALBUM", m_albumId);
749  query.bindValue(":TITLE", m_title);
750  query.bindValue(":GENRE", m_genreId);
751  query.bindValue(":YEAR", m_year);
752  query.bindValue(":TRACKNUM", m_trackNum);
753  query.bindValue(":LENGTH", m_length);
754  query.bindValue(":FILENAME", sqlfilename);
755  query.bindValue(":RATING", m_rating);
756  query.bindValueNoNull(":FORMAT", m_format);
757  query.bindValue(":DATE_MOD", MythDate::current());
758  query.bindValue(":PLAYCOUNT", m_playCount);
759 
760  if (m_id < 1)
761  query.bindValue(":DATE_ADD", MythDate::current());
762  else
763  query.bindValue(":ID", m_id);
764 
765  query.bindValue(":TRACKCOUNT", m_trackCount);
766  query.bindValue(":DISC_NUMBER", m_discNum);
767  query.bindValue(":DISC_COUNT",m_discCount);
768  query.bindValue(":SIZE", (quint64)m_fileSize);
769  query.bindValue(":HOSTNAME", m_hostname);
770 
771  if (!query.exec())
772  MythDB::DBError("MusicMetadata::dumpToDatabase - updating music_songs",
773  query);
774 
775  if (m_id < 1 && query.isActive() && 1 == query.numRowsAffected())
776  m_id = query.lastInsertId().toInt();
777 
778  // save the albumart to the db
779  if (m_albumArt)
781 
782  // update the album
783  query.prepare("UPDATE music_albums SET album_name = :ALBUM_NAME, "
784  "artist_id = :COMP_ARTIST_ID, compilation = :COMPILATION, "
785  "year = :YEAR "
786  "WHERE music_albums.album_id = :ALBUMID");
787  query.bindValue(":ALBUMID", m_albumId);
788  query.bindValue(":ALBUM_NAME", m_album);
789  query.bindValue(":COMP_ARTIST_ID", m_compartistId);
790  query.bindValue(":COMPILATION", m_compilation);
791  query.bindValue(":YEAR", m_year);
792 
793  if (!query.exec() || !query.isActive())
794  {
795  MythDB::DBError("music compilation update", query);
796  return;
797  }
798 }
799 
800 // Default values for formats
801 // NB These will eventually be customizable....
802 QString MusicMetadata::s_formatNormalFileArtist = "ARTIST";
804 QString MusicMetadata::s_formatNormalCdArtist = "ARTIST";
805 QString MusicMetadata::s_formatNormalCdTrack = "TITLE";
806 QString MusicMetadata::s_formatCompilationFileArtist = "COMPARTIST";
807 QString MusicMetadata::s_formatCompilationFileTrack = "TITLE (ARTIST)";
808 QString MusicMetadata::s_formatCompilationCdArtist = "COMPARTIST";
809 QString MusicMetadata::s_formatCompilationCdTrack = "TITLE (ARTIST)";
810 
812 {
813  QString tmp;
814 
815  tmp = gCoreContext->GetSetting("MusicFormatNormalFileArtist");
816  if (!tmp.isEmpty())
818 
819  tmp = gCoreContext->GetSetting("MusicFormatNormalFileTrack");
820  if (!tmp.isEmpty())
822 
823  tmp = gCoreContext->GetSetting("MusicFormatNormalCDArtist");
824  if (!tmp.isEmpty())
826 
827  tmp = gCoreContext->GetSetting("MusicFormatNormalCDTrack");
828  if (!tmp.isEmpty())
830 
831  tmp = gCoreContext->GetSetting("MusicFormatCompilationFileArtist");
832  if (!tmp.isEmpty())
834 
835  tmp = gCoreContext->GetSetting("MusicFormatCompilationFileTrack");
836  if (!tmp.isEmpty())
838 
839  tmp = gCoreContext->GetSetting("MusicFormatCompilationCDArtist");
840  if (!tmp.isEmpty())
842 
843  tmp = gCoreContext->GetSetting("MusicFormatCompilationCDTrack");
844  if (!tmp.isEmpty())
846 }
847 
848 
850 {
851  m_compilation = (!m_compilationArtist.isEmpty()
854  return m_compilation;
855 }
856 
857 
858 inline QString MusicMetadata::formatReplaceSymbols(const QString &format)
859 {
860  QString rv = format;
861  rv.replace("COMPARTIST", m_compilationArtist);
862  rv.replace("ARTIST", m_artist);
863  rv.replace("TITLE", m_title);
864  rv.replace("TRACK", QString("%1").arg(m_trackNum, 2));
865  return rv;
866 }
867 
869 {
870  if (m_artist.isEmpty())
871  {
872  m_artist = tr("Unknown Artist", "Default artist if no artist");
873  m_artistId = -1;
874  }
875  // This should be the same as Artist if it's a compilation track or blank
876  if (!m_compilation || m_compilationArtist.isEmpty())
877  {
879  m_compartistId = -1;
880  }
881  if (m_album.isEmpty())
882  {
883  m_album = tr("Unknown Album", "Default album if no album");
884  m_albumId = -1;
885  }
886  if (m_title.isEmpty())
888  if (m_genre.isEmpty())
889  {
890  m_genre = tr("Unknown Genre", "Default genre if no genre");
891  m_genreId = -1;
892  }
894 }
895 
897 {
898  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
899 
900  if (m_artistSort.isEmpty() and not m_artist.isEmpty())
901  m_artistSort = sh->doTitle(m_artist);
902  if (m_compilationArtistSort.isEmpty() and not m_compilationArtist.isEmpty())
904  if (m_albumSort.isEmpty() and not m_album.isEmpty())
905  m_albumSort = sh->doTitle(m_album);
906  if (m_titleSort.isEmpty() and not m_title.isEmpty())
907  m_titleSort = sh->doTitle(m_title);
908 }
909 
911 {
912  QString format_artist;
913  QString format_title;
914 
915  if (!m_compilation
916  || "" == m_compilationArtist
918  {
919  if (!cd)
920  {
921  format_artist = s_formatNormalFileArtist;
922  format_title = s_formatNormalFileTrack;
923  }
924  else
925  {
926  format_artist = s_formatNormalCdArtist;
927  format_title = s_formatNormalCdTrack;
928  }
929  }
930  else
931  {
932  if (!cd)
933  {
934  format_artist = s_formatCompilationFileArtist;
935  format_title = s_formatCompilationFileTrack;
936  }
937  else
938  {
939  format_artist = s_formatCompilationCdArtist;
940  format_title = s_formatCompilationCdTrack;
941  }
942  }
943 
944  // NB Could do some comparisons here to save memory with shallow copies...
945  m_formattedArtist = formatReplaceSymbols(format_artist);
946  m_formattedTitle = formatReplaceSymbols(format_title);
947 }
948 
949 
951 {
952  if (m_formattedArtist.isEmpty())
954 
955  return m_formattedArtist;
956 }
957 
958 
960 {
961  if (m_formattedTitle.isEmpty())
963 
964  return m_formattedTitle;
965 }
966 
967 void MusicMetadata::setFilename(const QString& lfilename)
968 {
969  m_filename = lfilename;
970  m_actualFilename.clear();
971 }
972 
974 {
975  // FIXME: for now just use the first url for radio streams
976  if (isRadio())
977  return m_urls[0];
978 
979  // if not asked to find the file just return the raw filename from the DB
980  if (!find)
981  return m_filename;
982 
983  if (!m_actualFilename.isEmpty())
984  return m_actualFilename;
985 
986  // check for a cd track
987  if (m_filename.endsWith(".cda"))
988  {
990  return m_filename;
991  }
992 
993  // check for http urls etc
994  if (m_filename.contains("://"))
995  {
997  return m_filename;
998  }
999 
1000  // first check to see if the filename is complete
1001  if (QFile::exists(m_filename))
1002  {
1004  return m_filename;
1005  }
1006 
1007  // maybe it's in our 'Music' storage group
1008  QString mythUrl = RemoteFile::FindFile(m_filename, m_hostname, "Music");
1009  if (!mythUrl.isEmpty())
1010  {
1011  m_actualFilename = mythUrl;
1012 
1013  QUrl url(mythUrl);
1014  if (url.host() != m_hostname &&
1015  QHostAddress(url.host()).isNull()) // Check that it's not an IP address
1016  {
1017  m_hostname = url.host();
1018  saveHostname();
1019  }
1020 
1021  return mythUrl;
1022  }
1023 
1024  // not found
1025  LOG(VB_GENERAL, LOG_ERR, QString("MusicMetadata: Asked to get the filename for a track but no file found: %1")
1026  .arg(m_filename));
1027 
1029 
1030  return m_actualFilename;
1031 }
1032 
1035 {
1036  // try the file name as is first
1037  if (QFile::exists(m_filename))
1038  return m_filename;
1039 
1040  // not found so now try to find the file in the local 'Music' storage group
1041  StorageGroup storageGroup("Music", gCoreContext->GetHostName(), false);
1042  return storageGroup.FindFile(m_filename);
1043 }
1044 
1045 void MusicMetadata::setField(const QString &field, const QString &data)
1046 {
1047  if (field == "artist")
1048  m_artist = data;
1049  else if (field == "compilation_artist")
1050  m_compilationArtist = data;
1051  else if (field == "album")
1052  m_album = data;
1053  else if (field == "title")
1054  m_title = data;
1055  else if (field == "genre")
1056  m_genre = data;
1057  else if (field == "filename")
1058  m_filename = data;
1059  else if (field == "year")
1060  m_year = data.toInt();
1061  else if (field == "tracknum")
1062  m_trackNum = data.toInt();
1063  else if (field == "trackcount")
1064  m_trackCount = data.toInt();
1065  else if (field == "discnum")
1066  m_discNum = data.toInt();
1067  else if (field == "disccount")
1068  m_discCount = data.toInt();
1069  else if (field == "length")
1070  m_length = data.toInt();
1071  else if (field == "compilation")
1072  m_compilation = (data.toInt() > 0);
1073  else
1074  {
1075  LOG(VB_GENERAL, LOG_ERR, QString("Something asked me to set data "
1076  "for a field called %1").arg(field));
1077  }
1078  ensureSortFields();
1079 }
1080 
1081 void MusicMetadata::getField(const QString &field, QString *data)
1082 {
1083  if (field == "artist")
1084  *data = FormatArtist();
1085  else if (field == "album")
1086  *data = m_album;
1087  else if (field == "title")
1088  *data = FormatTitle();
1089  else if (field == "genre")
1090  *data = m_genre;
1091  else
1092  {
1093  LOG(VB_GENERAL, LOG_ERR, QString("Something asked me to return data "
1094  "about a field called %1").arg(field));
1095  *data = "I Dunno";
1096  }
1097 }
1098 
1099 void MusicMetadata::toMap(InfoMap &metadataMap, const QString &prefix)
1100 {
1101  using namespace MythDate;
1102  metadataMap[prefix + "songid"] = QString::number(m_id);
1103  metadataMap[prefix + "artist"] = m_artist;
1104  metadataMap[prefix + "formatartist"] = FormatArtist();
1105  metadataMap[prefix + "compilationartist"] = m_compilationArtist;
1106 
1107  if (m_album.isEmpty() && ID_TO_REPO(m_id) == RT_Radio)
1108  {
1109  if (m_broadcaster.isEmpty())
1110  metadataMap[prefix + "album"] = m_channel;
1111  else
1112  metadataMap[prefix + "album"] = QString("%1 - %2").arg(m_broadcaster).arg(m_channel);
1113  }
1114  else
1115  metadataMap[prefix + "album"] = m_album;
1116 
1117  metadataMap[prefix + "title"] = m_title;
1118  metadataMap[prefix + "formattitle"] = FormatTitle();
1119  metadataMap[prefix + "tracknum"] = (m_trackNum > 0 ? QString("%1").arg(m_trackNum) : "");
1120  metadataMap[prefix + "trackcount"] = (m_trackCount > 0 ? QString("%1").arg(m_trackCount) : "");
1121  metadataMap[prefix + "discnum"] = (m_discNum > 0 ? QString("%1").arg(m_discNum) : "");
1122  metadataMap[prefix + "disccount"] = (m_discCount > 0 ? QString("%1").arg(m_discCount) : "");
1123  metadataMap[prefix + "genre"] = m_genre;
1124  metadataMap[prefix + "year"] = (m_year > 0 ? QString("%1").arg(m_year) : "");
1125 
1126  QString fmt = (m_length >= ONEHOURINMS) ? "H:mm:ss" : "mm:ss";
1127  metadataMap[prefix + "length"] = MythFormatTimeMs(m_length, fmt);
1128 
1129  if (m_lastPlay.isValid())
1130  {
1131  metadataMap[prefix + "lastplayed"] =
1133  }
1134  else
1135  {
1136  metadataMap[prefix + "lastplayed"] = tr("Never Played");
1137  }
1138 
1139  metadataMap[prefix + "dateadded"] = MythDate::toString(
1141 
1142  metadataMap[prefix + "playcount"] = QString::number(m_playCount);
1143 
1144  QLocale locale = gCoreContext->GetQLocale();
1145  QString tmpSize = locale.toString(m_fileSize *
1146  (1.0 / (1024.0 * 1024.0)), 'f', 2);
1147  metadataMap[prefix + "filesize"] = tmpSize;
1148 
1149  metadataMap[prefix + "filename"] = m_filename;
1150 
1151  // radio stream
1152  if (!m_broadcaster.isEmpty())
1153  metadataMap[prefix + "broadcasterchannel"] = m_broadcaster + " - " + m_channel;
1154  else
1155  metadataMap[prefix + "broadcasterchannel"] = m_channel;
1156  metadataMap[prefix + "broadcaster"] = m_broadcaster;
1157  metadataMap[prefix + "channel"] = m_channel;
1158  metadataMap[prefix + "genre"] = m_genre;
1159  metadataMap[prefix + "country"] = m_country;
1160  metadataMap[prefix + "language"] = m_language;
1161  metadataMap[prefix + "description"] = m_description;
1162 
1163  if (isRadio())
1164  {
1165  QUrl url(m_urls[0]);
1166  metadataMap[prefix + "url"] = url.toString(QUrl::RemoveUserInfo);
1167  }
1168  else
1169  metadataMap[prefix + "url"] = m_filename;
1170 
1171  metadataMap[prefix + "logourl"] = m_logoUrl;
1172  metadataMap[prefix + "metadataformat"] = m_metaFormat;
1173 }
1174 
1176 {
1177  if (m_rating > 0)
1178  {
1179  m_rating--;
1180  }
1181  m_changed = true;
1182 }
1183 
1185 {
1186  if (m_rating < 10)
1187  {
1188  m_rating++;
1189  }
1190  m_changed = true;
1191 }
1192 
1193 void MusicMetadata::setLastPlay(const QDateTime& lastPlay)
1194 {
1195  m_tempLastPlay = MythDate::as_utc(lastPlay);
1196  m_changed = true;
1197 }
1198 
1200 {
1202  m_changed = true;
1203 }
1204 
1206 {
1208  m_changed = true;
1209 }
1210 
1212 {
1213  // add the images found in the tag to the ones we got from the DB
1214 
1215  if (!m_albumArt)
1216  m_albumArt = new AlbumArtImages(this, false);
1217 
1218  for (auto *art : qAsConst(albumart))
1219  {
1220  art->m_filename = QString("%1-%2").arg(m_id).arg(art->m_filename);
1221  m_albumArt->addImage(art);
1222  }
1223 
1224  m_changed = true;
1225 }
1226 
1227 QStringList MusicMetadata::fillFieldList(const QString& field)
1228 {
1229  QStringList searchList;
1230  searchList.clear();
1231 
1233  if ("artist" == field)
1234  {
1235  query.prepare("SELECT artist_name FROM music_artists ORDER BY artist_name;");
1236  }
1237  else if ("compilation_artist" == field)
1238  {
1239  query.prepare("SELECT DISTINCT artist_name FROM music_artists, music_albums where "
1240  "music_albums.artist_id=music_artists.artist_id ORDER BY artist_name");
1241  }
1242  else if ("album" == field)
1243  {
1244  query.prepare("SELECT album_name FROM music_albums ORDER BY album_name;");
1245  }
1246  else if ("title" == field)
1247  {
1248  query.prepare("SELECT name FROM music_songs ORDER BY name;");
1249  }
1250  else if ("genre" == field)
1251  {
1252  query.prepare("SELECT genre FROM music_genres ORDER BY genre;");
1253  }
1254  else
1255  {
1256  return searchList;
1257  }
1258 
1259  if (query.exec() && query.isActive())
1260  {
1261  while (query.next())
1262  {
1263  searchList << query.value(0).toString();
1264  }
1265  }
1266  return searchList;
1267 }
1268 
1270 {
1271  if (!m_albumArt)
1272  m_albumArt = new AlbumArtImages(this);
1273 
1274  AlbumArtImage *albumart_image = nullptr;
1275  QString res;
1276 
1277  if ((albumart_image = m_albumArt->getImage(IT_FRONTCOVER)))
1278  res = albumart_image->m_filename; // NOLINT(bugprone-branch-clone)
1279  else if ((albumart_image = m_albumArt->getImage(IT_UNKNOWN)))
1280  res = albumart_image->m_filename;
1281  else if ((albumart_image = m_albumArt->getImage(IT_BACKCOVER)))
1282  res = albumart_image->m_filename;
1283  else if ((albumart_image = m_albumArt->getImage(IT_INLAY)))
1284  res = albumart_image->m_filename;
1285  else if ((albumart_image = m_albumArt->getImage(IT_CD)))
1286  res = albumart_image->m_filename;
1287 
1288  // check file exists
1289  if (!res.isEmpty() && albumart_image)
1290  {
1291  int repo = ID_TO_REPO(m_id);
1292  if (repo == RT_Radio)
1293  {
1294  // image is a radio station icon, check if we have already downloaded and cached it
1295  QString path = GetConfDir() + "/MythMusic/AlbumArt/";
1296  QFileInfo fi(res);
1297  QString filename = QString("%1-%2.%3").arg(m_id).arg("front").arg(fi.suffix());
1298 
1299  albumart_image->m_filename = path + filename;
1300 
1301  if (!QFile::exists(albumart_image->m_filename))
1302  {
1303  // file does not exist so try to download and cache it
1304  if (!GetMythDownloadManager()->download(res, albumart_image->m_filename))
1305  {
1306  m_albumArt->getImageList()->removeAll(albumart_image);
1307  return QString("");
1308  }
1309  }
1310 
1311  res = albumart_image->m_filename;
1312  }
1313  else
1314  {
1315  // check for the image in the storage group
1316  QUrl url(res);
1317 
1318  if (url.path().isEmpty() || url.host().isEmpty() || url.userName().isEmpty())
1319  {
1320  return QString("");
1321  }
1322 
1323  if (!RemoteFile::Exists(res))
1324  {
1325  if (albumart_image->m_embedded)
1326  {
1327  if (gCoreContext->IsMasterBackend() &&
1328  url.host() == gCoreContext->GetMasterHostName())
1329  {
1330  QStringList paramList;
1331  paramList.append(QString("--songid='%1'").arg(ID()));
1332  paramList.append(QString("--imagetype='%1'").arg(albumart_image->m_imageType));
1333 
1334  QString command = "mythutil --extractimage " + paramList.join(" ");
1335 
1336  QScopedPointer<MythSystem> cmd(MythSystem::Create(command,
1340  }
1341  else
1342  {
1343  QStringList slist;
1344  slist << "MUSIC_TAG_GETIMAGE"
1345  << Hostname()
1346  << QString::number(ID())
1347  << QString::number(albumart_image->m_imageType);
1349  }
1350  }
1351  }
1352  }
1353 
1354  return res;
1355  }
1356 
1357  return QString("");
1358 }
1359 
1361 {
1362  if (!m_albumArt)
1363  m_albumArt = new AlbumArtImages(this);
1364 
1365  AlbumArtImage *albumart_image = m_albumArt->getImage(type);
1366  if (albumart_image)
1367  return albumart_image->m_filename;
1368 
1369  return QString("");
1370 }
1371 
1373 {
1374  if (!m_albumArt)
1375  m_albumArt = new AlbumArtImages(this);
1376 
1377  return m_albumArt;
1378 }
1379 
1381 {
1382  delete m_albumArt;
1383  m_albumArt = nullptr; //new AlbumArtImages(this);
1384 }
1385 
1387 {
1388  if (!m_lyricsData)
1389  m_lyricsData = new LyricsData(this);
1390 
1391  return m_lyricsData;
1392 }
1393 
1394 // create a MetaIO for the file to read/write any tags etc
1395 // NOTE the caller is responsible for deleting it
1397 {
1398  // the taggers require direct file access so try to find
1399  // the file on the local filesystem
1400 
1401  QString filename = getLocalFilename();
1402 
1403  if (!filename.isEmpty())
1404  {
1405  LOG(VB_FILE, LOG_INFO, QString("MusicMetadata::getTagger - creating tagger for %1").arg(filename));
1407  }
1408 
1409  LOG(VB_GENERAL, LOG_ERR, QString("MusicMetadata::getTagger - failed to find %1 on the local filesystem").arg(Filename(false)));
1410  return nullptr;
1411 }
1412 
1413 //--------------------------------------------------------------------------
1414 
1416 {
1417  RunProlog();
1418  //if you want to simulate a big music collection load
1419  //sleep(3);
1420  m_parent->resync();
1421  RunEpilog();
1422 }
1423 
1425 {
1426  // Start a thread to do data loading and sorting
1427  startLoading();
1428 }
1429 
1431 {
1432  while (!m_allMusic.empty())
1433  {
1434  delete m_allMusic.back();
1435  m_allMusic.pop_back();
1436  }
1437 
1438  while (!m_cdData.empty())
1439  {
1440  delete m_cdData.back();
1441  m_cdData.pop_back();
1442  }
1443 
1444  m_metadataLoader->wait();
1445  delete m_metadataLoader;
1446 }
1447 
1449 {
1450  // If this is still running, the user
1451  // probably selected mythmusic and then
1452  // escaped out right away
1453 
1454  if (m_metadataLoader->isFinished())
1455  {
1456  return true;
1457  }
1458 
1459  m_metadataLoader->wait();
1460  return false;
1461 }
1462 
1475 {
1476  // Set this to false early rather than letting it be
1477  // delayed till the thread calls resync.
1478  m_doneLoading = false;
1479 
1480  if (m_metadataLoader)
1481  {
1482  cleanOutThreads();
1483  delete m_metadataLoader;
1484  }
1485 
1486  m_metadataLoader = new MetadataLoadingThread(this);
1487  m_metadataLoader->start();
1488 
1489  return true;
1490 }
1491 
1494 {
1495  uint added = 0;
1496  uint removed = 0;
1497  uint changed = 0;
1498 
1499  m_doneLoading = false;
1500 
1501  QString aquery = "SELECT music_songs.song_id, music_artists.artist_id, music_artists.artist_name, "
1502  "music_comp_artists.artist_name AS compilation_artist, "
1503  "music_albums.album_id, music_albums.album_name, music_songs.name, music_genres.genre, music_songs.year, "
1504  "music_songs.track, music_songs.length, music_songs.directory_id, "
1505  "CONCAT_WS('/', music_directories.path, music_songs.filename) AS filename, "
1506  "music_songs.rating, music_songs.numplays, music_songs.lastplay, music_songs.date_entered, "
1507  "music_albums.compilation, music_songs.format, music_songs.track_count, "
1508  "music_songs.size, music_songs.hostname, music_songs.disc_number, music_songs.disc_count "
1509  "FROM music_songs "
1510  "LEFT JOIN music_directories ON music_songs.directory_id=music_directories.directory_id "
1511  "LEFT JOIN music_artists ON music_songs.artist_id=music_artists.artist_id "
1512  "LEFT JOIN music_albums ON music_songs.album_id=music_albums.album_id "
1513  "LEFT JOIN music_artists AS music_comp_artists ON music_albums.artist_id=music_comp_artists.artist_id "
1514  "LEFT JOIN music_genres ON music_songs.genre_id=music_genres.genre_id "
1515  "ORDER BY music_songs.song_id;";
1516 
1517  QString filename;
1518  QString artist;
1519  QString album;
1520  QString title;
1521  QString compartist;
1522 
1524  if (!query.exec(aquery))
1525  MythDB::DBError("AllMusic::resync", query);
1526 
1527  m_numPcs = query.size() * 2;
1528  m_numLoaded = 0;
1529  QList<MusicMetadata::IdType> idList;
1530 
1531  if (query.isActive() && query.size() > 0)
1532  {
1533  while (query.next())
1534  {
1535  MusicMetadata::IdType id = query.value(0).toInt();
1536 
1537  idList.append(id);
1538 
1539  auto *dbMeta = new MusicMetadata(
1540  query.value(12).toString(), // filename
1541  query.value(2).toString(), // artist
1542  query.value(3).toString(), // compilation artist
1543  query.value(5).toString(), // album
1544  query.value(6).toString(), // title
1545  query.value(7).toString(), // genre
1546  query.value(8).toInt(), // year
1547  query.value(9).toInt(), // track no.
1548  query.value(10).toInt(), // length
1549  query.value(0).toInt(), // id
1550  query.value(13).toInt(), // rating
1551  query.value(14).toInt(), // playcount
1552  query.value(15).toDateTime(), // lastplay
1553  query.value(16).toDateTime(), // date_entered
1554  (query.value(17).toInt() > 0), // compilation
1555  query.value(18).toString()); // format
1556 
1557  dbMeta->setDirectoryId(query.value(11).toInt());
1558  dbMeta->setArtistId(query.value(1).toInt());
1559  dbMeta->setCompilationArtistId(query.value(3).toInt());
1560  dbMeta->setAlbumId(query.value(4).toInt());
1561  dbMeta->setTrackCount(query.value(19).toInt());
1562  dbMeta->setFileSize(query.value(20).toULongLong());
1563  dbMeta->setHostname(query.value(21).toString());
1564  dbMeta->setDiscNumber(query.value(22).toInt());
1565  dbMeta->setDiscCount(query.value(23).toInt());
1566 
1567  if (!m_musicMap.contains(id))
1568  {
1569  // new track
1570 
1571  // Don't delete dbMeta, as the MetadataPtrList now owns it
1572  m_allMusic.append(dbMeta);
1573 
1574  m_musicMap[id] = dbMeta;
1575 
1576  added++;
1577  }
1578  else
1579  {
1580  // existing track, check for any changes
1581  MusicMetadata *cacheMeta = m_musicMap[id];
1582 
1583  if (cacheMeta && !cacheMeta->compare(dbMeta))
1584  {
1585  cacheMeta->reloadMetadata();
1586  changed++;
1587  }
1588 
1589  // we already have this track in the cache so don't need dbMeta anymore
1590  delete dbMeta;
1591  }
1592 
1593  // compute max/min playcount,lastplay for all music
1594  if (query.at() == 0)
1595  {
1596  // first song
1597  m_playCountMin = m_playCountMax = query.value(13).toInt();
1598  m_lastPlayMin = m_lastPlayMax = query.value(14).toDateTime().toSecsSinceEpoch();
1599  }
1600  else
1601  {
1602  int playCount = query.value(13).toInt();
1603  qint64 lastPlay = query.value(14).toDateTime().toSecsSinceEpoch();
1604 
1605  m_playCountMin = min(playCount, m_playCountMin);
1606  m_playCountMax = max(playCount, m_playCountMax);
1607  m_lastPlayMin = min(lastPlay, m_lastPlayMin);
1608  m_lastPlayMax = max(lastPlay, m_lastPlayMax);
1609  }
1610  m_numLoaded++;
1611  }
1612  }
1613  else
1614  {
1615  LOG(VB_GENERAL, LOG_ERR, "MythMusic hasn't found any tracks!");
1616  }
1617 
1618  // get a list of tracks in our cache that's now not in the database
1619  QList<MusicMetadata::IdType> deleteList;
1620  for (const auto *track : qAsConst(m_allMusic))
1621  {
1622  if (!idList.contains(track->ID()))
1623  {
1624  deleteList.append(track->ID());
1625  }
1626  }
1627 
1628  // remove the no longer available tracks
1629  for (uint id : deleteList)
1630  {
1631  MusicMetadata *mdata = m_musicMap[id];
1632  m_allMusic.removeAll(mdata);
1633  m_musicMap.remove(id);
1634  removed++;
1635  delete mdata;
1636  }
1637 
1638  // tell any listeners a resync has just finished and they may need to reload/resync
1639  LOG(VB_GENERAL, LOG_DEBUG, QString("AllMusic::resync sending MUSIC_RESYNC_FINISHED added: %1, removed: %2, changed: %3")
1640  .arg(added).arg(removed).arg(changed));
1641  gCoreContext->SendMessage(QString("MUSIC_RESYNC_FINISHED %1 %2 %3").arg(added).arg(removed).arg(changed));
1642 
1643  m_doneLoading = true;
1644 }
1645 
1647 {
1648  if (m_musicMap.contains(an_id))
1649  return m_musicMap[an_id];
1650 
1651  return nullptr;
1652 }
1653 
1654 bool AllMusic::isValidID(int an_id)
1655 {
1656  return m_musicMap.contains(an_id);
1657 }
1658 
1659 bool AllMusic::updateMetadata(int an_id, MusicMetadata *the_track)
1660 {
1661  if (an_id > 0)
1662  {
1663  MusicMetadata *mdata = getMetadata(an_id);
1664  if (mdata)
1665  {
1666  *mdata = *the_track;
1667  return true;
1668  }
1669  }
1670  return false;
1671 }
1672 
1674 void AllMusic::save(void)
1675 {
1676  for (auto *item : qAsConst(m_allMusic))
1677  {
1678  if (item->hasChanged())
1679  item->persist();
1680  }
1681 }
1682 
1683 // cd stuff
1685 {
1686  while (!m_cdData.empty())
1687  {
1688  MusicMetadata *mdata = m_cdData.back();
1689  if (m_musicMap.contains(mdata->ID()))
1690  m_musicMap.remove(mdata->ID());
1691 
1692  delete m_cdData.back();
1693  m_cdData.pop_back();
1694  }
1695 
1696  m_cdTitle = tr("CD -- none");
1697 }
1698 
1699 void AllMusic::addCDTrack(const MusicMetadata &the_track)
1700 {
1701  auto *mdata = new MusicMetadata(the_track);
1702  mdata->setID(m_cdData.count() + 1);
1703  mdata->setRepo(RT_CD);
1704  m_cdData.append(mdata);
1705  m_musicMap[mdata->ID()] = mdata;
1706 }
1707 
1709 {
1710  if (m_cdData.count() < 1)
1711  return false;
1712 
1713  return m_cdData.last()->FormatTitle() == the_track->FormatTitle();
1714 }
1715 
1717 {
1718  for (auto *anit : qAsConst(m_cdData))
1719  {
1720  if (anit->Track() == the_track)
1721  {
1722  return anit;
1723  }
1724  }
1725 
1726  return nullptr;
1727 }
1728 
1729 /**************************************************************************/
1730 
1732 {
1733  loadStreams();
1734 }
1735 
1737 {
1738  while (!m_streamList.empty())
1739  {
1740  delete m_streamList.back();
1741  m_streamList.pop_back();
1742  }
1743 }
1744 
1746 {
1747  for (int x = 0; x < m_streamList.count(); x++)
1748  {
1749  if (m_streamList.at(x)->ID() == an_id)
1750  return true;
1751  }
1752 
1753  return false;
1754 }
1755 
1757 {
1758  for (int x = 0; x < m_streamList.count(); x++)
1759  {
1760  if (m_streamList.at(x)->ID() == an_id)
1761  return m_streamList.at(x);
1762  }
1763 
1764  return nullptr;
1765 }
1766 
1768 {
1769  while (!m_streamList.empty())
1770  {
1771  delete m_streamList.back();
1772  m_streamList.pop_back();
1773  }
1774 
1775  QString aquery = "SELECT intid, broadcaster, channel, description, url1, url2, url3, url4, url5,"
1776  "logourl, genre, metaformat, country, language, format "
1777  "FROM music_radios "
1778  "ORDER BY broadcaster,channel;";
1779 
1781  if (!query.exec(aquery))
1782  MythDB::DBError("AllStream::loadStreams", query);
1783 
1784  if (query.isActive() && query.size() > 0)
1785  {
1786  while (query.next())
1787  {
1788  UrlList urls;
1789  for (int x = 0; x < STREAMURLCOUNT; x++)
1790  urls[x] = query.value(4 + x).toString();
1791 
1792  auto *mdata = new MusicMetadata(
1793  query.value(0).toInt(), // intid
1794  query.value(1).toString(), // broadcaster
1795  query.value(2).toString(), // channel
1796  query.value(3).toString(), // description
1797  urls, // array of 5 urls
1798  query.value(9).toString(), // logourl
1799  query.value(10).toString(), // genre
1800  query.value(11).toString(), // metadataformat
1801  query.value(12).toString(), // country
1802  query.value(13).toString(), // language
1803  query.value(14).toString()); // format
1804 
1805  mdata->setRepo(RT_Radio);
1806 
1807  m_streamList.append(mdata);
1808  }
1809  }
1810  else
1811  {
1812  LOG(VB_GENERAL, LOG_WARNING, "MythMusic hasn't found any radio streams!");
1813  }
1814 }
1815 
1817 {
1818  // add the stream to the db
1820  query.prepare("INSERT INTO music_radios (broadcaster, channel, description, "
1821  "url1, url2, url3, url4, url5, "
1822  "logourl, genre, country, language, format, metaformat) "
1823  "VALUES (:BROADCASTER, :CHANNEL, :DESCRIPTION, :URL1, :URL2, :URL3, :URL4, :URL5, "
1824  ":LOGOURL, :GENRE, :COUNTRY, :LANGUAGE, :FORMAT, :METAFORMAT);");
1825  query.bindValueNoNull(":BROADCASTER", mdata->Broadcaster());
1826  query.bindValueNoNull(":CHANNEL", mdata->Channel());
1827  query.bindValueNoNull(":DESCRIPTION", mdata->Description());
1828  query.bindValueNoNull(":URL1", mdata->Url(0));
1829  query.bindValueNoNull(":URL2", mdata->Url(1));
1830  query.bindValueNoNull(":URL3", mdata->Url(2));
1831  query.bindValueNoNull(":URL4", mdata->Url(3));
1832  query.bindValueNoNull(":URL5", mdata->Url(4));
1833  query.bindValueNoNull(":LOGOURL", mdata->LogoUrl());
1834  query.bindValueNoNull(":GENRE", mdata->Genre());
1835  query.bindValueNoNull(":COUNTRY", mdata->Country());
1836  query.bindValueNoNull(":LANGUAGE", mdata->Language());
1837  query.bindValueNoNull(":FORMAT", mdata->Format());
1838  query.bindValueNoNull(":METAFORMAT", mdata->MetadataFormat());
1839 
1840  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
1841  {
1842  MythDB::DBError("music insert radio", query);
1843  return;
1844  }
1845 
1846  mdata->setID(query.lastInsertId().toInt());
1847  mdata->setRepo(RT_Radio);
1848 
1849  loadStreams();
1850 }
1851 
1853 {
1854  // remove the stream from the db
1855  int id = ID_TO_ID(mdata->ID());
1857  query.prepare("DELETE FROM music_radios WHERE intid = :ID");
1858  query.bindValue(":ID", id);
1859 
1860  if (!query.exec() || query.numRowsAffected() <= 0)
1861  {
1862  MythDB::DBError("AllStream::removeStream", query);
1863  return;
1864  }
1865 
1866  loadStreams();
1867 }
1868 
1870 {
1871  // update the stream in the db
1872  int id = ID_TO_ID(mdata->ID());
1874  query.prepare("UPDATE music_radios set broadcaster = :BROADCASTER, channel = :CHANNEL, description = :DESCRIPTION, "
1875  "url1 = :URL1, url2 = :URL2, url3 = :URL3, url4 = :URL4, url5 = :URL5, "
1876  "logourl = :LOGOURL, genre = :GENRE, country = :COUNTRY, language = :LANGUAGE, "
1877  "format = :FORMAT, metaformat = :METAFORMAT "
1878  "WHERE intid = :ID");
1879  query.bindValueNoNull(":BROADCASTER", mdata->Broadcaster());
1880  query.bindValueNoNull(":CHANNEL", mdata->Channel());
1881  query.bindValueNoNull(":DESCRIPTION", mdata->Description());
1882  query.bindValueNoNull(":URL1", mdata->Url(0));
1883  query.bindValueNoNull(":URL2", mdata->Url(1));
1884  query.bindValueNoNull(":URL3", mdata->Url(2));
1885  query.bindValueNoNull(":URL4", mdata->Url(3));
1886  query.bindValueNoNull(":URL5", mdata->Url(4));
1887  query.bindValueNoNull(":LOGOURL", mdata->LogoUrl());
1888  query.bindValueNoNull(":GENRE", mdata->Genre());
1889  query.bindValueNoNull(":COUNTRY", mdata->Country());
1890  query.bindValueNoNull(":LANGUAGE", mdata->Language());
1891  query.bindValueNoNull(":FORMAT", mdata->Format());
1892  query.bindValueNoNull(":METAFORMAT", mdata->MetadataFormat());
1893  query.bindValue(":ID", id);
1894 
1895  if (!query.exec() || !query.isActive() || query.numRowsAffected() <= 0)
1896  {
1897  MythDB::DBError("AllStream::updateStream", query);
1898  return;
1899  }
1900 
1901  loadStreams();
1902 }
1903 
1904 /**************************************************************************/
1905 
1907  : m_parent(metadata)
1908 {
1909  if (loadFromDB)
1910  findImages();
1911 }
1912 
1914 {
1915  while (!m_imageList.empty())
1916  {
1917  delete m_imageList.back();
1918  m_imageList.pop_back();
1919  }
1920 }
1921 
1923 {
1924  while (!m_imageList.empty())
1925  {
1926  delete m_imageList.back();
1927  m_imageList.pop_back();
1928  }
1929 
1930  if (m_parent == nullptr)
1931  return;
1932 
1933  int trackid = ID_TO_ID(m_parent->ID());
1934  int repo = ID_TO_REPO(m_parent->ID());
1935 
1936  if (repo == RT_Radio)
1937  {
1939  //FIXME: this should work with the alternate urls as well eg url2, url3 etc
1940  query.prepare("SELECT logourl FROM music_radios WHERE url1 = :URL;");
1941  query.bindValue(":URL", m_parent->Filename());
1942  if (query.exec())
1943  {
1944  while (query.next())
1945  {
1946  QString logoUrl = query.value(0).toString();
1947 
1948  auto *image = new AlbumArtImage();
1949  image->m_id = -1;
1950  image->m_filename = logoUrl;
1951  image->m_imageType = IT_FRONTCOVER;
1952  image->m_embedded = false;
1953  image->m_hostname = "";
1954  m_imageList.push_back(image);
1955  }
1956  }
1957  }
1958  else
1959  {
1960  if (trackid == 0)
1961  return;
1962 
1963  QFileInfo fi(m_parent->Filename(false));
1964  QString dir = fi.path();
1965 
1967  query.prepare("SELECT albumart_id, CONCAT_WS('/', music_directories.path, "
1968  "music_albumart.filename), music_albumart.filename, music_albumart.imagetype, "
1969  "music_albumart.embedded, music_albumart.hostname "
1970  "FROM music_albumart "
1971  "LEFT JOIN music_directories ON "
1972  "music_directories.directory_id = music_albumart.directory_id "
1973  "WHERE music_directories.path = :DIR "
1974  "OR song_id = :SONGID "
1975  "ORDER BY music_albumart.imagetype;");
1976  query.bindValue(":DIR", dir);
1977  query.bindValue(":SONGID", trackid);
1978  if (query.exec())
1979  {
1980  while (query.next())
1981  {
1982  auto *image = new AlbumArtImage();
1983  bool embedded = (query.value(4).toInt() == 1);
1984  image->m_id = query.value(0).toInt();
1985 
1986  QUrl url(m_parent->Filename(true));
1987 
1988  if (embedded)
1989  {
1990  if (url.scheme() == "myth")
1991  {
1992  image->m_filename = MythCoreContext::GenMythURL(url.host(), url.port(),
1993  QString("AlbumArt/") + query.value(1).toString(),
1994  "MusicArt");
1995  }
1996  else
1997  {
1998  image->m_filename = query.value(1).toString();
1999  }
2000  }
2001  else
2002  {
2003  if (url.scheme() == "myth")
2004  {
2005  image->m_filename = MythCoreContext::GenMythURL(url.host(), url.port(),
2006  query.value(1).toString(),
2007  "Music");
2008  }
2009  else
2010  {
2011  image->m_filename = query.value(1).toString();
2012  }
2013  }
2014 
2015  image->m_imageType = (ImageType) query.value(3).toInt();
2016  image->m_embedded = embedded;
2017  image->m_hostname = query.value(5).toString();
2018 
2019  m_imageList.push_back(image);
2020  }
2021  }
2022 
2023  // add any artist images
2024  QString artist = m_parent->Artist().toLower();
2025  if (findIcon("artist", artist) != QString())
2026  {
2027  auto *image = new AlbumArtImage();
2028  image->m_id = -1;
2029  image->m_filename = findIcon("artist", artist);
2030  image->m_imageType = IT_ARTIST;
2031  image->m_embedded = false;
2032 
2033  m_imageList.push_back(image);
2034  }
2035  }
2036 }
2037 
2039 {
2040  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
2041  auto *busy = new MythUIBusyDialog(tr("Scanning for music album art..."),
2042  popupStack, "scanbusydialog");
2043 
2044  if (busy->Create())
2045  {
2046  popupStack->AddScreen(busy, false);
2047  }
2048  else
2049  {
2050  delete busy;
2051  busy = nullptr;
2052  }
2053 
2054  QStringList strList;
2055  strList << "MUSIC_FIND_ALBUMART"
2056  << m_parent->Hostname()
2057  << QString::number(m_parent->ID())
2058  << "1";
2059 
2060  auto *scanThread = new AlbumArtScannerThread(strList);
2061  scanThread->start();
2062 
2063  while (scanThread->isRunning())
2064  {
2065  QCoreApplication::processEvents();
2066  usleep(1000);
2067  }
2068 
2069  strList = scanThread->getResult();
2070 
2071  delete scanThread;
2072 
2073  if (busy)
2074  busy->Close();
2075 
2076  while (!m_imageList.empty())
2077  {
2078  delete m_imageList.back();
2079  m_imageList.pop_back();
2080  }
2081 
2082  for (int x = 2; x < strList.count(); x += 6)
2083  {
2084  auto *image = new AlbumArtImage;
2085  image->m_id = strList[x].toInt();
2086  image->m_imageType = (ImageType) strList[x + 1].toInt();
2087  image->m_embedded = (strList[x + 2].toInt() == 1);
2088  image->m_description = strList[x + 3];
2089 
2090  if (image->m_embedded)
2091  {
2092  image->m_filename = MythCoreContext::GenMythURL(m_parent->Hostname(), 0,
2093  QString("AlbumArt/") + strList[x + 4],
2094  "MusicArt");
2095  }
2096  else
2097  {
2098  image->m_filename = MythCoreContext::GenMythURL(m_parent->Hostname(), 0,
2099  strList[x + 4],
2100  "Music");
2101  }
2102 
2103  image->m_hostname = strList[x + 5];
2104 
2105  LOG(VB_FILE, LOG_INFO, "AlbumArtImages::scanForImages found image");
2106  LOG(VB_FILE, LOG_INFO, QString("ID: %1").arg(image->m_id));
2107  LOG(VB_FILE, LOG_INFO, QString("ImageType: %1").arg(image->m_imageType));
2108  LOG(VB_FILE, LOG_INFO, QString("Embedded: %1").arg(image->m_embedded));
2109  LOG(VB_FILE, LOG_INFO, QString("Description: %1").arg(image->m_description));
2110  LOG(VB_FILE, LOG_INFO, QString("Filename: %1").arg(image->m_filename));
2111  LOG(VB_FILE, LOG_INFO, QString("Hostname: %1").arg(image->m_hostname));
2112  LOG(VB_FILE, LOG_INFO, "-------------------------------");
2113 
2114  addImage(image);
2115 
2116  delete image;
2117  }
2118 }
2119 
2121 {
2122  for (auto *item : qAsConst(m_imageList))
2123  {
2124  if (item->m_imageType == type)
2125  return item;
2126  }
2127 
2128  return nullptr;
2129 }
2130 
2132 {
2133  for (auto *item : qAsConst(m_imageList))
2134  {
2135  if (item->m_id == imageID)
2136  return item;
2137  }
2138 
2139  return nullptr;
2140 }
2141 
2142 QStringList AlbumArtImages::getImageFilenames(void) const
2143 {
2144  QStringList paths;
2145 
2146  for (const auto *item : qAsConst(m_imageList))
2147  paths += item->m_filename;
2148 
2149  return paths;
2150 }
2151 
2153 {
2154  if (index < (uint)m_imageList.size())
2155  return m_imageList[index];
2156 
2157  return nullptr;
2158 }
2159 
2160 // static method to get a translated type name from an ImageType
2162 {
2163  // these const's should match the ImageType enum's
2164  static const std::array<const std::string,6> s_typeStrings {
2165  QT_TR_NOOP("Unknown"), // IT_UNKNOWN
2166  QT_TR_NOOP("Front Cover"), // IT_FRONTCOVER
2167  QT_TR_NOOP("Back Cover"), // IT_BACKCOVER
2168  QT_TR_NOOP("CD"), // IT_CD
2169  QT_TR_NOOP("Inlay"), // IT_INLAY
2170  QT_TR_NOOP("Artist"), // IT_ARTIST
2171  };
2172 
2173  return QCoreApplication::translate("AlbumArtImages",
2174  s_typeStrings[type].c_str());
2175 }
2176 
2177 // static method to get a filename from an ImageType
2179 {
2180  // these const's should match the ImageType enum's
2181  static const std::array<const std::string,6> s_filenameStrings {
2182  QT_TR_NOOP("unknown"), // IT_UNKNOWN
2183  QT_TR_NOOP("front"), // IT_FRONTCOVER
2184  QT_TR_NOOP("back"), // IT_BACKCOVER
2185  QT_TR_NOOP("cd"), // IT_CD
2186  QT_TR_NOOP("inlay"), // IT_INLAY
2187  QT_TR_NOOP("artist") // IT_ARTIST
2188  };
2189 
2190  return QCoreApplication::translate("AlbumArtImages",
2191  s_filenameStrings[type].c_str());
2192 }
2193 
2194 // static method to guess the image type from the filename
2196 {
2198 
2199  if (filename.contains("front", Qt::CaseInsensitive) ||
2200  filename.contains(tr("front"), Qt::CaseInsensitive) ||
2201  filename.contains("cover", Qt::CaseInsensitive) ||
2202  filename.contains(tr("cover"), Qt::CaseInsensitive))
2203  type = IT_FRONTCOVER;
2204  else if (filename.contains("back", Qt::CaseInsensitive) ||
2205  filename.contains(tr("back"), Qt::CaseInsensitive))
2206  type = IT_BACKCOVER;
2207  else if (filename.contains("inlay", Qt::CaseInsensitive) ||
2208  filename.contains(tr("inlay"), Qt::CaseInsensitive))
2209  type = IT_INLAY;
2210  else if (filename.contains("cd", Qt::CaseInsensitive) ||
2211  filename.contains(tr("cd"), Qt::CaseInsensitive))
2212  type = IT_CD;
2213 
2214  return type;
2215 }
2216 
2217 // static method to get image type from the type name
2219 {
2221 
2222  if (name.toLower() == "front")
2223  type = IT_FRONTCOVER;
2224  else if (name.toLower() == "back")
2225  type = IT_BACKCOVER;
2226  else if (name.toLower() == "inlay")
2227  type = IT_INLAY;
2228  else if (name.toLower() == "cd")
2229  type = IT_CD;
2230  else if (name.toLower() == "artist")
2231  type = IT_ARTIST;
2232  else if (name.toLower() == "unknown")
2233  type = IT_UNKNOWN;
2234 
2235  return type;
2236 }
2237 
2238 void AlbumArtImages::addImage(const AlbumArtImage * const newImage)
2239 {
2240  // do we already have an image of this type?
2241  AlbumArtImage *image = nullptr;
2242 
2243  for (auto *item : qAsConst(m_imageList))
2244  {
2245  if (item->m_imageType == newImage->m_imageType
2246  && item->m_embedded == newImage->m_embedded)
2247  {
2248  image = item;
2249  break;
2250  }
2251  }
2252 
2253  if (!image)
2254  {
2255  // not found so just add it to the list
2256  image = new AlbumArtImage(newImage);
2257  m_imageList.push_back(image);
2258  }
2259  else
2260  {
2261  // we already have an image of this type so just update it with the new info
2262  image->m_filename = newImage->m_filename;
2263  image->m_imageType = newImage->m_imageType;
2264  image->m_embedded = newImage->m_embedded;
2265  image->m_description = newImage->m_description;
2266  image->m_hostname = newImage->m_hostname;
2267  }
2268 }
2269 
2272 {
2273  MusicMetadata::IdType trackID = ID_TO_ID(m_parent->ID());
2274  int directoryID = m_parent->getDirectoryId();
2275 
2276  // sanity check we have a valid songid and directoryid
2277  if (trackID == 0 || directoryID == -1)
2278  {
2279  LOG(VB_GENERAL, LOG_ERR, "AlbumArtImages: Asked to save to the DB but "
2280  "have invalid songid or directoryid");
2281  return;
2282  }
2283 
2285 
2286  // remove all albumart for this track from the db
2287  query.prepare("DELETE FROM music_albumart "
2288  "WHERE song_id = :SONGID "
2289  "OR (embedded = 0 AND directory_id = :DIRECTORYID)");
2290 
2291  query.bindValue(":SONGID", trackID);
2292  query.bindValue(":DIRECTORYID", directoryID);
2293 
2294  if (!query.exec())
2295  {
2296  MythDB::DBError("AlbumArtImages::dumpToDatabase - "
2297  "deleting existing albumart", query);
2298  }
2299 
2300  // now add the albumart to the db
2301  for (auto *image : qAsConst(m_imageList))
2302  {
2303  //TODO: for the moment just ignore artist images
2304  if (image->m_imageType == IT_ARTIST)
2305  continue;
2306 
2307  if (image->m_id > 0)
2308  {
2309  // re-use the same id this image had before
2310  query.prepare("INSERT INTO music_albumart ( albumart_id, "
2311  "filename, imagetype, song_id, directory_id, embedded, hostname ) "
2312  "VALUES ( :ID, :FILENAME, :TYPE, :SONGID, :DIRECTORYID, :EMBED, :HOSTNAME );");
2313  query.bindValue(":ID", image->m_id);
2314  }
2315  else
2316  {
2317  query.prepare("INSERT INTO music_albumart ( filename, "
2318  "imagetype, song_id, directory_id, embedded, hostname ) VALUES ( "
2319  ":FILENAME, :TYPE, :SONGID, :DIRECTORYID, :EMBED, :HOSTNAME );");
2320  }
2321 
2322  QFileInfo fi(image->m_filename);
2323  query.bindValue(":FILENAME", fi.fileName());
2324 
2325  query.bindValue(":TYPE", image->m_imageType);
2326  query.bindValue(":SONGID", image->m_embedded ? trackID : 0);
2327  query.bindValue(":DIRECTORYID", image->m_embedded ? 0 : directoryID);
2328  query.bindValue(":EMBED", image->m_embedded);
2329  query.bindValue(":HOSTNAME", image->m_hostname);
2330 
2331  if (!query.exec())
2332  {
2333  MythDB::DBError("AlbumArtImages::dumpToDatabase - "
2334  "add/update music_albumart", query);
2335  }
2336  else
2337  {
2338  if (image->m_id <= 0)
2339  image->m_id = query.lastInsertId().toInt();
2340  }
2341  }
2342 }
MythFormatTimeMs
QString MythFormatTimeMs(int msecs, const QString &fmt)
Format a milliseconds time value.
Definition: mythmiscutil.cpp:1232
MusicMetadata::getCompilationArtistId
int getCompilationArtistId()
Definition: musicmetadata.cpp:546
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:204
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:126
MusicMetadata::m_genreId
int m_genreId
Definition: musicmetadata.h:348
STREAMURLCOUNT
#define STREAMURLCOUNT
Definition: musicmetadata.h:76
MusicMetadata::getGenreId
int getGenreId()
Definition: musicmetadata.cpp:629
MythCoreContext::SendMessage
void SendMessage(const QString &message)
Definition: mythcorecontext.cpp:1526
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:203
MSqlQuery::bindValueNoNull
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:869
MusicMetadata::Filename
QString Filename(bool find=true)
Definition: musicmetadata.cpp:973
AlbumArtImage::m_imageType
ImageType m_imageType
Definition: musicmetadata.h:51
AllStream::isValidID
bool isValidID(MusicMetadata::IdType an_id)
Definition: musicmetadata.cpp:1745
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:825
AllStream::updateStream
void updateStream(MusicMetadata *mdata)
Definition: musicmetadata.cpp:1869
METADATA_INVALID_FILENAME
#define METADATA_INVALID_FILENAME
Definition: musicmetadata.h:73
MusicMetadata::incPlayCount
void incPlayCount()
Definition: musicmetadata.cpp:1205
MusicMetadata::LogoUrl
QString LogoUrl(void)
Definition: musicmetadata.h:274
MusicMetadata::Genre
QString Genre() const
Definition: musicmetadata.h:175
AllStream::addStream
void addStream(MusicMetadata *mdata)
Definition: musicmetadata.cpp:1816
AllStream::AllStream
AllStream(void)
Definition: musicmetadata.cpp:1731
getMythSortHelper
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
Definition: mythsorthelper.cpp:126
MusicMetadata::checkEmptyFields
void checkEmptyFields(void)
Definition: musicmetadata.cpp:868
kMSDontBlockInputDevs
@ kMSDontBlockInputDevs
avoid blocking LIRC & Joystick Menu
Definition: mythsystem.h:34
MusicMetadata::s_formatCompilationCdArtist
static QString s_formatCompilationCdArtist
Definition: musicmetadata.h:385
mythdb.h
MusicMetadata::m_hostname
QString m_hostname
Definition: musicmetadata.h:362
MythCoreContext::SendReceiveStringList
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Definition: mythcorecontext.cpp:1379
MythDate::as_utc
QDateTime as_utc(const QDateTime &old_dt)
Returns copy of QDateTime with TimeSpec set to UTC.
Definition: mythdate.cpp:23
MusicMetadata::m_description
QString m_description
Definition: musicmetadata.h:370
MusicMetadata::MetadataFormat
QString MetadataFormat(void)
Definition: musicmetadata.h:277
AllMusic::isValidID
bool isValidID(int an_id)
Definition: musicmetadata.cpp:1654
MusicMetadata::FormatArtist
QString FormatArtist()
Definition: musicmetadata.cpp:950
MusicMetadata::getAlbumArtImages
AlbumArtImages * getAlbumArtImages(void)
Definition: musicmetadata.cpp:1372
MusicMetadata::m_rating
int m_rating
Definition: musicmetadata.h:343
MusicMetadata::createFromID
static MusicMetadata * createFromID(int trackid)
Definition: musicmetadata.cpp:264
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:462
MusicMetadata::fillFieldList
static QStringList fillFieldList(const QString &field)
Definition: musicmetadata.cpp:1227
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:633
MetaIO::createTagger
static MetaIO * createTagger(const QString &filename)
Finds an appropriate tagger for the given file.
Definition: metaio.cpp:32
AlbumArtImages::getImageList
AlbumArtList * getImageList(void)
Definition: musicmetadata.h:533
MusicMetadata::MusicMetadata
MusicMetadata(QString lfilename="", QString lartist="", QString lcompilation_artist="", QString lalbum="", QString ltitle="", QString lgenre="", int lyear=0, int ltracknum=0, int llength=0, int lid=0, int lrating=0, int lplaycount=0, QDateTime llastplay=QDateTime(), QDateTime ldateadded=QDateTime(), bool lcompilation=false, QString lformat="")
Definition: musicmetadata.h:88
MusicMetadata::m_lyricsData
LyricsData * m_lyricsData
Definition: musicmetadata.h:358
MusicMetadata::m_urls
UrlList m_urls
Definition: musicmetadata.h:371
MusicMetadata::m_title
QString m_title
Definition: musicmetadata.h:331
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:602
AllStream::getMetadata
MusicMetadata * getMetadata(MusicMetadata::IdType an_id)
Definition: musicmetadata.cpp:1756
MusicMetadata::m_compilationArtistSort
QString m_compilationArtistSort
Definition: musicmetadata.h:328
MusicMetadata::setArtistAndTrackFormats
static void setArtistAndTrackFormats()
Definition: musicmetadata.cpp:811
AlbumArtImages::getImageTypeFromName
static ImageType getImageTypeFromName(const QString &name)
Definition: musicmetadata.cpp:2218
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:888
AllMusic::startLoading
bool startLoading(void)
Start loading metadata.
Definition: musicmetadata.cpp:1474
MusicMetadata::isRadio
bool isRadio(void) const
Definition: musicmetadata.h:223
mythcoreutil.h
MusicMetadata::m_artistSort
QString m_artistSort
Definition: musicmetadata.h:326
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
MythScreenStack
Definition: mythscreenstack.h:16
arg
arg(title).arg(filename).arg(doDelete))
MetaIO
Definition: metaio.h:18
MusicMetadata::ID
IdType ID() const
Definition: musicmetadata.h:217
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
MusicMetadata::m_albumArt
AlbumArtImages * m_albumArt
Definition: musicmetadata.h:356
STREAMUPDATEURL
#define STREAMUPDATEURL
Definition: musicmetadata.h:75
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MusicMetadata::m_length
int m_length
Definition: musicmetadata.h:342
IT_BACKCOVER
@ IT_BACKCOVER
Definition: musicmetadata.h:32
MusicMetadata::compare
bool compare(MusicMetadata *mdata) const
Definition: musicmetadata.cpp:156
MusicMetadata
Definition: musicmetadata.h:81
metaioflacvorbis.h
AlbumArtImages::guessImageType
static ImageType guessImageType(const QString &filename)
Definition: musicmetadata.cpp:2195
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:46
mythdirs.h
mythsorthelper.h
MusicMetadata::getLocalFilename
QString getLocalFilename(void)
try to find the track on the local file system
Definition: musicmetadata.cpp:1034
MusicMetadata::persist
void persist(void)
Definition: musicmetadata.cpp:184
MusicMetadata::Artist
QString Artist() const
Definition: musicmetadata.h:126
MusicMetadata::setEmbeddedAlbumArt
void setEmbeddedAlbumArt(AlbumArtList &albumart)
Definition: musicmetadata.cpp:1211
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &stackname)
Definition: mythmainwindow.cpp:309
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
MetadataLoadingThread
Definition: musicmetadata.h:402
MusicMetadata::m_format
QString m_format
Definition: musicmetadata.h:336
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
musicutils.h
mythprogressdialog.h
MusicMetadata::m_directoryId
int m_directoryId
Definition: musicmetadata.h:344
AlbumArtImages::getImage
AlbumArtImage * getImage(ImageType type)
Definition: musicmetadata.cpp:2120
MusicMetadata::m_formattedTitle
QString m_formattedTitle
Definition: musicmetadata.h:334
MusicMetadata::~MusicMetadata
~MusicMetadata()
Definition: musicmetadata.cpp:82
tmp
static guint32 * tmp
Definition: goom_core.cpp:30
AllMusic::getCDMetadata
MusicMetadata * getCDMetadata(int m_the_track)
Definition: musicmetadata.cpp:1716
UrlList
QString[STREAMURLCOUNT] UrlList
Definition: musicmetadata.h:78
MusicMetadata::getField
void getField(const QString &field, QString *data)
Definition: musicmetadata.cpp:1081
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MusicMetadata::m_changed
bool m_changed
Definition: musicmetadata.h:365
mythsystem.h
AllMusic::checkCDTrack
bool checkCDTrack(MusicMetadata *the_track)
Definition: musicmetadata.cpp:1708
MusicMetadata::m_tempPlayCount
int m_tempPlayCount
Definition: musicmetadata.h:353
MusicMetadata::formatReplaceSymbols
QString formatReplaceSymbols(const QString &format)
Definition: musicmetadata.cpp:858
MusicMetadata::Url
QString Url(uint index=0)
Definition: musicmetadata.cpp:670
MusicMetadata::Channel
QString Channel(void)
Definition: musicmetadata.h:265
MusicMetadata::m_playCount
int m_playCount
Definition: musicmetadata.h:352
MythCoreContext::IsMasterBackend
bool IsMasterBackend(void)
is this the actual MBE process
Definition: mythcorecontext.cpp:713
mythdate.h
AllMusic::AllMusic
AllMusic(void)
Definition: musicmetadata.cpp:1424
mythlogging.h
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:778
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
MusicMetadata::Description
QString Description(void)
Definition: musicmetadata.h:268
MythCoreContext::GetQLocale
QLocale GetQLocale(void)
Definition: mythcorecontext.cpp:1854
MusicMetadata::m_dateAdded
QDateTime m_dateAdded
Definition: musicmetadata.h:351
MusicMetadata::m_lastPlay
QDateTime m_lastPlay
Definition: musicmetadata.h:349
remotefile.h
MusicMetadata::m_year
int m_year
Definition: musicmetadata.h:337
MusicMetadata::getLyricsData
LyricsData * getLyricsData(void)
Definition: musicmetadata.cpp:1386
RT_Radio
@ RT_Radio
Definition: musicmetadata.h:62
AlbumArtScannerThread
Definition: musicmetadata.h:501
MusicMetadata::toMap
void toMap(InfoMap &metadataMap, const QString &prefix="")
Definition: musicmetadata.cpp:1099
ID_TO_ID
#define ID_TO_ID(x)
Definition: musicmetadata.h:70
MusicMetadata::s_formatCompilationFileTrack
static QString s_formatCompilationFileTrack
Definition: musicmetadata.h:384
operator==
bool operator==(MusicMetadata &a, MusicMetadata &b)
Definition: musicmetadata.cpp:49
RT_CD
@ RT_CD
Definition: musicmetadata.h:61
AllStream::~AllStream
~AllStream()
Definition: musicmetadata.cpp:1736
MusicMetadata::m_tempLastPlay
QDateTime m_tempLastPlay
Definition: musicmetadata.h:350
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
MusicMetadata::Language
QString Language(void)
Definition: musicmetadata.h:283
MusicMetadata::getAlbumArtFile
QString getAlbumArtFile(void)
Definition: musicmetadata.cpp:1269
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
MusicMetadata::getArtistId
int getArtistId()
Definition: musicmetadata.cpp:509
AllMusic::cleanOutThreads
bool cleanOutThreads()
Definition: musicmetadata.cpp:1448
MusicMetadata::getAlbumId
int getAlbumId()
Definition: musicmetadata.cpp:588
AllMusic::updateMetadata
bool updateMetadata(int an_id, MusicMetadata *the_track)
Definition: musicmetadata.cpp:1659
AlbumArtImages::getImageAt
AlbumArtImage * getImageAt(uint index)
Definition: musicmetadata.cpp:2152
MusicMetadata::operator=
MusicMetadata & operator=(const MusicMetadata &rhs)
Definition: musicmetadata.cpp:98
AlbumArtImages::scanForImages
void scanForImages(void)
Definition: musicmetadata.cpp:2038
MusicMetadata::m_channel
QString m_channel
Definition: musicmetadata.h:369
MusicMetadata::updateStreamList
static bool updateStreamList(void)
Definition: musicmetadata.cpp:325
AlbumArtImages::getTypeFilename
static QString getTypeFilename(ImageType type)
Definition: musicmetadata.cpp:2178
filename
QString filename
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:634
AlbumArtImages::findImages
void findImages(void)
Definition: musicmetadata.cpp:1922
MusicMetadata::m_artistId
int m_artistId
Definition: musicmetadata.h:345
AllMusic::addCDTrack
void addCDTrack(const MusicMetadata &the_track)
Definition: musicmetadata.cpp:1699
AllStream::removeStream
void removeStream(MusicMetadata *mdata)
Definition: musicmetadata.cpp:1852
MusicMetadata::getDirectoryId
int getDirectoryId()
Definition: musicmetadata.cpp:460
metaioavfcomment.h
RemoteFile::FindFile
static QString FindFile(const QString &filename, const QString &host, const QString &storageGroup, bool useRegex=false, bool allowFallback=false)
Search all BE's for a file in the give storage group.
Definition: remotefile.cpp:1283
storagegroup.h
MythUIBusyDialog
Definition: mythprogressdialog.h:37
metaiowavpack.h
MusicMetadata::setFilename
void setFilename(const QString &lfilename)
Definition: musicmetadata.cpp:967
MusicMetadata::m_trackCount
int m_trackCount
Definition: musicmetadata.h:339
MusicMetadata::m_fileSize
uint64_t m_fileSize
Definition: musicmetadata.h:364
LyricsData
Definition: lyricsdata.h:47
AlbumArtImages::getTypeName
static QString getTypeName(ImageType type)
Definition: musicmetadata.cpp:2161
AllMusic::getMetadata
MusicMetadata * getMetadata(int an_id)
Definition: musicmetadata.cpp:1646
uint
unsigned int uint
Definition: compat.h:140
IT_ARTIST
@ IT_ARTIST
Definition: musicmetadata.h:35
IT_CD
@ IT_CD
Definition: musicmetadata.h:33
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
MusicMetadata::m_discNum
int m_discNum
Definition: musicmetadata.h:340
MusicMetadata::m_compartistId
int m_compartistId
Definition: musicmetadata.h:346
AlbumArtImages::getImageByID
AlbumArtImage * getImageByID(int imageID)
Definition: musicmetadata.cpp:2131
MusicMetadata::m_compilation
bool m_compilation
Definition: musicmetadata.h:354
MusicMetadata::m_trackNum
int m_trackNum
Definition: musicmetadata.h:338
ONEHOURINMS
#define ONEHOURINMS
Definition: mythmiscutil.h:94
MusicMetadata::m_album
QString m_album
Definition: musicmetadata.h:329
kMSAutoCleanup
@ kMSAutoCleanup
automatically delete if backgrounded
Definition: mythsystem.h:43
MusicMetadata::s_formatCompilationCdTrack
static QString s_formatCompilationCdTrack
Definition: musicmetadata.h:386
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
AllMusic::resync
void resync()
resync our cache with the database
Definition: musicmetadata.cpp:1493
kMSRunBackground
@ kMSRunBackground
run child in the background
Definition: mythsystem.h:36
MythDate::kSimplify
@ kSimplify
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
AlbumArtImages::AlbumArtImages
AlbumArtImages(MusicMetadata *metadata, bool loadFromDB=true)
Definition: musicmetadata.cpp:1906
MusicMetadata::IdType
uint32_t IdType
Definition: musicmetadata.h:86
AlbumArtImage::m_hostname
QString m_hostname
Definition: musicmetadata.h:50
IT_UNKNOWN
@ IT_UNKNOWN
Definition: musicmetadata.h:30
AllMusic::~AllMusic
~AllMusic()
Definition: musicmetadata.cpp:1430
MusicMetadata::reloadMetadata
void reloadMetadata(void)
Definition: musicmetadata.cpp:437
MusicMetadata::dumpToDatabase
void dumpToDatabase(void)
Definition: musicmetadata.cpp:678
MusicMetadata::m_formattedArtist
QString m_formattedArtist
Definition: musicmetadata.h:333
lastUpdate
QDateTime lastUpdate(GrabberScript *script)
Definition: netutils.cpp:338
MusicMetadata::m_albumId
int m_albumId
Definition: musicmetadata.h:347
mythmiscutil.h
MusicMetadata::Hostname
QString Hostname(void)
Definition: musicmetadata.h:229
MythDate::kAddYear
@ kAddYear
Add year to string if not included.
Definition: mythdate.h:22
MusicMetadata::decRating
void decRating()
Definition: musicmetadata.cpp:1175
AlbumArtImages
Definition: musicmetadata.h:520
AlbumArtList
QList< AlbumArtImage * > AlbumArtList
Definition: musicmetadata.h:56
MetadataLoadingThread::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: musicmetadata.cpp:1415
dir
QDir dir
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1171
metaio.h
MythDate
Definition: mythdate.cpp:8
MusicMetadata::Format
QString Format() const
Definition: musicmetadata.h:235
kMSProcessEvents
@ kMSProcessEvents
process events while waiting
Definition: mythsystem.h:37
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
MusicMetadata::m_language
QString m_language
Definition: musicmetadata.h:375
MusicMetadata::m_metaFormat
QString m_metaFormat
Definition: musicmetadata.h:373
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:14
MusicMetadata::m_artist
QString m_artist
Definition: musicmetadata.h:325
MusicMetadata::Country
QString Country(void)
Definition: musicmetadata.h:280
AllMusic::clearCDData
void clearCDData(void)
Definition: musicmetadata.cpp:1684
AlbumArtImage
Definition: musicmetadata.h:40
AlbumArtImage::m_id
int m_id
Definition: musicmetadata.h:48
AllMusic::save
void save()
Check each MusicMetadata entry and save those that have changed (ratings, etc.)
Definition: musicmetadata.cpp:1674
MusicMetadata::m_albumSort
QString m_albumSort
Definition: musicmetadata.h:330
MusicMetadata::m_logoUrl
QString m_logoUrl
Definition: musicmetadata.h:372
MusicMetadata::m_broadcaster
QString m_broadcaster
Definition: musicmetadata.h:368
mythcontext.h
MusicMetadata::FormatTitle
QString FormatTitle()
Definition: musicmetadata.cpp:959
MusicMetadata::setField
void setField(const QString &field, const QString &data)
Definition: musicmetadata.cpp:1045
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:107
StorageGroup
Definition: storagegroup.h:12
MusicMetadata::s_formatNormalFileTrack
static QString s_formatNormalFileTrack
Definition: musicmetadata.h:379
MusicMetadata::m_genre
QString m_genre
Definition: musicmetadata.h:335
MusicMetadata::ensureSortFields
void ensureSortFields(void)
Definition: musicmetadata.cpp:896
metaioid3.h
metaiomp4.h
IT_FRONTCOVER
@ IT_FRONTCOVER
Definition: musicmetadata.h:31
thePrefix
static QString thePrefix
Definition: musicmetadata.cpp:47
MusicMetadata::Broadcaster
QString Broadcaster(void)
Definition: musicmetadata.h:262
MusicMetadata::setLastPlay
void setLastPlay()
Definition: musicmetadata.cpp:1199
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:16
MusicMetadata::setRepo
void setRepo(RepoType repo)
Definition: musicmetadata.h:219
MSqlQuery::numRowsAffected
int numRowsAffected() const
Definition: mythdbcon.h:206
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:856
MusicMetadata::s_formatCompilationFileArtist
static QString s_formatCompilationFileArtist
Definition: musicmetadata.h:383
MusicMetadata::reloadAlbumArtImages
void reloadAlbumArtImages(void)
Definition: musicmetadata.cpp:1380
gzipUncompress
QByteArray gzipUncompress(const QByteArray &data)
Definition: mythcoreutil.cpp:230
MythDownloadManager::GetLastModified
QDateTime GetLastModified(const QString &url)
Gets the Last Modified timestamp for a URI.
Definition: mythdownloadmanager.cpp:1554
MusicMetadata::setCompilationFormatting
void setCompilationFormatting(bool cd=false)
Definition: musicmetadata.cpp:910
MusicMetadata::incRating
void incRating()
Definition: musicmetadata.cpp:1184
lyricsdata.h
MusicMetadata::setID
void setID(IdType lid)
Definition: musicmetadata.h:218
AlbumArtImages::~AlbumArtImages
~AlbumArtImages()
Definition: musicmetadata.cpp:1913
MusicMetadata::m_compilationArtist
QString m_compilationArtist
Definition: musicmetadata.h:327
AllStream::loadStreams
void loadStreams(void)
Definition: musicmetadata.cpp:1767
kMSDontDisableDrawing
@ kMSDontDisableDrawing
avoid disabling UI drawing
Definition: mythsystem.h:35
mythdownloadmanager.h
IT_INLAY
@ IT_INLAY
Definition: musicmetadata.h:34
AlbumArtImage::m_description
QString m_description
Definition: musicmetadata.h:52
MusicMetadata::determineIfCompilation
bool determineIfCompilation(bool cd=false)
Definition: musicmetadata.cpp:849
MusicMetadata::createFromFilename
static MusicMetadata * createFromFilename(const QString &filename)
Definition: musicmetadata.cpp:228
MusicMetadata::m_actualFilename
QString m_actualFilename
Definition: musicmetadata.h:363
ID_TO_REPO
#define ID_TO_REPO(x)
Definition: musicmetadata.h:71
MusicMetadata::m_titleSort
QString m_titleSort
Definition: musicmetadata.h:332
operator!=
bool operator!=(MusicMetadata &a, MusicMetadata &b)
Definition: musicmetadata.cpp:54
mythmainwindow.h
MusicMetadata::saveHostname
void saveHostname(void)
Definition: musicmetadata.cpp:212
MusicMetadata::setUrl
void setUrl(const QString &url, uint index=0)
Definition: musicmetadata.cpp:664
AlbumArtImages::addImage
void addImage(const AlbumArtImage *newImage)
Definition: musicmetadata.cpp:2238
AlbumArtImages::dumpToDatabase
void dumpToDatabase(void)
saves or updates the image details in the DB
Definition: musicmetadata.cpp:2271
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:49
query
MSqlQuery query(MSqlQuery::InitCon())
MusicMetadata::m_id
IdType m_id
Definition: musicmetadata.h:360
MusicMetadata::m_filename
QString m_filename
Definition: musicmetadata.h:361
findIcon
META_PUBLIC QString findIcon(const QString &type, const QString &name, bool ignoreCache=false)
find an image for a artist or genre
MusicMetadata::getTagger
MetaIO * getTagger(void)
Definition: musicmetadata.cpp:1396
MythCoreContext::SaveSettingOnHost
bool SaveSettingOnHost(const QString &key, const QString &newValue, const QString &host)
Definition: mythcorecontext.cpp:909
ImageType
ImageType
Definition: musicmetadata.h:29
musicmetadata.h
AlbumArtImages::m_imageList
AlbumArtList m_imageList
Definition: musicmetadata.h:547
metaiooggvorbis.h
MusicMetadata::s_formatNormalFileArtist
static QString s_formatNormalFileArtist
Definition: musicmetadata.h:378
AlbumArtImages::getImageFilenames
QStringList getImageFilenames(void) const
Definition: musicmetadata.cpp:2142
MSqlQuery::at
int at(void) const
Definition: mythdbcon.h:210
MusicMetadata::m_country
QString m_country
Definition: musicmetadata.h:374
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:356
MusicMetadata::m_discCount
int m_discCount
Definition: musicmetadata.h:341
AlbumArtImages::m_parent
MusicMetadata * m_parent
Definition: musicmetadata.h:546
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:916
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:161
MusicMetadata::s_formatNormalCdArtist
static QString s_formatNormalCdArtist
Definition: musicmetadata.h:380
MusicMetadata::s_formatNormalCdTrack
static QString s_formatNormalCdTrack
Definition: musicmetadata.h:381
AlbumArtImage::m_filename
QString m_filename
Definition: musicmetadata.h:49
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
AlbumArtImage::m_embedded
bool m_embedded
Definition: musicmetadata.h:53
MythSystem::Create
static MythSystem * Create(const QStringList &args, uint flags=kMSNone, const QString &startPath=QString(), Priority cpuPriority=kInheritPriority, Priority diskPriority=kInheritPriority)
Definition: mythsystem.cpp:203
build_compdb.paths
paths
Definition: build_compdb.py:13