MythTV  master
metadatadownload.cpp
Go to the documentation of this file.
1 // qt
2 #include <QCoreApplication>
3 #include <QEvent>
4 #include <QDir>
5 #include <QUrl>
6 
7 // myth
8 #include "mythcorecontext.h"
9 #include "mythdirs.h"
10 #include "mythuihelper.h"
11 #include "mythsystemlegacy.h"
12 #include "storagegroup.h"
13 #include "metadatadownload.h"
14 #include "metadatafactory.h"
15 #include "mythmiscutil.h"
16 #include "remotefile.h"
17 #include "mythlogging.h"
18 
20  (QEvent::Type) QEvent::registerEventType();
21 
23  (QEvent::Type) QEvent::registerEventType();
24 
26 {
27  cancel();
28  wait();
29 }
30 
36 {
37  // Add a lookup to the queue
38  QMutexLocker lock(&m_mutex);
39 
40  m_lookupList.append(lookup);
41  lookup->DecrRef();
42  if (!isRunning())
43  start();
44 }
45 
51 {
52  // Add a lookup to the queue
53  QMutexLocker lock(&m_mutex);
54 
55  m_lookupList.prepend(lookup);
56  lookup->DecrRef();
57  if (!isRunning())
58  start();
59 }
60 
62 {
63  QMutexLocker lock(&m_mutex);
64 
65  m_lookupList.clear();
66  m_parent = nullptr;
67 }
68 
70 {
71  RunProlog();
72 
73  while (true)
74  {
75  m_mutex.lock();
76  if (m_lookupList.isEmpty())
77  {
78  // no more to process, we're done
79  m_mutex.unlock();
80  break;
81  }
82  // Ref owns the MetadataLookup object for the duration of the loop
83  // and it will be deleted automatically when the loop completes
85  m_mutex.unlock();
86  MetadataLookup *lookup = ref;
87  MetadataLookupList list;
88 
89  // Go go gadget Metadata Lookup
90  if (lookup->GetType() == kMetadataVideo ||
91  lookup->GetType() == kMetadataRecording)
92  {
93  if (lookup->GetSubtype() == kProbableTelevision)
94  {
95  list = handleTelevision(lookup);
96  if (findExactMatchCount(list, lookup->GetBaseTitle(), true) == 0)
97  {
98  // There are no exact match prospects with artwork from TV search,
99  // so add in movies, where we might find a better match.
100  list.append(handleMovie(lookup));
101  }
102  }
103  else if (lookup->GetSubtype() == kProbableMovie)
104  {
105  list = handleMovie(lookup);
106  if (findExactMatchCount(list, lookup->GetBaseTitle(), true) == 0)
107  {
108  // There are no exact match prospects with artwork from Movie search
109  // so add in television, where we might find a better match.
110  list.append(handleTelevision(lookup));
111  }
112  }
113  else
114  {
115  // will try both movie and TV
116  list = handleVideoUndetermined(lookup);
117  }
118 
119  if ((list.isEmpty() ||
120  (list.size() > 1 && !lookup->GetAutomatic())) &&
121  lookup->GetSubtype() == kProbableTelevision)
122  {
123  list.append(handleMovie(lookup));
124  }
125  else if ((list.isEmpty() ||
126  (list.size() > 1 && !lookup->GetAutomatic())) &&
127  lookup->GetSubtype() == kProbableMovie)
128  {
129  list.append(handleTelevision(lookup));
130  }
131  }
132  else if (lookup->GetType() == kMetadataGame)
133  list = handleGame(lookup);
134 
135  // inform parent we have lookup ready for it
136  if (m_parent && !list.isEmpty())
137  {
138  // If there's only one result, don't bother asking
139  // our parent about it, just add it to the back of
140  // the queue in kLookupData mode.
141  if (list.count() == 1 && list[0]->GetStep() == kLookupSearch)
142  {
143  MetadataLookup *newlookup = list.takeFirst();
144 
145  newlookup->SetStep(kLookupData);
146  prependLookup(newlookup);
147  // Type may have changed
148  LookupType ret = GuessLookupType(newlookup);
149  if (ret != kUnknownVideo)
150  {
151  newlookup->SetSubtype(ret);
152  }
153  continue;
154  }
155 
156  // If we're in automatic mode, we need to make
157  // these decisions on our own. Pass to title match.
158  if (list[0]->GetAutomatic() && list.count() > 1
159  && list[0]->GetStep() == kLookupSearch)
160  {
161  MetadataLookup *bestLookup = findBestMatch(list, lookup->GetBaseTitle());
162  if (bestLookup)
163  {
164  MetadataLookup *newlookup = bestLookup;
165 
166  // bestlookup is owned by list, we need an extra reference
167  newlookup->IncrRef();
168  newlookup->SetStep(kLookupData);
169  // Type may have changed
170  LookupType ret = GuessLookupType(newlookup);
171  if (ret != kUnknownVideo)
172  {
173  newlookup->SetSubtype(ret);
174  }
175  prependLookup(newlookup);
176  continue;
177  }
178 
179  QCoreApplication::postEvent(m_parent,
180  new MetadataLookupFailure(MetadataLookupList() << lookup));
181  }
182 
183  LOG(VB_GENERAL, LOG_INFO,
184  QString("Returning Metadata Results: %1 %2 %3")
185  .arg(lookup->GetBaseTitle()).arg(lookup->GetSeason())
186  .arg(lookup->GetEpisode()));
187  QCoreApplication::postEvent(m_parent,
188  new MetadataLookupEvent(list));
189  }
190  else
191  {
192  if (list.isEmpty())
193  {
194  LOG(VB_GENERAL, LOG_INFO,
195  QString("Metadata Lookup Failed: No Results %1 %2 %3")
196  .arg(lookup->GetBaseTitle()).arg(lookup->GetSeason())
197  .arg(lookup->GetEpisode()));
198  }
199  if (m_parent)
200  {
201  // list is always empty here
202  list.append(lookup);
203  QCoreApplication::postEvent(m_parent,
204  new MetadataLookupFailure(list));
205  }
206  }
207  }
208 
209  RunEpilog();
210 }
211 
213  const QString &originaltitle,
214  bool withArt) const
215 {
216  unsigned int exactMatches = 0;
217  unsigned int exactMatchesWithArt = 0;
218 
219  for (MetadataLookupList::const_iterator i = list.begin();
220  i != list.end(); ++i)
221  {
222  // Consider exact title matches (ignoring case)
223  if ((QString::compare((*i)->GetTitle(), originaltitle, Qt::CaseInsensitive) == 0))
224  {
225  // In lookup by name, the television database tends to only include Banner artwork.
226  // In lookup by name, the movie database tends to include only Fan and Cover artwork.
227  if ((!((*i)->GetArtwork(kArtworkFanart)).empty()) ||
228  (!((*i)->GetArtwork(kArtworkCoverart)).empty()) ||
229  (!((*i)->GetArtwork(kArtworkBanner)).empty()))
230  {
231  exactMatchesWithArt++;
232  }
233  exactMatches++;
234  }
235  }
236 
237  if (withArt)
238  return exactMatchesWithArt;
239  return exactMatches;
240 }
241 
243  const QString &originaltitle) const
244 {
245  QStringList titles;
246  MetadataLookup *ret = nullptr;
247  QDate exactTitleDate;
248  float exactTitlePopularity;
249  int exactMatches = 0;
250  int exactMatchesWithArt = 0;
251  bool foundMatchWithArt = false;
252 
253  // Build a list of all the titles
254  for (MetadataLookupList::const_iterator i = list.begin();
255  i != list.end(); ++i)
256  {
257  QString title = (*i)->GetTitle();
258  LOG(VB_GENERAL, LOG_INFO, QString("Comparing metadata title '%1' [%2] to recording title '%3'")
259  .arg(title)
260  .arg((*i)->GetReleaseDate().toString())
261  .arg(originaltitle));
262  // Consider exact title matches (ignoring case), which have some artwork available.
263  if (QString::compare(title, originaltitle, Qt::CaseInsensitive) == 0)
264  {
265  bool hasArtwork = ((!((*i)->GetArtwork(kArtworkFanart)).empty()) ||
266  (!((*i)->GetArtwork(kArtworkCoverart)).empty()) ||
267  (!((*i)->GetArtwork(kArtworkBanner)).empty()));
268 
269  LOG(VB_GENERAL, LOG_INFO, QString("'%1', popularity = %2, ReleaseDate = %3")
270  .arg(title)
271  .arg((*i)->GetPopularity())
272  .arg((*i)->GetReleaseDate().toString()));
273 
274  // After the first exact match, prefer any more popular one.
275  // Most of the Movie database entries have Popularity fields.
276  // The TV series database generally has no Popularity values specified,
277  // so if none are found so far in the search, pick the most recently
278  // released entry with artwork. Also, if the first exact match had
279  // no artwork, prefer any later exact match with artwork.
280  if ((ret == nullptr) ||
281  (hasArtwork &&
282  ((!foundMatchWithArt) ||
283  (((*i)->GetPopularity() > exactTitlePopularity)) ||
284  ((exactTitlePopularity == 0.0F) && ((*i)->GetReleaseDate() > exactTitleDate)))))
285  {
286  exactTitleDate = (*i)->GetReleaseDate();
287  exactTitlePopularity = (*i)->GetPopularity();
288  ret = (*i);
289  }
290  exactMatches++;
291  if (hasArtwork)
292  {
293  foundMatchWithArt = true;
294  exactMatchesWithArt++;
295  }
296  }
297 
298  titles.append(title);
299  }
300 
301  LOG(VB_GENERAL, LOG_DEBUG, QString("exactMatches = %1, exactMatchesWithArt = %2")
302  .arg(exactMatches)
303  .arg(exactMatchesWithArt));
304 
305  // If there was one or more exact matches then we can skip a more intensive
306  // and time consuming search
307  if (exactMatches > 0)
308  {
309  if (exactMatches == 1)
310  {
311  LOG(VB_GENERAL, LOG_INFO, QString("Single exact title match for '%1'")
312  .arg(originaltitle));
313  }
314  else
315  {
316  LOG(VB_GENERAL, LOG_INFO,
317  QString("Multiple exact title matches found for '%1'. "
318  "Selecting most popular or most recent [%2]")
319  .arg(originaltitle)
320  .arg(exactTitleDate.toString()));
321  }
322  return ret;
323  }
324 
325  // Apply Levenshtein distance algorithm to determine closest match
326  QString bestTitle = nearestName(originaltitle, titles);
327 
328  // If no "best" was chosen, give up.
329  if (bestTitle.isEmpty())
330  {
331  LOG(VB_GENERAL, LOG_ERR,
332  QString("No adequate match or multiple "
333  "matches found for %1. Update manually.")
334  .arg(originaltitle));
335  return nullptr;
336  }
337 
338  LOG(VB_GENERAL, LOG_INFO, QString("Best Title Match For %1: %2")
339  .arg(originaltitle).arg(bestTitle));
340 
341  // Grab the one item that matches the besttitle (IMPERFECT)
342  MetadataLookupList::const_iterator i = list.begin();
343  for (; i != list.end(); ++i)
344  {
345  if ((*i)->GetTitle() == bestTitle)
346  {
347  ret = (*i);
348  break;
349  }
350  }
351 
352  return ret;
353 }
354 
355 MetadataLookupList MetadataDownload::runGrabber(const QString& cmd, const QStringList& args,
356  MetadataLookup *lookup,
357  bool passseas)
358 {
359  MythSystemLegacy grabber(cmd, args, kMSStdOut);
360  MetadataLookupList list;
361 
362  LOG(VB_GENERAL, LOG_INFO, QString("Running Grabber: %1 %2")
363  .arg(cmd).arg(args.join(" ")));
364 
365  grabber.Run();
366  grabber.Wait();
367  QByteArray result = grabber.ReadAll();
368  if (!result.isEmpty())
369  {
370  QDomDocument doc;
371  doc.setContent(result, true);
372  QDomElement root = doc.documentElement();
373  QDomElement item = root.firstChildElement("item");
374 
375  while (!item.isNull())
376  {
377  MetadataLookup *tmp = ParseMetadataItem(item, lookup, passseas);
378  list.append(tmp);
379  // MetadataLookup is to be owned by list
380  tmp->DecrRef();
381  item = item.nextSiblingElement("item");
382  }
383  }
384  return list;
385 }
386 
388 {
389  return MetaGrabberScript::GetType(kGrabberMovie).GetPath();
390 }
391 
393 {
395 }
396 
398 {
399  return MetaGrabberScript::GetType(kGrabberGame).GetPath();
400 }
401 
402 bool MetadataDownload::runGrabberTest(const QString &grabberpath)
403 {
404  return MetaGrabberScript(grabberpath).Test();
405 }
406 
408 {
410  {
411  LOG(VB_GENERAL, LOG_INFO,
412  QString("Movie grabber not functional. Aborting this run."));
413  return false;
414  }
415 
416  return true;
417 }
418 
420 {
422  {
423  LOG(VB_GENERAL, LOG_INFO,
424  QString("Television grabber not functional. Aborting this run."));
425  return false;
426  }
427 
428  return true;
429 }
430 
432  MetadataLookup *lookup,
433  bool passseas)
434 {
435  MetadataLookupList list;
436 
437  LOG(VB_GENERAL, LOG_INFO,
438  QString("Matching MXML file found. Parsing %1 for metadata...")
439  .arg(MXMLpath));
440 
441  if (lookup->GetType() == kMetadataVideo)
442  {
443  QByteArray mxmlraw;
444  QDomElement item;
445  RemoteFile *rf = new RemoteFile(MXMLpath);
446 
447  if (rf->isOpen())
448  {
449  bool loaded = rf->SaveAs(mxmlraw);
450  if (loaded)
451  {
452  QDomDocument doc;
453  if (doc.setContent(mxmlraw, true))
454  {
455  lookup->SetStep(kLookupData);
456  QDomElement root = doc.documentElement();
457  item = root.firstChildElement("item");
458  }
459  else
460  {
461  LOG(VB_GENERAL, LOG_ERR,
462  QString("Corrupt or invalid MXML file."));
463  }
464  }
465  }
466 
467  delete rf;
468  rf = nullptr;
469 
470  MetadataLookup *tmp = ParseMetadataItem(item, lookup, passseas);
471  list.append(tmp);
472  // MetadataLookup is owned by the MetadataLookupList returned
473  tmp->DecrRef();
474  }
475 
476  return list;
477 }
478 
480  MetadataLookup *lookup)
481 {
482  MetadataLookupList list;
483 
484  LOG(VB_GENERAL, LOG_INFO,
485  QString("Matching NFO file found. Parsing %1 for metadata...")
486  .arg(NFOpath));
487 
488  bool error = false;
489 
490  if (lookup->GetType() == kMetadataVideo)
491  {
492  QByteArray nforaw;
493  QDomElement item;
494  RemoteFile *rf = new RemoteFile(NFOpath);
495 
496  if (rf->isOpen())
497  {
498  bool loaded = rf->SaveAs(nforaw);
499 
500  if (loaded)
501  {
502  QDomDocument doc;
503 
504  if (doc.setContent(nforaw, true))
505  {
506  lookup->SetStep(kLookupData);
507  item = doc.documentElement();
508  }
509  else
510  {
511  LOG(VB_GENERAL, LOG_ERR,
512  QString("Invalid NFO file found."));
513  error = true;
514  }
515  }
516  }
517 
518  delete rf;
519  rf = nullptr;
520 
521  if (!error)
522  {
523  MetadataLookup *tmp = ParseMetadataMovieNFO(item, lookup);
524 
525  list.append(tmp);
526  // MetadataLookup is owned by the MetadataLookupList returned
527  tmp->DecrRef();
528  }
529  }
530 
531  return list;
532 }
533 
535 {
536  MetadataLookupList list;
537  MetaGrabberScript grabber =
539 
540  // If the inetref is populated, even in kLookupSearch mode,
541  // become a kLookupData grab and use that.
542  if (lookup->GetStep() == kLookupSearch &&
543  (!lookup->GetInetref().isEmpty() &&
544  lookup->GetInetref() != "00000000"))
545  {
546  lookup->SetStep(kLookupData);
547  }
548 
549  if (lookup->GetStep() == kLookupSearch)
550  {
551  if (lookup->GetTitle().isEmpty())
552  {
553  // no point searching on nothing...
554  return list;
555  }
556  // we're searching
557  list = grabber.Search(lookup->GetTitle(), lookup);
558  }
559  else if (lookup->GetStep() == kLookupData)
560  {
561  // we're just grabbing data
562  list = grabber.LookupData(lookup->GetInetref(), lookup);
563  }
564 
565  return list;
566 }
567 
577 {
578  MetadataLookupList list;
579 
580  QString mxml;
581  QString nfo;
582 
583  if (!lookup->GetFilename().isEmpty())
584  {
585  mxml = getMXMLPath(lookup->GetFilename());
586  nfo = getNFOPath(lookup->GetFilename());
587  }
588 
589  if (!mxml.isEmpty())
590  list = readMXML(mxml, lookup);
591  else if (!nfo.isEmpty())
592  list = readNFO(nfo, lookup);
593 
594  if (!list.isEmpty())
595  return list;
596 
597  MetaGrabberScript grabber =
599 
600  // initial search mode
601  if (!lookup->GetInetref().isEmpty() && lookup->GetInetref() != "00000000" &&
602  (lookup->GetStep() == kLookupSearch || lookup->GetStep() == kLookupData))
603  {
604  // with inetref
605  lookup->SetStep(kLookupData);
606  // we're just grabbing data
607  list = grabber.LookupData(lookup->GetInetref(), lookup);
608  }
609  else if (lookup->GetStep() == kLookupSearch)
610  {
611  if (lookup->GetBaseTitle().isEmpty())
612  {
613  // no point searching on nothing...
614  return list;
615  }
616  list = grabber.Search(lookup->GetBaseTitle(), lookup);
617  }
618 
619  return list;
620 }
621 
634 {
635  MetadataLookupList list;
636 
637  QString mxml;
638  QString nfo;
639 
640  if (!lookup->GetFilename().isEmpty())
641  {
642  mxml = getMXMLPath(lookup->GetFilename());
643  nfo = getNFOPath(lookup->GetFilename());
644  }
645 
646  if (!mxml.isEmpty())
647  list = readMXML(mxml, lookup);
648  else if (!nfo.isEmpty())
649  list = readNFO(nfo, lookup);
650 
651  if (!list.isEmpty())
652  return list;
653 
654  MetaGrabberScript grabber =
656  bool searchcollection = false;
657 
658  // initial search mode
659  if (!lookup->GetInetref().isEmpty() && lookup->GetInetref() != "00000000" &&
660  (lookup->GetStep() == kLookupSearch || lookup->GetStep() == kLookupData))
661  {
662  // with inetref
663  lookup->SetStep(kLookupData);
664  if (!lookup->GetSubtitle().isEmpty())
665  {
666  list = grabber.SearchSubtitle(lookup->GetInetref(),
667  lookup->GetBaseTitle() /* unused */,
668  lookup->GetSubtitle(), lookup, false);
669  }
670 
671  if (list.isEmpty() && lookup->GetSeason() && lookup->GetEpisode())
672  {
673  list = grabber.LookupData(lookup->GetInetref(), lookup->GetSeason(),
674  lookup->GetEpisode(), lookup);
675  }
676 
677  if (list.isEmpty() && !lookup->GetCollectionref().isEmpty())
678  {
679  list = grabber.LookupCollection(lookup->GetCollectionref(), lookup);
680  searchcollection = true;
681  }
682  else if (list.isEmpty())
683  {
684  // We do not store CollectionRef in our database
685  // so try with the inetref, for all purposes with TVDB, they are
686  // always identical
687  list = grabber.LookupCollection(lookup->GetInetref(), lookup);
688  searchcollection = true;
689  }
690  }
691  else if (lookup->GetStep() == kLookupSearch)
692  {
693  if (lookup->GetBaseTitle().isEmpty())
694  {
695  // no point searching on nothing...
696  return list;
697  }
698  if (!lookup->GetSubtitle().isEmpty())
699  {
700  list = grabber.SearchSubtitle(lookup->GetBaseTitle(),
701  lookup->GetSubtitle(), lookup, false);
702  }
703  if (list.isEmpty())
704  {
705  list = grabber.Search(lookup->GetBaseTitle(), lookup);
706  }
707  }
708  else if (lookup->GetStep() == kLookupCollection)
709  {
710  list = grabber.LookupCollection(lookup->GetCollectionref(), lookup);
711  }
712 
713  // Collection Fallback
714  // If the lookup allows generic metadata, and the specific
715  // season and episode are not available, try for series metadata.
716  if (!searchcollection && list.isEmpty() &&
717  !lookup->GetCollectionref().isEmpty() &&
718  lookup->GetAllowGeneric() && lookup->GetStep() == kLookupData)
719  {
720  lookup->SetStep(kLookupCollection);
721  list = grabber.LookupCollection(lookup->GetCollectionref(), lookup);
722  }
723 
724  if (!list.isEmpty())
725  {
726  // mark all results so that search collection is properly handled later
727  lookup->SetIsCollection(searchcollection);
728  for (MetadataLookupList::iterator it = list.begin();
729  it != list.end(); ++it)
730  {
731  (*it)->SetIsCollection(searchcollection);
732  }
733  }
734 
735  return list;
736 }
737 
739 {
740  MetadataLookupList list;
741 
742  if (lookup->GetSubtype() != kProbableMovie &&
743  !lookup->GetSubtitle().isEmpty())
744  {
745  list.append(handleTelevision(lookup));
746  }
747 
748  if (lookup->GetSubtype() != kProbableTelevision)
749  {
750  list.append(handleMovie(lookup));
751  }
752 
753  if (list.count() == 1)
754  {
755  list[0]->SetStep(kLookupData);
756  }
757 
758  return list;
759 }
760 
762 {
763  // We only enter this mode if we are pretty darn sure this is a TV show,
764  // but we're for some reason looking up a generic, or the title didn't
765  // exactly match in one of the earlier lookups. This is a total
766  // hail mary to try to get at least *series* level info and art/inetref.
767 
768  MetadataLookupList list;
769 
770  if (lookup->GetBaseTitle().isEmpty())
771  {
772  // no point searching on nothing...
773  return list;
774  }
775 
776  // no inetref known, just pull the default grabber
778 
779  // cache some initial values so we can change them in the lookup later
780  LookupType origtype = lookup->GetSubtype();
781  int origseason = lookup->GetSeason();
782  int origepisode = lookup->GetEpisode();
783 
784  if (origseason == 0 && origepisode == 0)
785  {
786  lookup->SetSeason(1);
787  lookup->SetEpisode(1);
788  }
789 
790  list = grabber.Search(lookup->GetBaseTitle(), lookup);
791 
792  if (list.count() == 1)
793  {
794  // search was successful, rerun as normal television mode
795  lookup->SetInetref(list[0]->GetInetref());
796  lookup->SetCollectionref(list[0]->GetCollectionref());
797  list = handleTelevision(lookup);
798  }
799 
800  lookup->SetSeason(origseason);
801  lookup->SetEpisode(origepisode);
802  lookup->SetSubtype(origtype);
803 
804  return list;
805 }
806 
807 static QString getNameWithExtension(const QString &filename, const QString &type)
808 {
809  QString ret;
810  QString newname;
811  QUrl qurl(filename);
812  QString ext = QFileInfo(qurl.path()).suffix();
813 
814  if (ext.isEmpty())
815  {
816  // no extension, assume it is a directory
817  newname = filename + "/" + QFileInfo(qurl.path()).fileName() + "." + type;
818  }
819  else
820  {
821  newname = filename.left(filename.size() - ext.size()) + type;
822  }
823  QUrl xurl(newname);
824 
825  if (RemoteFile::Exists(newname))
826  ret = newname;
827 
828  return ret;
829 }
830 
831 QString MetadataDownload::getMXMLPath(const QString& filename)
832 {
833  return getNameWithExtension(filename, "mxml");
834 }
835 
836 QString MetadataDownload::getNFOPath(const QString& filename)
837 {
838  return getNameWithExtension(filename, "nfo");
839 }
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
QString getNFOPath(const QString &filename)
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
MetadataLookupList readMXML(const QString &MXMLpath, MetadataLookup *lookup, bool passseas=true)
void Run(time_t timeout=0)
Runs a command inside the /bin/sh shell. Returns immediately.
MetadataLookupList handleGame(MetadataLookup *lookup)
MetadataLookup * ParseMetadataItem(const QDomElement &item, MetadataLookup *lookup, bool passseas)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
allow access to stdout
Definition: mythsystem.h:39
QString nearestName(const QString &actual, const QStringList &candidates)
static void error(const char *str,...)
Definition: vbi.c:42
MetadataLookupList m_lookupList
void SetInetref(const QString &inetref)
LookupType GuessLookupType(ProgramInfo *pginfo)
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
MetadataLookupList Search(const QString &title, MetadataLookup *lookup, bool passseas=true)
MetadataLookupList LookupCollection(const QString &collectionref, MetadataLookup *lookup, bool passseas=true)
static guint32 * tmp
Definition: goom_core.c:35
void prependLookup(MetadataLookup *lookup)
prependLookup: Add lookup to top of the queue MetadataDownload::m_lookupList takes ownership of the g...
RefCountHandler< T > takeFirstAndDecr(void)
Removes the first item in the list and returns it.
static MetaGrabberScript GetGrabber(GrabberType defaultType, const MetadataLookup *lookup=nullptr)
bool GetAutomatic() const
QString GetSubtitle() const
MetadataType GetType() const
uint GetSeason() const
QString GetTitle() const
void SetStep(LookupStep step)
MetadataLookupList SearchSubtitle(const QString &title, const QString &subtitle, MetadataLookup *lookup, bool passseas=true)
uint GetEpisode() const
MetadataLookupList runGrabber(const QString &cmd, const QStringList &args, MetadataLookup *lookup, bool passseas=true)
virtual int IncrRef(void)
Increments reference count.
MetadataLookupList handleMovie(MetadataLookup *lookup)
handleMovie: attempt to find movie data via the following (in order) 1- Local MXML 2- Local NFO 3- By...
unsigned int findExactMatchCount(MetadataLookupList list, const QString &originaltitle, bool withArt) const
QByteArray & ReadAll()
bool GetAllowGeneric() const
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
bool isRunning(void) const
Definition: mthread.cpp:274
MetadataLookupList readNFO(const QString &NFOpath, MetadataLookup *lookup)
T * takeFirst(void)
Removes the first item in the list and returns it.
QString GetInetref() const
MetadataLookupList LookupData(const QString &inetref, MetadataLookup *lookup, bool passseas=true)
LookupType GetSubtype() const
void SetSeason(uint season)
static QString GetTelevisionGrabber()
void SetCollectionref(const QString &collectionref)
static QString GetGameGrabber()
MetadataLookup * ParseMetadataMovieNFO(const QDomElement &item, MetadataLookup *lookup)
static QString getNameWithExtension(const QString &filename, const QString &type)
LookupStep GetStep() const
uint Wait(time_t timeout=0)
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:461
bool SaveAs(QByteArray &data)
QString getMXMLPath(const QString &filename)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool isOpen(void) const
Definition: remotefile.cpp:246
MetadataLookupList handleTelevision(MetadataLookup *lookup)
handleTelevision attempt to find television data via the following (in order) 1- Local MXML 2- Local ...
QString GetCollectionref() const
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
void SetSubtype(LookupType subtype)
RefCountedList< MetadataLookup > MetadataLookupList
void SetIsCollection(bool collection)
void SetEpisode(uint episode)
bool runGrabberTest(const QString &grabberpath)
MetadataLookupList handleVideoUndetermined(MetadataLookup *lookup)
void addLookup(MetadataLookup *lookup)
addLookup: Add lookup to bottom of the queue MetadataDownload::m_lookupList takes ownership of the gi...
MetadataLookupList handleRecordingGeneric(MetadataLookup *lookup)
LookupType
static QString GetMovieGrabber()
MetadataLookup * findBestMatch(MetadataLookupList list, const QString &originaltitle) const
GrabberType GetType(void) const
QString GetFilename() const
QString GetBaseTitle() const