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