MythTV  master
metadataimagedownload.cpp
Go to the documentation of this file.
1 // qt
2 #include <QCoreApplication>
3 #include <QDir>
4 #include <QEvent>
5 #include <QFileInfo>
6 #include <QImage>
7 #include <utility>
8 
9 // myth
10 #include "mythcorecontext.h"
11 #include "mythuihelper.h"
12 #include "mythdirs.h"
13 #include "storagegroup.h"
14 #include "metadataimagedownload.h"
15 #include "remotefile.h"
16 #include "mythdownloadmanager.h"
17 #include "mythlogging.h"
18 #include "mythdate.h"
19 
20 QEvent::Type ImageDLEvent::kEventType =
21  (QEvent::Type) QEvent::registerEventType();
22 
24  (QEvent::Type) QEvent::registerEventType();
25 
26 QEvent::Type ThumbnailDLEvent::kEventType =
27  (QEvent::Type) QEvent::registerEventType();
28 
30 {
31  cancel();
32  wait();
33 }
34 
36  QString url, QVariant data)
37 {
38  QMutexLocker lock(&m_mutex);
39 
40  auto *id = new ThumbnailData();
41  id->title = std::move(title);
42  id->data = std::move(data);
43  id->url = std::move(url);
44  m_thumbnailList.append(id);
45  if (!isRunning())
46  start();
47 }
48 
54 {
55  QMutexLocker lock(&m_mutex);
56 
57  m_downloadList.append(lookup);
58  lookup->DecrRef();
59  if (!isRunning())
60  start();
61 }
62 
64 {
65  QMutexLocker lock(&m_mutex);
66 
67  qDeleteAll(m_thumbnailList);
68  m_thumbnailList.clear();
69  // clearing m_downloadList automatically delete all its content
70  m_downloadList.clear();
71 }
72 
74 {
75  RunProlog();
76 
77  // Always handle thumbnails first, they're higher priority.
78  ThumbnailData *thumb = nullptr;
79  while ((thumb = moreThumbs()) != nullptr)
80  {
81  QString sFilename = getDownloadFilename(thumb->title, thumb->url);
82 
83  bool exists = QFile::exists(sFilename);
84  if (!exists && !thumb->url.isEmpty())
85  {
86  if (!GetMythDownloadManager()->download(thumb->url, sFilename))
87  {
88  LOG(VB_GENERAL, LOG_ERR,
89  QString("MetadataImageDownload: failed to download thumbnail from: %1")
90  .arg(thumb->url));
91 
92  delete thumb;
93  continue;
94  }
95  }
96 
97  // inform parent we have thumbnail ready for it
98  if (QFile::exists(sFilename) && m_parent)
99  {
100  LOG(VB_GENERAL, LOG_DEBUG,
101  QString("Threaded Image Thumbnail Download: %1")
102  .arg(sFilename));
103  thumb->url = sFilename;
104  QCoreApplication::postEvent(m_parent,
105  new ThumbnailDLEvent(thumb));
106  }
107  else
108  delete thumb;
109  }
110 
111  while (true)
112  {
113  m_mutex.lock();
114  if (m_downloadList.isEmpty())
115  {
116  // no more to process, we're done
117  m_mutex.unlock();
118  break;
119  }
120  // Ref owns the MetadataLookup object for the duration of the loop
121  // and it will be deleted automatically when the loop completes
123  m_mutex.unlock();
124  MetadataLookup *lookup = ref;
125  DownloadMap downloads = lookup->GetDownloads();
126  DownloadMap downloaded;
127 
128  bool errored = false;
129  for (DownloadMap::iterator i = downloads.begin();
130  i != downloads.end(); ++i)
131  {
132  VideoArtworkType type = i.key();
133  ArtworkInfo info = i.value();
134  QString filename = getDownloadFilename( type, lookup,
135  info.url );
136  if (lookup->GetHost().isEmpty())
137  {
138  QString path = getLocalWritePath(lookup->GetType(), type);
139  QDir dirPath(path);
140  if (!dirPath.exists())
141  {
142  if (!dirPath.mkpath(path))
143  {
144  LOG(VB_GENERAL, LOG_ERR,
145  QString("Metadata Image Download: Unable to create "
146  "path %1, aborting download.").arg(path));
147  errored = true;
148  break;
149  }
150  }
151  QString finalfile = path + "/" + filename;
152  QString oldurl = info.url;
153  info.url = finalfile;
154  if (!QFile::exists(finalfile) || lookup->GetAllowOverwrites())
155  {
156  QFile dest_file(finalfile);
157  if (dest_file.exists())
158  {
159  QFileInfo fi(finalfile);
160  GetMythUI()->RemoveFromCacheByFile(fi.fileName());
161  dest_file.remove();
162  }
163 
164  LOG(VB_GENERAL, LOG_INFO,
165  QString("Metadata Image Download: %1 ->%2")
166  .arg(oldurl, finalfile));
167  QByteArray download;
168  GetMythDownloadManager()->download(oldurl, &download);
169 
170  QImage testImage;
171  bool didLoad = testImage.loadFromData(download);
172  if (!didLoad)
173  {
174  LOG(VB_GENERAL, LOG_ERR,
175  QString("Tried to write %1, but it appears to be "
176  "an HTML redirect (filesize %2).")
177  .arg(oldurl).arg(download.size()));
178  errored = true;
179  break;
180  }
181 
182  if (dest_file.open(QIODevice::WriteOnly))
183  {
184  off_t size = dest_file.write(download,
185  download.size());
186  dest_file.close();
187  if (size != download.size())
188  {
189  // File creation failed for some reason, delete it
190  RemoteFile::DeleteFile(finalfile);
191  LOG(VB_GENERAL, LOG_ERR,
192  QString("Image Download: Error Writing Image "
193  "to file: %1").arg(finalfile));
194  errored = true;
195  break;
196  }
197  }
198  }
199  }
200  else
201  {
202  QString path = getStorageGroupURL(type, lookup->GetHost());
203  QString finalfile = path + filename;
204  QString oldurl = info.url;
205  info.url = finalfile;
206  bool exists = false;
207  bool onMaster = false;
208  QString resolvedFN;
209  if (gCoreContext->IsMasterBackend() &&
210  gCoreContext->IsThisHost(lookup->GetHost()))
211  {
213  resolvedFN = sg.FindFile(filename);
214  exists = !resolvedFN.isEmpty() && QFile::exists(resolvedFN);
215  if (!exists)
216  {
217  resolvedFN = getLocalStorageGroupPath(type,
218  lookup->GetHost()) + "/" + filename;
219  }
220  onMaster = true;
221  }
222  else
223  exists = RemoteFile::Exists(finalfile);
224 
225  if (!exists || lookup->GetAllowOverwrites())
226  {
227  if (exists && !onMaster)
228  {
229  QFileInfo fi(finalfile);
230  GetMythUI()->RemoveFromCacheByFile(fi.fileName());
231  RemoteFile::DeleteFile(finalfile);
232  }
233  else if (exists)
234  QFile::remove(resolvedFN);
235 
236  LOG(VB_GENERAL, LOG_INFO,
237  QString("Metadata Image Download: %1 -> %2")
238  .arg(oldurl, finalfile));
239  QByteArray download;
240  GetMythDownloadManager()->download(oldurl, &download);
241 
242  QImage testImage;
243  bool didLoad = testImage.loadFromData(download);
244  if (!didLoad)
245  {
246  LOG(VB_GENERAL, LOG_ERR,
247  QString("Tried to write %1, but it appears to be "
248  "an HTML redirect or corrupt file "
249  "(filesize %2).")
250  .arg(oldurl).arg(download.size()));
251  errored = true;
252  break;
253  }
254 
255  if (!onMaster)
256  {
257  RemoteFile outFile(finalfile, true);
258 
259  if (!outFile.isOpen())
260  {
261  LOG(VB_GENERAL, LOG_ERR,
262  QString("Image Download: Failed to open "
263  "remote file (%1) for write. Does "
264  "Storage Group Exist?")
265  .arg(finalfile));
266  errored = true;
267  break;
268  }
269  off_t written = outFile.Write(download,
270  download.size());
271  if (written != download.size())
272  {
273  // File creation failed for some reason, delete it
274  RemoteFile::DeleteFile(finalfile);
275 
276  LOG(VB_GENERAL, LOG_ERR,
277  QString("Image Download: Error Writing Image "
278  "to file: %1").arg(finalfile));
279  errored = true;
280  break;
281  }
282  }
283  else
284  {
285  QFile dest_file(resolvedFN);
286  if (dest_file.open(QIODevice::WriteOnly))
287  {
288  off_t size = dest_file.write(download,
289  download.size());
290  dest_file.close();
291  if (size != download.size())
292  {
293  // File creation failed for some reason, delete it
294  RemoteFile::DeleteFile(resolvedFN);
295  LOG(VB_GENERAL, LOG_ERR,
296  QString("Image Download: Error Writing Image "
297  "to file: %1").arg(finalfile));
298  errored = true;
299  break;
300  }
301  }
302  }
303  }
304  }
305  if (!errored)
306  {
307  // update future Artwork Map with what we've successfully
308  // retrieved (either downloaded or already existing
309  downloaded.insert(type, info);
310  }
311  }
312  if (errored)
313  {
314  QCoreApplication::postEvent(m_parent,
315  new ImageDLFailureEvent(lookup));
316  }
317  lookup->SetDownloads(downloaded);
318  QCoreApplication::postEvent(m_parent, new ImageDLEvent(lookup));
319  }
320 
321  RunEpilog();
322 }
323 
325 {
326  QMutexLocker lock(&m_mutex);
327  ThumbnailData *ret = nullptr;
328 
329  if (!m_thumbnailList.isEmpty())
330  ret = m_thumbnailList.takeFirst();
331  return ret;
332 }
333 
334 QString getDownloadFilename(const QString& title, const QString& url)
335 {
336  QString fileprefix = GetConfDir();
337 
338  QDir dir(fileprefix);
339  if (!dir.exists())
340  dir.mkdir(fileprefix);
341 
342  fileprefix += "/cache/metadata-thumbcache";
343 
344  dir.setPath(fileprefix);;
345  if (!dir.exists())
346  dir.mkdir(fileprefix);
347 
348  QByteArray titlearr(title.toLatin1());
349  QByteArray urlarr(url.toLatin1());
350 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
351  quint16 titleChecksum = qChecksum(titlearr.data(), titlearr.length());
352  quint16 urlChecksum = qChecksum(urlarr.data(), urlarr.length());
353 #else
354  quint16 titleChecksum = qChecksum(titlearr);
355  quint16 urlChecksum = qChecksum(urlarr);
356 #endif
357  QUrl qurl(url);
358  QString ext = QFileInfo(qurl.path()).suffix();
359  QString basefilename = QString("thumbnail_%1_%2.%3")
360  .arg(QString::number(urlChecksum),
361  QString::number(titleChecksum), ext);
362 
363  QString outputfile = QString("%1/%2").arg(fileprefix, basefilename);
364 
365  return outputfile;
366 }
367 
369  const QString& url)
370 {
371  QString basefilename;
372  QString title;
373  QString inter;
374  uint tracknum = lookup->GetTrackNumber();
375  uint season = lookup->GetSeason();
376  uint episode = lookup->GetEpisode();
377  QString system = lookup->GetSystem();
378  if (!lookup->GetIsCollection() && (season > 0 || episode > 0))
379  {
380  title = lookup->GetTitle();
381  if (title.contains("/"))
382  title.replace("/", "-");
383  if (title.contains("?"))
384  title.replace("?", "");
385  if (title.contains("*"))
386  title.replace("*", "");
387  inter = QString(" Season %1").arg(QString::number(season));
388  if (type == kArtworkScreenshot)
389  inter += QString("x%1").arg(QString::number(episode));
390  }
391  else if (lookup->GetType() == kMetadataVideo ||
392  lookup->GetType() == kMetadataRecording)
393  title = lookup->GetInetref();
394  else if (lookup->GetType() == kMetadataGame)
395  title = QString("%1 (%2)").arg(lookup->GetTitle(), lookup->GetSystem());
396 
397  if (tracknum > 0)
398  inter = QString(" Track %1").arg(QString::number(tracknum));
399  else if (!system.isEmpty())
400  inter = QString(" (%1)").arg(system);
401 
402  QString suffix;
403  QUrl qurl(url);
404  QString ext = QFileInfo(qurl.path()).suffix();
405 
406  if (type == kArtworkCoverart)
407  suffix = "_coverart";
408  else if (type == kArtworkFanart)
409  suffix = "_fanart";
410  else if (type == kArtworkBanner)
411  suffix = "_banner";
412  else if (type == kArtworkScreenshot)
413  suffix = "_screenshot";
414  else if (type == kArtworkPoster)
415  suffix = "_poster";
416  else if (type == kArtworkBackCover)
417  suffix = "_backcover";
418  else if (type == kArtworkInsideCover)
419  suffix = "_insidecover";
420  else if (type == kArtworkCDImage)
421  suffix = "_cdimage";
422 
423  basefilename = title + inter + suffix + "." + ext;
424 
425  return basefilename;
426 }
427 
429 {
430  QString ret;
431 
432  if (metadatatype == kMetadataVideo)
433  {
434  if (type == kArtworkCoverart)
435  ret = gCoreContext->GetSetting("VideoArtworkDir");
436  else if (type == kArtworkFanart)
437  ret = gCoreContext->GetSetting("mythvideo.fanartDir");
438  else if (type == kArtworkBanner)
439  ret = gCoreContext->GetSetting("mythvideo.bannerDir");
440  else if (type == kArtworkScreenshot)
441  ret = gCoreContext->GetSetting("mythvideo.screenshotDir");
442  }
443  else if (metadatatype == kMetadataMusic)
444  {
445  }
446  else if (metadatatype == kMetadataGame)
447  {
448  if (type == kArtworkCoverart)
449  ret = gCoreContext->GetSetting("mythgame.boxartdir");
450  else if (type == kArtworkFanart)
451  ret = gCoreContext->GetSetting("mythgame.fanartdir");
452  else if (type == kArtworkScreenshot)
453  ret = gCoreContext->GetSetting("mythgame.screenshotdir");
454  }
455 
456  return ret;
457 }
458 
459 QString getStorageGroupURL(VideoArtworkType type, const QString& host)
460 {
461  QString sgroup = getStorageGroupName(type);
462  uint port = gCoreContext->GetBackendServerPort(host);
463 
464  return MythCoreContext::GenMythURL(host, port, "", sgroup);
465 }
466 
467 QString getLocalStorageGroupPath(VideoArtworkType type, const QString& host)
468 {
469  QString path;
470 
472 
473  path = sg.FindNextDirMostFree();
474 
475  return path;
476 }
477 
479 {
480  switch (type)
481  {
482  case kArtworkCoverart:
483  return "Coverart";
484  case kArtworkFanart:
485  return "Fanart";
486  case kArtworkBanner:
487  return "Banners";
488  case kArtworkScreenshot:
489  return "Screenshots";
490  default:
491  return "Default";
492  }
493 }
494 
496 {
497  QString cache = QString("%1/cache/metadata-thumbcache")
498  .arg(GetConfDir());
499  QDir cacheDir(cache);
500  QStringList thumbs = cacheDir.entryList(QDir::Files);
501 
502  for (auto i = thumbs.crbegin(); i != thumbs.crend(); ++i)
503  {
504  QString filename = QString("%1/%2").arg(cache, *i);
505  QFileInfo fi(filename);
506  QDateTime lastmod = fi.lastModified();
507  if (lastmod.addDays(2) < MythDate::current())
508  {
509  LOG(VB_GENERAL, LOG_DEBUG, QString("Deleting file %1")
510  .arg(filename));
511  QFile::remove(filename);
512  }
513  }
514 }
515 
getLocalStorageGroupPath
QString getLocalStorageGroupPath(VideoArtworkType type, const QString &host)
Definition: metadataimagedownload.cpp:467
kMetadataMusic
@ kMetadataMusic
Definition: metadatacommon.h:45
VideoArtworkType
VideoArtworkType
Definition: metadataimagehelper.h:10
MetadataImageDownload::~MetadataImageDownload
~MetadataImageDownload() override
Definition: metadataimagedownload.cpp:29
RefCountHandler
Definition: referencecounterlist.h:17
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
MetadataLookup::GetTrackNumber
uint GetTrackNumber() const
Definition: metadatacommon.h:343
kArtworkInsideCover
@ kArtworkInsideCover
Definition: metadataimagehelper.h:17
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
kMetadataRecording
@ kMetadataRecording
Definition: metadatacommon.h:44
MetadataType
MetadataType
Definition: metadatacommon.h:42
MetadataLookup::GetTitle
QString GetTitle() const
Definition: metadatacommon.h:299
kMetadataVideo
@ kMetadataVideo
Definition: metadatacommon.h:43
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:461
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:303
MetadataImageDownload::cancel
void cancel()
Definition: metadataimagedownload.cpp:63
RefCountedList::takeFirstAndDecr
RefCountHandler< T > takeFirstAndDecr(void)
Removes the first item in the list and returns it.
Definition: referencecounterlist.h:112
StorageGroup::FindFile
QString FindFile(const QString &filename)
Definition: storagegroup.cpp:602
ImageDLFailureEvent::kEventType
static Type kEventType
Definition: metadataimagedownload.h:67
MetadataImageDownload::moreThumbs
ThumbnailData * moreThumbs()
Definition: metadataimagedownload.cpp:324
MetadataImageDownload::m_thumbnailList
QList< ThumbnailData * > m_thumbnailList
Definition: metadataimagedownload.h:109
RemoteFile
Definition: remotefile.h:17
ImageDLEvent
Definition: metadataimagedownload.h:18
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
MetadataImageDownload::addThumb
void addThumb(QString title, QString url, QVariant data)
Definition: metadataimagedownload.cpp:35
RemoteFile::Write
int Write(const void *data, int size)
Definition: remotefile.cpp:834
RemoteFile::isOpen
bool isOpen(void) const
Definition: remotefile.cpp:246
MetadataImageDownload::run
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: metadataimagedownload.cpp:73
mythdirs.h
MetadataLookup::SetDownloads
void SetDownloads(DownloadMap map)
Definition: metadatacommon.h:253
kArtworkBackCover
@ kArtworkBackCover
Definition: metadataimagehelper.h:16
kArtworkCDImage
@ kArtworkCDImage
Definition: metadataimagehelper.h:18
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
MetadataImageDownload::m_downloadList
MetadataLookupList m_downloadList
Definition: metadataimagedownload.h:108
ThumbnailData::title
QString title
Definition: metadataimagedownload.h:13
MetadataLookup
Definition: metadatacommon.h:87
getDownloadFilename
QString getDownloadFilename(const QString &title, const QString &url)
Definition: metadataimagedownload.cpp:334
MetadataLookup::GetDownloads
DownloadMap GetDownloads() const
Definition: metadatacommon.h:372
MythCoreContext::IsMasterBackend
bool IsMasterBackend(void)
is this the actual MBE process
Definition: mythcorecontext.cpp:719
mythdate.h
ThumbnailDLEvent::kEventType
static Type kEventType
Definition: metadataimagedownload.h:84
mythlogging.h
MetadataLookup::GetEpisode
uint GetEpisode() const
Definition: metadatacommon.h:315
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:784
GetConfDir
QString GetConfDir(void)
Definition: mythdirs.cpp:224
getStorageGroupURL
QString getStorageGroupURL(VideoArtworkType type, const QString &host)
Definition: metadataimagedownload.cpp:459
MetadataLookup::GetAllowOverwrites
bool GetAllowOverwrites() const
Definition: metadatacommon.h:294
ThumbnailData::url
QString url
Definition: metadataimagedownload.h:15
remotefile.h
ArtworkInfo
Definition: metadataimagehelper.h:21
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1088
metadataimagedownload.h
ImageDLFailureEvent
Definition: metadataimagedownload.h:44
kArtworkPoster
@ kArtworkPoster
Definition: metadataimagehelper.h:15
MetadataLookup::GetType
MetadataType GetType() const
Definition: metadatacommon.h:286
kArtworkFanart
@ kArtworkFanart
Definition: metadataimagehelper.h:12
MythUIThemeCache::RemoveFromCacheByFile
void RemoveFromCacheByFile(const QString &File)
Definition: mythuithemecache.cpp:524
ThumbnailDLEvent
Definition: metadataimagedownload.h:70
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
MythDownloadManager::download
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
Definition: mythdownloadmanager.cpp:430
storagegroup.h
RemoteFile::DeleteFile
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:418
MetadataImageDownload::m_parent
QObject * m_parent
Definition: metadataimagedownload.h:107
uint
unsigned int uint
Definition: compat.h:144
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MetadataImageDownload::m_mutex
QMutex m_mutex
Definition: metadataimagedownload.h:110
MetadataLookup::GetSeason
uint GetSeason() const
Definition: metadatacommon.h:314
off_t
#define off_t
Definition: mythiowrapper.cpp:240
MetadataLookup::GetSystem
QString GetSystem() const
Definition: metadatacommon.h:346
mythuihelper.h
mythcorecontext.h
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
MetadataLookup::GetInetref
QString GetInetref() const
Definition: metadatacommon.h:356
kMetadataGame
@ kMetadataGame
Definition: metadatacommon.h:46
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:266
StorageGroup
Definition: storagegroup.h:11
kArtworkBanner
@ kArtworkBanner
Definition: metadataimagehelper.h:13
getLocalWritePath
QString getLocalWritePath(MetadataType metadatatype, VideoArtworkType type)
Definition: metadataimagedownload.cpp:428
DownloadMap
QMap< VideoArtworkType, ArtworkInfo > DownloadMap
Definition: metadatacommon.h:84
MetadataLookup::GetIsCollection
bool GetIsCollection() const
Definition: metadatacommon.h:360
MythCoreContext::IsThisHost
bool IsThisHost(const QString &addr)
is this address mapped to this host
Definition: mythcorecontext.cpp:745
cleanThumbnailCacheDir
void cleanThumbnailCacheDir()
Definition: metadataimagedownload.cpp:495
kArtworkScreenshot
@ kArtworkScreenshot
Definition: metadataimagehelper.h:14
ThumbnailData
Definition: metadataimagedownload.h:12
mythdownloadmanager.h
getStorageGroupName
QString getStorageGroupName(VideoArtworkType type)
Definition: metadataimagedownload.cpp:478
GetMythUI
MythUIHelper * GetMythUI()
Definition: mythuihelper.cpp:66
MetadataLookup::GetHost
QString GetHost() const
Definition: metadatacommon.h:305
build_compdb.filename
filename
Definition: build_compdb.py:21
kArtworkCoverart
@ kArtworkCoverart
Definition: metadataimagehelper.h:11
ImageDLEvent::kEventType
static Type kEventType
Definition: metadataimagedownload.h:41
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:922
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
ArtworkInfo::url
QString url
Definition: metadataimagehelper.h:25
MetadataImageDownload::addDownloads
void addDownloads(MetadataLookup *lookup)
addLookup: Add lookup to bottom of the queue MetadataDownload::m_downloadList takes ownership of the ...
Definition: metadataimagedownload.cpp:53