MythTV  master
musicmetadata.h
Go to the documentation of this file.
1 #ifndef MUSICMETADATA_H_
2 #define MUSICMETADATA_H_
3 
4 // C/C++
5 #include <cstdint>
6 #include <utility>
7 
8 
9 // qt
10 #include <QCoreApplication>
11 #include <QDateTime>
12 #include <QImage>
13 #include <QMap>
14 #include <QMetaType>
15 #include <QStringList>
16 
17 // mythtv
18 #include "mythtypes.h"
19 #include "mythmetaexp.h"
20 #include "mthread.h"
21 #include "mythcorecontext.h"
22 
23 class AllMusic;
24 class AlbumArtImages;
25 class LyricsData;
26 class MetaIO;
27 
29 {
37 };
38 
40 {
41  public:
42  AlbumArtImage(void) :
43  m_filename(""), m_hostname(""), m_description("") {}
45  m_id(image->m_id), m_filename(image->m_filename),
46  m_hostname(image->m_hostname), m_imageType(image->m_imageType),
47  m_description(image->m_description), m_embedded(image->m_embedded) {}
48  int m_id {0};
49  QString m_filename;
50  QString m_hostname;
51  ImageType m_imageType {IT_UNKNOWN};
52  QString m_description;
53  bool m_embedded {false};
54 };
55 
56 using AlbumArtList = QList<AlbumArtImage*>;
57 
59 {
61  RT_CD = 1,
63 };
64 
65 #define METADATA_BITS_FOR_REPO 8
66 #define METADATA_REPO_SHIFT 24
67 #define METADATA_REPO_MASK 0xff000000
68 #define METADATA_ID_MASK 0x00ffffff
69 
70 #define ID_TO_ID(x) x & METADATA_ID_MASK;
71 #define ID_TO_REPO(x) x >> METADATA_REPO_SHIFT
72 
73 #define METADATA_INVALID_FILENAME "**NOT FOUND**"
74 
75 #define STREAMUPDATEURL "https://services.mythtv.org/music/data/?data=streams"
76 #define STREAMURLCOUNT 5
77 
78 using UrlList = QString[STREAMURLCOUNT];
79 
81 {
82  Q_DECLARE_TR_FUNCTIONS(MusicMetadata);
83 
84  public:
85 
86  using IdType = uint32_t;
87 
88  explicit MusicMetadata(QString lfilename = "", QString lartist = "", QString lcompilation_artist = "",
89  QString lalbum = "", QString ltitle = "", QString lgenre = "",
90  int lyear = 0, int ltracknum = 0, int llength = 0, int lid = 0,
91  int lrating = 0, int lplaycount = 0, QDateTime llastplay = QDateTime(),
92  QDateTime ldateadded = QDateTime(), bool lcompilation = false, QString lformat = "")
93  : m_artist(std::move(lartist)),
94  m_compilationArtist(std::move(lcompilation_artist)),
95  m_album(std::move(lalbum)),
96  m_title(std::move(ltitle)),
97  m_genre(std::move(lgenre)),
98  m_format(std::move(lformat)),
99  m_year(lyear),
100  m_trackNum(ltracknum),
101  m_length(llength),
102  m_rating(lrating),
103  m_lastPlay(std::move(llastplay)),
104  m_dateAdded(std::move(ldateadded)),
105  m_playCount(lplaycount),
106  m_compilation(lcompilation),
107  m_id(lid),
108  m_filename(std::move(lfilename))
109  {
110  checkEmptyFields();
111  ensureSortFields();
112  }
113 
114  MusicMetadata(int lid, QString lbroadcaster, QString lchannel, QString ldescription, UrlList lurls, QString llogourl,
115  QString lgenre, QString lmetaformat, QString lcountry, QString llanguage, QString lformat);
116 
117  ~MusicMetadata();
118 
120  {
121  *this = other;
122  m_changed = false;
123  }
124 
125  MusicMetadata& operator=(const MusicMetadata &rhs);
126 
127  QString Artist() const { return m_artist; }
128  QString ArtistSort() const { return m_artistSort; }
129  void setArtist(const QString &lartist,
130  const QString &lartist_sort = nullptr)
131  {
132  m_artist = lartist;
133  m_artistSort = lartist_sort;
134  m_formattedArtist.clear(); m_formattedTitle.clear();
135  ensureSortFields();
136  }
137 
138  QString CompilationArtist() const { return m_compilationArtist; }
139  QString CompilationArtistSort() const { return m_compilationArtistSort; }
140  void setCompilationArtist(const QString &lcompilation_artist,
141  const QString &lcompilation_artist_sort = nullptr)
142  {
143  m_compilationArtist = lcompilation_artist;
144  m_compilationArtistSort = lcompilation_artist_sort;
145  m_formattedArtist.clear(); m_formattedTitle.clear();
146  ensureSortFields();
147  }
148 
149  QString Album() const { return m_album; }
150  QString AlbumSort() const { return m_albumSort; }
151  void setAlbum(const QString &lalbum,
152  const QString &lalbum_sort = nullptr)
153  {
154  m_album = lalbum;
155  m_albumSort = lalbum_sort;
156  m_formattedArtist.clear(); m_formattedTitle.clear();
157  ensureSortFields();
158  }
159 
160  QString Title() const { return m_title; }
161  QString TitleSort() const { return m_titleSort; }
162  void setTitle(const QString &ltitle,
163  const QString &ltitle_sort = nullptr)
164  {
165  m_title = ltitle;
166  m_titleSort = ltitle_sort;
167  ensureSortFields();
168  }
169 
170  QString FormatArtist();
171  QString FormatTitle();
172 
173  QString Genre() const { return m_genre; }
174  void setGenre(const QString &lgenre) { m_genre = lgenre; }
175 
176  void setDirectoryId(int ldirectoryid) { m_directoryId = ldirectoryid; }
177  int getDirectoryId();
178 
179  void setArtistId(int lartistid) { m_artistId = lartistid; }
180  int getArtistId();
181 
182  void setAlbumId(int lalbumid) { m_albumId = lalbumid; }
183  int getAlbumId();
184 
185  void setGenreId(int lgenreid) { m_genreId = lgenreid; }
186  int getGenreId();
187 
188  int Year() const { return m_year; }
189  void setYear(int lyear) { m_year = lyear; }
190 
191  int Track() const { return m_trackNum; }
192  void setTrack(int ltrack) { m_trackNum = ltrack; }
193 
194  int GetTrackCount() const { return m_trackCount; }
195  void setTrackCount(int ltrackcount) { m_trackCount = ltrackcount; }
196 
197  int Length() const { return m_length; }
198  void setLength(int llength) { m_length = llength; }
199 
200  int DiscNumber() const {return m_discNum;}
201  void setDiscNumber(int discnum) { m_discNum = discnum; }
202 
203  int DiscCount() const {return m_discCount;}
204  void setDiscCount(int disccount) { m_discCount = disccount; }
205 
206  int Playcount() const { return m_playCount; }
207  void setPlaycount(int lplaycount) { m_playCount = lplaycount; }
208 
209  IdType ID() const { return m_id; }
210  void setID(IdType lid) { m_id = lid; }
211  void setRepo(RepoType repo) { m_id = (m_id & METADATA_ID_MASK) | (repo << METADATA_REPO_SHIFT); }
212 
213  bool isCDTrack(void) const { return ID_TO_REPO(m_id) == RT_CD; }
214  bool isDBTrack(void) const { return ID_TO_REPO(m_id) == RT_Database; }
215  bool isRadio(void) const { return ID_TO_REPO(m_id) == RT_Radio; }
216 
217  QString Filename(bool find = true);
218  void setFilename(const QString &lfilename);
219  QString getLocalFilename(void);
220 
221  QString Hostname(void) { return m_hostname; }
222  void setHostname(const QString &host) { m_hostname = host; }
223 
224  uint64_t FileSize() const { return m_fileSize; }
225  void setFileSize(uint64_t lfilesize) { m_fileSize = lfilesize; }
226 
227  QString Format() const { return m_format; }
228  void setFormat(const QString &lformat) { m_format = lformat; }
229 
230  int Rating() const { return m_rating; }
231  void decRating();
232  void incRating();
233  void setRating(int lrating) { m_rating = lrating; }
234 
235  QDateTime LastPlay() const { return m_lastPlay; }
236  void setLastPlay();
237  void setLastPlay(const QDateTime& lastPlay);
238 
239  int PlayCount() const { return m_playCount; }
240  void incPlayCount();
241 
242  // track is part of a compilation album
243  bool Compilation() const { return m_compilation; }
244  void setCompilation(bool state)
245  {
246  m_compilation = state;
247  m_formattedArtist.clear();
248  m_formattedTitle.clear();
249  }
250  bool determineIfCompilation(bool cd = false);
251 
252  // for radio streams
253  void setBroadcaster(const QString &broadcaster) { m_broadcaster = broadcaster; }
254  QString Broadcaster(void) { return m_broadcaster; }
255 
256  void setChannel(const QString &channel) { m_channel = channel; }
257  QString Channel(void) { return m_channel; }
258 
259  void setDescription(const QString &description) { m_description = description; }
260  QString Description(void) { return m_description; }
261 
262  void setUrl(const QString &url, uint index = 0);
263  QString Url(uint index = 0);
264 
265  void setLogoUrl(const QString &logourl) { m_logoUrl = logourl; }
266  QString LogoUrl(void) { return m_logoUrl; }
267 
268  void setMetadataFormat(const QString &metaformat) { m_metaFormat = metaformat; }
269  QString MetadataFormat(void) { return m_metaFormat; }
270 
271  void setCountry(const QString &country) { m_country = country; }
272  QString Country(void) { return m_country; }
273 
274  void setLanguage(const QString &language) { m_language = language; }
275  QString Language(void) { return m_language; }
276 
277  void setEmbeddedAlbumArt(AlbumArtList &albumart);
278 
279  void reloadMetadata(void);
280  void dumpToDatabase(void);
281  void setField(const QString &field, const QString &data);
282  void getField(const QString& field, QString *data);
283  void toMap(InfoMap &metadataMap, const QString &prefix = "");
284 
285  void persist(void);
286 
287  bool hasChanged(void) const { return m_changed; }
288 
289  bool compare(MusicMetadata *mdata) const;
290 
291  // static functions
292  static MusicMetadata *createFromFilename(const QString &filename);
293  static MusicMetadata *createFromID(int trackid);
294  static void setArtistAndTrackFormats();
295  static QStringList fillFieldList(const QString& field);
296  static bool updateStreamList(void);
297 
298  // this looks for any image available - preferring a front cover if available
299  QString getAlbumArtFile(void);
300  // this looks only for the given image type
301  QString getAlbumArtFile(ImageType type);
302 
303  AlbumArtImages *getAlbumArtImages(void);
304  void reloadAlbumArtImages(void);
305 
306  LyricsData *getLyricsData(void);
307 
308  MetaIO *getTagger(void);
309 
310  private:
311  void setCompilationFormatting(bool cd = false);
312  QString formatReplaceSymbols(const QString &format);
313  void checkEmptyFields(void);
314  void ensureSortFields(void);
315  void saveHostname(void);
316 
317  QString m_artist;
318  QString m_artistSort;
321  QString m_album;
322  QString m_albumSort;
323  QString m_title;
324  QString m_titleSort;
327  QString m_genre;
328  QString m_format;
329  int m_year {0};
330  int m_trackNum {0};
331  int m_trackCount {0};
332  int m_discNum {0};
333  int m_discCount {0};
334  int m_length {0};
335  int m_rating {0};
336  int m_directoryId {-1};
337  int m_artistId {-1};
338  int m_compartistId {-1};
339  int m_albumId {-1};
340  int m_genreId {-1};
341  QDateTime m_lastPlay;
342  QDateTime m_tempLastPlay;
343  QDateTime m_dateAdded;
344  int m_playCount {0};
345  int m_tempPlayCount {0};
346  bool m_compilation {false};
347 
348  AlbumArtImages *m_albumArt {nullptr};
349 
350  LyricsData *m_lyricsData {nullptr};
351 
352  IdType m_id {0};
353  QString m_filename; // file name as stored in the DB
354  QString m_hostname; // host where file is located as stored in the DB
355  QString m_actualFilename; // actual URL of the file if found
356  uint64_t m_fileSize {0};
357  bool m_changed {false};
358 
359  // radio stream stuff
360  QString m_broadcaster;
361  QString m_channel;
362  QString m_description;
364  QString m_logoUrl;
365  QString m_metaFormat;
366  QString m_country;
367  QString m_language;
368 
369  // Various formatting strings
370  static QString s_formatNormalFileArtist;
371  static QString s_formatNormalFileTrack;
372  static QString s_formatNormalCdArtist;
373  static QString s_formatNormalCdTrack;
374 
379 };
380 
383 
386 
390 
391 //---------------------------------------------------------------------------
392 
394 {
395 
396  public:
397 
398  explicit MetadataLoadingThread(AllMusic *parent_ptr)
399  : MThread("MetadataLoading"), m_parent(parent_ptr) {}
400  void run() override; // MThread
401 
402  private:
403 
404  AllMusic *m_parent {nullptr};
405 };
406 
407 //---------------------------------------------------------------------------
408 
410 {
411  Q_DECLARE_TR_FUNCTIONS(AllMusic);
412 
413  public:
414 
415  AllMusic(void);
416  ~AllMusic();
417 
418  MusicMetadata* getMetadata(int an_id);
419  bool updateMetadata(int an_id, MusicMetadata *the_track);
420  int count() const { return m_numPcs; }
421  int countLoaded() const { return m_numLoaded; }
422  void save();
423  bool startLoading(void);
424  void resync(); // After a CD rip, for example
425 
426  // cd stuff
427  void clearCDData(void);
428  void addCDTrack(const MusicMetadata &the_track);
429  bool checkCDTrack(MusicMetadata *the_track);
430  MusicMetadata* getCDMetadata(int m_the_track);
431  QString getCDTitle(void) const { return m_cdTitle; }
432  void setCDTitle(const QString &a_title) { m_cdTitle = a_title; }
433  int getCDTrackCount(void) const { return m_cdData.count(); }
434 
435  bool doneLoading() const { return m_doneLoading; }
436  bool cleanOutThreads();
437 
438  MetadataPtrList *getAllMetadata(void) { return &m_allMusic; }
439  MetadataPtrList *getAllCDMetadata(void) { return &m_cdData; }
440 
441  bool isValidID(int an_id);
442 
443  private:
445 
446  int m_numPcs {0};
447  int m_numLoaded {0};
448 
449  using MusicMap = QMap<int, MusicMetadata*>;
451 
452  // cd stuff
453  MetadataPtrList m_cdData; // More than one cd player?
454  QString m_cdTitle;
455 
456  MetadataLoadingThread *m_metadataLoader {nullptr};
457  bool m_doneLoading {false};
458 
459  int m_playCountMin {0};
460  int m_playCountMax {0};
461 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
462  double m_lastPlayMin {0.0};
463  double m_lastPlayMax {0.0};
464 #else
465  qint64 m_lastPlayMin {0};
466  qint64 m_lastPlayMax {0};
467 #endif
468 };
469 
470 using StreamList = QList<MusicMetadata*>;
471 
473 {
474  public:
475 
476  AllStream(void);
477  ~AllStream();
478 
479  void loadStreams(void);
480 
481  bool isValidID(MusicMetadata::IdType an_id);
482 
483  MusicMetadata* getMetadata(MusicMetadata::IdType an_id);
484 
485  StreamList *getStreams(void) { return &m_streamList; }
486 
487  void addStream(MusicMetadata *mdata);
488  void removeStream(MusicMetadata *mdata);
489  void updateStream(MusicMetadata *mdata);
490 
491  private:
493 };
494 
495 //----------------------------------------------------------------------------
496 
498 {
499  public:
500  explicit AlbumArtScannerThread(QStringList strList) :
501  MThread("AlbumArtScanner"), m_strList(std::move(strList)) {}
502 
503  void run() override // MThread
504  {
505  RunProlog();
507  RunEpilog();
508  }
509 
510  QStringList getResult(void) { return m_strList; }
511 
512  private:
513  QStringList m_strList;
514 };
515 
517 {
518  Q_DECLARE_TR_FUNCTIONS(AlbumArtImages);
519 
520  public:
521  explicit AlbumArtImages(MusicMetadata *metadata, bool loadFromDB = true);
522  ~AlbumArtImages();
523 
524  void scanForImages(void);
525  void addImage(const AlbumArtImage &newImage);
526  uint getImageCount() { return m_imageList.size(); }
527  AlbumArtImage *getImage(ImageType type);
528  AlbumArtImage *getImageByID(int imageID);
529  QStringList getImageFilenames(void) const;
530  AlbumArtList *getImageList(void) { return &m_imageList; }
531  AlbumArtImage *getImageAt(uint index);
532 
533  void dumpToDatabase(void);
534 
535  static ImageType guessImageType(const QString &filename);
536  static QString getTypeName(ImageType type);
537  static QString getTypeFilename(ImageType type);
538  static ImageType getImageTypeFromName(const QString &name);
539 
540  private:
541  void findImages(void);
542 
543  MusicMetadata *m_parent {nullptr};
545 };
546 
548 
549 #endif
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
QList< AlbumArtImage * > AlbumArtList
Definition: musicmetadata.h:56
#define ID_TO_REPO(x)
Definition: musicmetadata.h:71
void setDiscCount(int disccount)
bool hasChanged(void) const
int getCDTrackCount(void) const
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
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
QString[STREAMURLCOUNT] UrlList
Definition: musicmetadata.h:78
QString m_compilationArtistSort
int DiscNumber() const
static QString s_formatNormalFileArtist
void setGenreId(int lgenreid)
void setTrack(int ltrack)
bool isRadio(void) const
static QString s_formatCompilationCdTrack
void setDirectoryId(int ldirectoryid)
QStringList getResult(void)
uint getImageCount()
void setYear(int lyear)
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QString LogoUrl(void)
QDateTime m_lastPlay
QString Language(void)
QString m_titleSort
uint32_t IdType
Definition: musicmetadata.h:86
QString Genre() const
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)
QString Hostname(void)
int GetTrackCount() const
QString m_actualFilename
void setLength(int llength)
RepoType
Definition: musicmetadata.h:58
void setBroadcaster(const QString &broadcaster)
void setLanguage(const QString &language)
bool operator!=(MusicMetadata &a, MusicMetadata &b)
QString m_description
Definition: musicmetadata.h:52
QString CompilationArtistSort() const
void setDiscNumber(int discnum)
QString m_filename
QString ArtistSort() const
QString MetadataFormat(void)
void setCDTitle(const QString &a_title)
int Length() const
uint64_t FileSize() const
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString m_formattedTitle
QString Country(void)
void setLogoUrl(const QString &logourl)
QDateTime m_dateAdded
AlbumArtList * getImageList(void)
#define STREAMURLCOUNT
Definition: musicmetadata.h:76
QString AlbumSort() const
QString m_artistSort
int Rating() const
int PlayCount() const
QDateTime m_tempLastPlay
void setHostname(const QString &host)
AlbumArtList m_imageList
QString m_hostname
Definition: musicmetadata.h:50
MusicMetadata(const MusicMetadata &other)
Definition: metaio.h:17
bool isCDTrack(void) const
QList< MusicMetadata * > StreamList
static QString s_formatCompilationCdArtist
QString m_compilationArtist
void setCompilation(bool state)
QString m_format
QString Artist() const
bool isDBTrack(void) const
MetadataLoadingThread(AllMusic *parent_ptr)
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
QString Channel(void)
void setArtistId(int lartistid)
QString m_language
QString m_metaFormat
#define META_PUBLIC
Definition: mythmetaexp.h:9
void setAlbumId(int lalbumid)
QString m_filename
Definition: musicmetadata.h:49
QString m_logoUrl
StreamList m_streamList
#define METADATA_REPO_SHIFT
Definition: musicmetadata.h:66
IdType ID() const
void setChannel(const QString &channel)
void setAlbum(const QString &lalbum, const QString &lalbum_sort=nullptr)
void setRating(int lrating)
QList< MusicMetadata * > MetadataPtrList
int Track() const
MusicMap m_musicMap
AlbumArtScannerThread(QStringList strList)
void setRepo(RepoType repo)
unsigned int uint
Definition: compat.h:140
QString Album() const
QString m_channel
QString m_hostname
AlbumArtImage(void)
Definition: musicmetadata.h:42
StreamList * getStreams(void)
void setFormat(const QString &lformat)
void setTitle(const QString &ltitle, const QString &ltitle_sort=nullptr)
QString m_formattedArtist
void setArtist(const QString &lartist, const QString &lartist_sort=nullptr)
QString Format() const
QString m_description
AlbumArtImage(AlbumArtImage *image)
Definition: musicmetadata.h:44
QString m_artist
QString TitleSort() const
bool Compilation() const
Q_DECLARE_METATYPE(ImageType)
bool doneLoading() const
static QString s_formatNormalCdArtist
QString m_albumSort
int Year() const
QString Description(void)
#define METADATA_ID_MASK
Definition: musicmetadata.h:68
static QString s_formatNormalCdTrack
static QString s_formatCompilationFileTrack
QString Title() const
void setPlaycount(int lplaycount)
MetadataPtrList m_allMusic
void setFileSize(uint64_t lfilesize)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
MetadataPtrList m_cdData
static QString s_formatCompilationFileArtist
void setMetadataFormat(const QString &metaformat)
void setDescription(const QString &description)
QMap< int, MusicMetadata * > MusicMap
QDateTime LastPlay() const
ImageType
Definition: musicmetadata.h:28
QString CompilationArtist() const
int countLoaded() const
QString getCDTitle(void) const
QString m_broadcaster
bool operator==(MusicMetadata &a, MusicMetadata &b)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
QString m_country
int Playcount() const
int DiscCount() const
void setTrackCount(int ltrackcount)
MetadataPtrList * getAllMetadata(void)
QString Broadcaster(void)
void setCompilationArtist(const QString &lcompilation_artist, const QString &lcompilation_artist_sort=nullptr)
int count() const
static QString s_formatNormalFileTrack
MetadataPtrList * getAllCDMetadata(void)
QString m_cdTitle
void setID(IdType lid)
void setCountry(const QString &country)
void setGenre(const QString &lgenre)