MythTV  master
playlistcontainer.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <utility>
3 
4 // MythTV
5 #include <libmyth/mythcontext.h>
6 #include <libmythbase/compat.h>
7 #include <libmythbase/mythdb.h>
9 
10 // mythmusic
11 #include "playlist.h"
12 #include "playlistcontainer.h"
13 
15 {
16  RunProlog();
17  while (!m_allMusic->doneLoading())
18  {
19  usleep(250ms); // cppcheck-suppress usleepCalled
20  }
21  m_parent->load();
22  RunEpilog();
23 }
24 
25 #define LOC QString("PlaylistContainer: ")
26 #define LOC_WARN QString("PlaylistContainer, Warning: ")
27 #define LOC_ERR QString("PlaylistContainer, Error: ")
28 
30  m_playlistsLoader(new PlaylistLoadingThread(this, all_music)),
31  m_myHost(gCoreContext->GetHostName()),
32 
33  m_ratingWeight( gCoreContext->GetNumSetting("IntelliRatingWeight", 2)),
34  m_playCountWeight(gCoreContext->GetNumSetting("IntelliPlayCountWeight", 2)),
35  m_lastPlayWeight( gCoreContext->GetNumSetting("IntelliLastPlayWeight", 2)),
36  m_randomWeight( gCoreContext->GetNumSetting("IntelliRandomWeight", 2))
37 {
39 }
40 
42 {
44  delete m_playlistsLoader;
45  m_playlistsLoader = nullptr;
46 
47  delete m_activePlaylist;
48  delete m_streamPlaylist;
49  if (m_allPlaylists)
50  {
51  while (!m_allPlaylists->empty())
52  {
53  delete m_allPlaylists->front();
54  m_allPlaylists->pop_front();
55  }
56  delete m_allPlaylists;
57  }
58 }
59 
61  int &lastplay, int &random) const
62 {
64  playcount = m_playCountWeight;
65  lastplay = m_lastPlayWeight;
66  random = m_randomWeight;
67 }
68 
70 {
71  m_doneLoading = false;
72  m_activePlaylist = new Playlist();
74 
75  m_streamPlaylist = new Playlist();
77 
78  m_allPlaylists = new QList<Playlist*>;
79 
81 
83 
85  query.prepare("SELECT playlist_id FROM music_playlists "
86  "WHERE playlist_name != :DEFAULT"
87  " AND playlist_name != :BACKUP "
88  " AND playlist_name != :STREAM "
89  " AND (hostname = '' OR hostname = :HOST) "
90  "ORDER BY playlist_name;");
91  query.bindValue(":DEFAULT", DEFAULT_PLAYLIST_NAME);
92  query.bindValue(":BACKUP", "backup_playlist_storage");
93  query.bindValue(":STREAM", DEFAULT_STREAMLIST_NAME);
94  query.bindValue(":HOST", m_myHost);
95 
96  if (!query.exec())
97  {
98  MythDB::DBError("Querying playlists", query);
99  }
100  else
101  {
102  while (query.next())
103  {
104  auto *temp_playlist = new Playlist();
105  // No, we don't destruct this ...
106  temp_playlist->setParent(this);
107  temp_playlist->loadPlaylistByID(query.value(0).toInt(), m_myHost);
108  m_allPlaylists->push_back(temp_playlist);
109  // ... cause it's sitting on this PtrList
110  }
111  }
112 
113  m_doneLoading = true;
114 }
115 
116 // resync all the playlists after a rescan just in case some tracks were removed
118 {
119  // NOLINTNEXTLINE(modernize-loop-convert)
120  for (auto it = m_allPlaylists->begin(); it != m_allPlaylists->end(); ++it)
121  (*it)->resync();
122 
124 }
125 
127 {
128  // Debugging
130  for (const auto & playlist : qAsConst(*m_allPlaylists))
131  playlist->describeYourself();
132 }
133 
135 {
136  // return a pointer to a playlist
137  // by id;
138 
139  if (m_activePlaylist->getID() == id)
140  {
141  return m_activePlaylist;
142  }
143 
144  auto idmatch = [id](const auto & playlist)
145  { return playlist->getID() == id; };
146  auto it = std::find_if(m_allPlaylists->cbegin(), m_allPlaylists->cend(), idmatch);
147  if (it != m_allPlaylists->cend())
148  return *it;
149 
150  LOG(VB_GENERAL, LOG_ERR,
151  "getPlaylistName() called with unknown index number");
152  return nullptr;
153 }
154 
156 {
157  // return a pointer to a playlist
158  // by name;
159  auto namematch = [name](const auto & playlist)
160  { return playlist->getName() == name; };
161  auto it = std::find_if(m_allPlaylists->cbegin(), m_allPlaylists->cend(), namematch);
162  if (it != m_allPlaylists->cend())
163  return *it;
164 
165  LOG(VB_GENERAL, LOG_ERR, QString("getPlaylistName() called with unknown name: %1").arg(name));
166  return nullptr;
167 }
168 
170 {
171  // NOLINTNEXTLINE(modernize-loop-convert)
172  for (auto it = m_allPlaylists->begin(); it != m_allPlaylists->end(); ++it)
173  {
174  if ((*it)->hasChanged())
175  (*it)->savePlaylist((*it)->getName(), m_myHost);
176  }
177 
180 }
181 
182 void PlaylistContainer::createNewPlaylist(const QString &name)
183 {
184  auto *new_list = new Playlist();
185  new_list->setParent(this);
186 
187  // Need to touch the database to get persistent ID
188  new_list->savePlaylist(name, m_myHost);
189 
190  m_allPlaylists->push_back(new_list);
191 }
192 
193 void PlaylistContainer::copyNewPlaylist(const QString &name)
194 {
195  auto *new_list = new Playlist();
196  new_list->setParent(this);
197 
198  // Need to touch the database to get persistent ID
199  new_list->savePlaylist(name, m_myHost);
200 
201  m_allPlaylists->push_back(new_list);
202  m_activePlaylist->copyTracks(new_list, false);
203 }
204 
206 {
208  Playlist *copy_from = getPlaylist(index);
209  if (!copy_from)
210  {
211  LOG(VB_GENERAL, LOG_ERR, LOC + "copyToActive() " +
212  QString("Unknown playlist: %1").arg(index));
213  return;
214  }
215  copy_from->copyTracks(m_activePlaylist, true);
216 }
217 
218 void PlaylistContainer::renamePlaylist(int index, const QString& new_name)
219 {
220  Playlist *list_to_rename = getPlaylist(index);
221  if (list_to_rename)
222  {
223  list_to_rename->setName(new_name);
224  list_to_rename->changed();
225  }
226 }
227 
229 {
230  Playlist *list_to_kill = getPlaylist(kill_me);
231  if (!list_to_kill)
232  {
233  LOG(VB_GENERAL, LOG_ERR, LOC + "deletePlaylist() " +
234  QString("Unknown playlist: %1").arg(kill_me));
235  return;
236  }
237 
238  list_to_kill->removeAllTracks();
239  m_allPlaylists->removeAll(list_to_kill);
240 
241  MSqlQuery query(MSqlQuery::InitCon());
242  query.prepare("DELETE FROM music_playlists WHERE playlist_id = :ID ;");
243  query.bindValue(":ID", kill_me);
244 
245  if (!query.exec() || query.numRowsAffected() < 1)
246  {
247  MythDB::DBError("playlist delete", query);
248  }
249 }
250 
251 
252 QString PlaylistContainer::getPlaylistName(int index, bool &reference)
253 {
254  if (m_activePlaylist)
255  {
256  if (m_activePlaylist->getID() == index)
257  {
258  return m_activePlaylist->getName();
259  }
260 
261  auto indexmatch = [index](const auto & playlist)
262  { return playlist->getID() == index; };
263  auto it = std::find_if(m_allPlaylists->cbegin(), m_allPlaylists->cend(), indexmatch);
264  if (it != m_allPlaylists->cend())
265  return (*it)->getName();
266  }
267 
268  LOG(VB_GENERAL, LOG_ERR, LOC +
269  "getPlaylistName() called with unknown index number");
270 
271  reference = true;
272  return tr("Something is Wrong");
273 }
274 
275 bool PlaylistContainer::nameIsUnique(const QString& a_name, int which_id)
276 {
277  if (a_name == DEFAULT_PLAYLIST_NAME)
278  return false;
279 
280  auto itemfound = [a_name,which_id](const auto & playlist)
281  { return playlist->getName() == a_name &&
282  playlist->getID() != which_id; };
283  return std::none_of(m_allPlaylists->cbegin(), m_allPlaylists->cend(), itemfound);
284 }
285 
287 {
288  QStringList res;
289 
290  for (const auto & playlist : qAsConst(*m_allPlaylists))
291  {
292  res.append(playlist->getName());
293  }
294 
295  return res;
296 }
297 
299 {
301  {
302  return true;
303  }
305  return false;
306 }
307 
309 {
311 }
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:811
PlaylistContainer::~PlaylistContainer
~PlaylistContainer()
Definition: playlistcontainer.cpp:41
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
playlistcontainer.h
PlaylistContainer::renamePlaylist
void renamePlaylist(int index, const QString &new_name)
Definition: playlistcontainer.cpp:218
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
PlaylistContainer::m_playCountWeight
int m_playCountWeight
Definition: playlistcontainer.h:86
PlaylistContainer::getPlaylistName
QString getPlaylistName(int index, bool &reference)
Definition: playlistcontainer.cpp:252
mythdb.h
AllMusic
Definition: musicmetadata.h:418
Playlist::setParent
void setParent(PlaylistContainer *myparent)
Definition: playlist.h:53
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
PlaylistContainer::PlaylistContainer
PlaylistContainer(AllMusic *all_music)
Definition: playlistcontainer.cpp:29
PlaylistLoadingThread::m_parent
PlaylistContainer * m_parent
Definition: playlistcontainer.h:29
PlaylistContainer::createNewPlaylist
void createNewPlaylist(const QString &name)
Definition: playlistcontainer.cpp:182
Playlist
Definition: playlist.h:45
Playlist::getName
QString getName(void)
Definition: playlist.h:106
MThread::usleep
static void usleep(std::chrono::microseconds time)
Definition: mthread.cpp:335
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:617
PlaylistContainer::deletePlaylist
void deletePlaylist(int kill_me)
Definition: playlistcontainer.cpp:228
PlaylistContainer::copyNewPlaylist
void copyNewPlaylist(const QString &name)
Definition: playlistcontainer.cpp:193
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
PlaylistContainer::describeYourself
void describeYourself(void) const
Definition: playlistcontainer.cpp:126
PlaylistContainer::getPlaylistNames
QStringList getPlaylistNames(void)
Definition: playlistcontainer.cpp:286
PlaylistLoadingThread
Definition: playlistcontainer.h:18
DEFAULT_PLAYLIST_NAME
static constexpr const char * DEFAULT_PLAYLIST_NAME
Definition: playlistcontainer.h:11
PlaylistContainer::FillIntelliWeights
void FillIntelliWeights(int &rating, int &playcount, int &lastplay, int &random) const
Definition: playlistcontainer.cpp:60
mythlogging.h
AllMusic::doneLoading
bool doneLoading() const
Definition: musicmetadata.h:444
Playlist::changed
void changed(void)
Definition: playlist.cpp:991
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:549
compat.h
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
hardwareprofile.scan.rating
def rating(profile, smoonURL, gate)
Definition: scan.py:39
PlaylistContainer::m_streamPlaylist
Playlist * m_streamPlaylist
Definition: playlistcontainer.h:78
Playlist::resync
void resync(void)
make sure all tracks are still valid after a scan
Definition: playlist.cpp:606
PlaylistContainer::getPlaylist
Playlist * getPlaylist(int id)
Definition: playlistcontainer.cpp:134
Playlist::setName
void setName(const QString &a_name)
Definition: playlist.h:107
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
PlaylistContainer::nameIsUnique
bool nameIsUnique(const QString &a_name, int which_id)
Definition: playlistcontainer.cpp:275
MThread::isFinished
bool isFinished(void) const
Definition: mthread.cpp:258
PlaylistContainer::resync
void resync(void)
Definition: playlistcontainer.cpp:117
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
PlaylistContainer::m_playlistsLoader
PlaylistLoadingThread * m_playlistsLoader
Definition: playlistcontainer.h:81
Playlist::loadPlaylist
void loadPlaylist(const QString &a_name, const QString &a_host)
Definition: playlist.cpp:522
PlaylistContainer::load
void load()
Definition: playlistcontainer.cpp:69
LOC
#define LOC
Definition: playlistcontainer.cpp:25
PlaylistContainer::cleanOutThreads
bool cleanOutThreads()
Definition: playlistcontainer.cpp:298
PlaylistLoadingThread::m_allMusic
AllMusic * m_allMusic
Definition: playlistcontainer.h:30
Playlist::copyTracks
void copyTracks(Playlist *to_ptr, bool update_display)
Definition: playlist.cpp:42
PlaylistContainer::m_myHost
QString m_myHost
Definition: playlistcontainer.h:83
PlaylistContainer::save
void save()
Definition: playlistcontainer.cpp:169
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:887
PlaylistContainer::m_doneLoading
bool m_doneLoading
Definition: playlistcontainer.h:82
mythcontext.h
PlaylistContainer::m_allPlaylists
QList< Playlist * > * m_allPlaylists
Definition: playlistcontainer.h:79
Playlist::savePlaylist
void savePlaylist(const QString &a_name, const QString &a_host)
Definition: playlist.cpp:999
PlaylistContainer::m_activePlaylist
Playlist * m_activePlaylist
Definition: playlistcontainer.h:77
DEFAULT_STREAMLIST_NAME
static constexpr const char * DEFAULT_STREAMLIST_NAME
Definition: playlistcontainer.h:12
MSqlQuery::numRowsAffected
int numRowsAffected() const
Definition: mythdbcon.h:218
PlaylistContainer::m_lastPlayWeight
int m_lastPlayWeight
Definition: playlistcontainer.h:87
PlaylistContainer::clearActive
void clearActive()
Definition: playlistcontainer.cpp:308
PlaylistContainer::copyToActive
void copyToActive(int index)
Definition: playlistcontainer.cpp:205
Playlist::describeYourself
void describeYourself(void) const
Definition: playlist.cpp:474
Playlist::removeAllTracks
void removeAllTracks(void)
Definition: playlist.cpp:86
Playlist::getID
int getID(void) const
Definition: playlist.h:111
playlist.h
PlaylistLoadingThread::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: playlistcontainer.cpp:14
PlaylistContainer::m_randomWeight
int m_randomWeight
Definition: playlistcontainer.h:88
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:836