MythTV  master
musicutils.cpp
Go to the documentation of this file.
1 // c/c++
2 #include <iostream>
3 
4 // qt
5 #include <QFile>
6 #include <QRegularExpression>
7 #include <QDir>
8 
9 // mythtv
10 #include <mythdirs.h>
11 #include <mythlogging.h>
12 #include <mythcorecontext.h>
13 #include <remotefile.h>
14 
15 extern "C" {
16 #include <libavformat/avformat.h>
17 #include <libavcodec/avcodec.h>
18 }
19 
20 // libmythmetadata
21 #include "musicmetadata.h"
22 #include "musicutils.h"
23 
24 const static QRegularExpression badChars1 { R"((/|\\|:|'|"|\?|\|))" };
25 const static QRegularExpression badChars2 { R"((/|\\|:|'|\,|\!|\(|\)|"|\?|\|))" };
26 
27 QString fixFilename(const QString &filename)
28 {
29  QString ret = filename;
30  return ret.replace(badChars1, "_");
31 }
32 
33 static QMap<QString, QString> iconMap;
34 QString findIcon(const QString &type, const QString &name, bool ignoreCache)
35 {
36  LOG(VB_FILE, LOG_INFO, QString("findicon: looking for type: %1, name: %2").arg(type).arg(name));
37 
38  if (!ignoreCache)
39  {
40  QMap<QString, QString>::iterator i = iconMap.find(type + name);
41  if (i != iconMap.end())
42  {
43  LOG(VB_FILE, LOG_INFO, QString("findicon: found in cache %1").arg(i.value()));
44  return i.value();
45  }
46  }
47 
48  QString cleanName = fixFilename(name) + '.';
49  cleanName = '^' + QRegularExpression::escape(cleanName);
50  QString file = QString("/Icons/%1/%2").arg(type).arg(cleanName);
51  QString imageExtensions = "(jpg|jpeg|png|gif)";
52  QStringList fileList;
53 
54  fileList = RemoteFile::FindFileList(file + imageExtensions, gCoreContext->GetMasterHostName(), "MusicArt", true, true);
55  if (!fileList.isEmpty())
56  {
57  LOG(VB_FILE, LOG_INFO, QString("findicon: found %1 icons using %2").arg(fileList.size()).arg(fileList[0]));
58  iconMap.insert(type + name, fileList[0]);
59  return fileList[0];
60  }
61 
62  iconMap.insert(type + name, QString());
63 
64  LOG(VB_FILE, LOG_INFO, QString("findicon: not found type: %1, name: %2").arg(type).arg(name));
65 
66  return QString();
67 }
68 
69 QString fixFileToken_sl(QString token)
70 {
71  // this version doesn't remove fwd-slashes so we can
72  // pick them up later and create directories as required
73  token.replace(QRegularExpression(R"((\\|:|'|"|\?|\|))"), QString("_"));
74  return token;
75 }
76 
77 QString filenameFromMetadata(MusicMetadata *track)
78 {
79  QString filename;
80  QString fntempl = gCoreContext->GetSetting("FilenameTemplate");
81  bool no_ws = gCoreContext->GetBoolSetting("NoWhitespace", false);
82 
83  QRegularExpression rx_ws("\\s{1,}");
84  QRegularExpression rx("^(.*?)(GENRE|ARTIST|ALBUM|TRACK|TITLE|YEAR)");
85  auto match = rx.match(fntempl);
86  while (match.hasMatch())
87  {
88  filename += match.captured(1);
89 
90  if ((match.captured(2) == "GENRE") &&
91  (!track->Genre().isEmpty()))
92  filename += fixFilename(track->Genre());
93  else if ((match.captured(2) == "ARTIST") &&
94  (!track->FormatArtist().isEmpty()))
95  filename += fixFilename(track->FormatArtist());
96  else if ((match.captured(2) == "ALBUM") &&
97  (!track->Album().isEmpty()))
98  filename += fixFilename(track->Album());
99  else if ((match.captured(2) == "TRACK") && (track->Track() >= 0))
100  filename += fixFilename(QString("%1").arg(track->Track(), 2,10,QChar('0')));
101  else if ((match.captured(2) == "TITLE") &&
102  (!track->FormatTitle().isEmpty()))
103  filename += fixFilename(track->FormatTitle());
104  else if ((match.captured(2) == "YEAR") && (track->Year() >= 0))
105  filename += fixFilename(QString::number(track->Year(), 10));
106  fntempl.remove(0, match.capturedLength());
107  match = rx.match(fntempl);
108  }
109 
110  if (no_ws)
111  filename.replace(rx_ws, "_");
112 
113 
114  if (filename == "" || filename.length() > FILENAME_MAX)
115  {
116  QString tempstr = QString::number(track->Track(), 10);
117  tempstr += " - " + track->FormatTitle();
118  filename = fixFilename(tempstr);
119  LOG(VB_GENERAL, LOG_ERR, "Invalid file storage definition.");
120  }
121 
122  return filename;
123 }
124 
125 bool isNewTune(const QString& artist, const QString& album, const QString& title)
126 {
127 
128  QString matchartist = artist;
129  QString matchalbum = album;
130  QString matchtitle = title;
131 
132  if (! matchartist.isEmpty())
133  matchartist.replace(badChars2, QString("_"));
134 
135  if (! matchalbum.isEmpty())
136  matchalbum.replace(badChars2, QString("_"));
137 
138  if (! matchtitle.isEmpty())
139  matchtitle.replace(badChars2, QString("_"));
140 
141  MSqlQuery query(MSqlQuery::InitCon());
142  QString queryString("SELECT filename, artist_name,"
143  " album_name, name, song_id "
144  "FROM music_songs "
145  "LEFT JOIN music_artists"
146  " ON music_songs.artist_id=music_artists.artist_id "
147  "LEFT JOIN music_albums"
148  " ON music_songs.album_id=music_albums.album_id "
149  "WHERE artist_name LIKE :ARTIST "
150  "AND album_name LIKE :ALBUM "
151  "AND name LIKE :TITLE "
152  "ORDER BY artist_name, album_name,"
153  " name, song_id, filename");
154 
155  query.prepare(queryString);
156 
157  query.bindValue(":ARTIST", matchartist);
158  query.bindValue(":ALBUM", matchalbum);
159  query.bindValue(":TITLE", matchtitle);
160 
161  if (!query.exec() || !query.isActive())
162  {
163  MythDB::DBError("Search music database", query);
164  return true;
165  }
166 
167  return query.size() <= 0;
168 }
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
findIcon
QString findIcon(const QString &type, const QString &name, bool ignoreCache)
find an image for a artist or genre
Definition: musicutils.cpp:34
MythCoreContext::GetMasterHostName
QString GetMasterHostName(void)
Definition: mythcorecontext.cpp:832
MusicMetadata::Genre
QString Genre() const
Definition: musicmetadata.h:175
MusicMetadata::FormatArtist
QString FormatArtist()
Definition: musicmetadata.cpp:942
MusicMetadata::Track
int Track() const
Definition: musicmetadata.h:199
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MusicMetadata
Definition: musicmetadata.h:80
build_compdb.file
file
Definition: build_compdb.py:55
mythdirs.h
RemoteFile::FindFileList
static QStringList FindFileList(const QString &filename, const QString &host, const QString &storageGroup, bool useRegex=false, bool allowFallback=false)
Search all BE's for files in the give storage group.
Definition: remotefile.cpp:1303
musicutils.h
mythlogging.h
isNewTune
META_PUBLIC bool isNewTune(const QString &artist, const QString &album, const QString &title)
try to find a track in the db using the given artist, album and title
remotefile.h
fixFilename
QString fixFilename(const QString &filename)
remove any bad filename characters
Definition: musicutils.cpp:27
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:536
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:194
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MusicMetadata::Album
QString Album() const
Definition: musicmetadata.h:150
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:931
filenameFromMetadata
META_PUBLIC QString filenameFromMetadata(MusicMetadata *track)
create a filename using the template in the settings and a MusicMetadata object
badChars1
const static QRegularExpression badChars1
Definition: musicutils.cpp:24
mythcorecontext.h
iconMap
static QMap< QString, QString > iconMap
Definition: musicutils.cpp:33
fixFileToken_sl
QString fixFileToken_sl(QString token)
remove any bad filename characters (leaving '/' untouched)
Definition: musicutils.cpp:69
MusicMetadata::FormatTitle
QString FormatTitle()
Definition: musicmetadata.cpp:951
hardwareprofile.distros.shared.html.escape
def escape(tagless_text)
Definition: html.py:27
build_compdb.filename
filename
Definition: build_compdb.py:21
musicmetadata.h
badChars2
const static QRegularExpression badChars2
Definition: musicutils.cpp:25
MusicMetadata::Year
int Year() const
Definition: musicmetadata.h:196
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:923