MythTV  master
metadatacommon.cpp
Go to the documentation of this file.
1 // Qt headers
2 #include <QCoreApplication>
3 #include <QLocale>
4 #include <QMetaType>
5 #include <utility>
6 
7 #include "rssparse.h"
8 #include "programinfo.h"
9 #include "mythcorecontext.h"
10 #include "metadatacommon.h"
11 #include "mythlogging.h"
12 #include "mythlocale.h"
13 #include "mythmiscutil.h"
14 
15 static int x0 = qRegisterMetaType< RefCountHandler<MetadataLookup> >();
16 
17 // full constructor
20  LookupType subtype,
21  QVariant data,
22  LookupStep step,
23  bool automatic,
24  bool handleimages,
25  bool allowoverwrites,
26  bool allowgeneric,
27  bool preferdvdorder,
28  QString host,
29  QString filename,
30  const QString &title,
31  QString network,
32  QString status,
33  QStringList categories,
34  const float userrating,
35  uint ratingcount,
36  QString language,
37  QString subtitle,
38  QString tagline,
39  QString description,
40  uint season,
41  uint episode,
42  uint chanid,
43  QString channum,
44  QString chansign,
45  QString channame,
46  QString chanplaybackfilters,
47  QString recgroup,
48  QString playgroup,
49  QString seriesid,
50  QString programid,
51  QString storagegroup,
52  QDateTime startts,
53  QDateTime endts,
54  QDateTime recstartts,
55  QDateTime recendts,
56  uint programflags,
57  uint audioproperties,
58  uint videoproperties,
59  uint subtitletype,
60  QString certification,
61  QStringList countries,
62  const float popularity,
63  const uint budget,
64  const uint revenue,
65  QString album,
66  uint tracknum,
67  QString system,
68  const uint year,
69  const QDate &releasedate,
70  QDateTime lastupdated,
71  const uint runtime,
72  const uint runtimesecs,
73  QString inetref,
74  QString collectionref,
75  QString tmsref,
76  QString imdb,
77  PeopleMap people,
78  QStringList studios,
79  QString homepage,
80  QString trailerURL,
81  ArtworkMap artwork,
82  DownloadMap downloads) :
83  ReferenceCounter("MetadataLookup"),
84 
85  m_type(type),
86  m_subtype(subtype),
87  m_data(std::move(data)),
88  m_step(step),
89  m_automatic(automatic),
90  m_handleImages(handleimages),
91  m_allowOverwrites(allowoverwrites),
92  m_allowGeneric(allowgeneric),
93  m_dvdOrder(preferdvdorder),
94  m_host(std::move(host)),
95  m_filename(std::move(filename)),
96  m_title(title),
97  m_network(std::move(network)),
98  m_status(std::move(status)),
99  m_categories(std::move(categories)),
100  m_userRating(userrating),
101  m_ratingCount(ratingcount),
102  m_language(std::move(language)),
103  m_subtitle(std::move(subtitle)),
104  m_tagline(std::move(tagline)),
105  m_description(std::move(description)),
106  m_season(season),
107  m_episode(episode),
108  m_chanId(chanid),
109  m_chanNum(std::move(channum)),
110  m_chanSign(std::move(chansign)),
111  m_chanName(std::move(channame)),
112  m_chanPlaybackFilters(std::move(chanplaybackfilters)),
113  m_recGroup(std::move(recgroup)),
114  m_playGroup(std::move(playgroup)),
115  m_seriesId(std::move(seriesid)),
116  m_programid(std::move(programid)),
117  m_storageGroup(std::move(storagegroup)),
118  m_startTs(std::move(startts)),
119  m_endTs(std::move(endts)),
120  m_recStartTs(std::move(recstartts)),
121  m_recEndTs(std::move(recendts)),
122  m_programFlags(programflags),
123  m_audioProperties(audioproperties),
124  m_videoProperties(videoproperties),
125  m_subtitleType(subtitletype),
126  m_certification(std::move(certification)),
127  m_countries(std::move(countries)),
128  m_popularity(popularity),
129  m_budget(budget),
130  m_revenue(revenue),
131  m_album(std::move(album)),
132  m_trackNum(tracknum),
133  m_system(std::move(system)),
134  m_year(year),
135  m_releaseDate(releasedate),
136  m_lastUpdated(std::move(lastupdated)),
137  m_runtime(runtime),
138  m_runtimeSecs(runtimesecs),
139  m_inetRef(std::move(inetref)),
140  m_collectionRef(std::move(collectionref)),
141  m_tmsRef(std::move(tmsref)),
142  m_imdb(std::move(imdb)),
143  m_people(std::move(people)),
144  m_studios(std::move(studios)),
145  m_homepage(std::move(homepage)),
146  m_trailerURL(std::move(trailerURL)),
147  m_artwork(std::move(artwork)),
148  m_downloads(std::move(downloads))
149 {
150  QString manRecSuffix = QString(" (%1)").arg(QObject::tr("Manual Record"));
151  m_baseTitle = title;
152  m_baseTitle.replace(manRecSuffix,"");
153 }
154 
155 // ProgramInfo-style constructor
158  LookupType subtype,
159  QVariant data,
160  LookupStep step,
161  bool automatic,
162  bool handleimages,
163  bool allowoverwrites,
164  bool allowgeneric,
165  bool preferdvdorder,
166  QString host,
167  QString filename,
168  const QString &title,
169  QStringList categories,
170  const float userrating,
171  QString subtitle,
172  QString description,
173  uint chanid,
174  QString channum,
175  QString chansign,
176  QString channame,
177  QString chanplaybackfilters,
178  QString recgroup,
179  QString playgroup,
180  QString seriesid,
181  QString programid,
182  QString storagegroup,
183  QDateTime startts,
184  QDateTime endts,
185  QDateTime recstartts,
186  QDateTime recendts,
187  uint programflags,
188  uint audioproperties,
189  uint videoproperties,
190  uint subtitletype,
191  const uint year,
192  const QDate &releasedate,
193  QDateTime lastupdated,
194  const uint runtime,
195  const uint runtimesecs) :
196  ReferenceCounter("MetadataLookup"),
197 
198  m_type(type),
199  m_subtype(subtype),
200  m_data(std::move(data)),
201  m_step(step),
202  m_automatic(automatic),
203  m_handleImages(handleimages),
204  m_allowOverwrites(allowoverwrites),
205  m_allowGeneric(allowgeneric),
206  m_dvdOrder(preferdvdorder),
207  m_host(std::move(host)),
208  m_filename(std::move(filename)),
209  m_title(title),
210  m_categories(std::move(categories)),
211  m_userRating(userrating),
212  m_ratingCount(0),
213  m_subtitle(std::move(subtitle)),
214  m_description(std::move(description)),
215  m_season(0),
216  m_episode(0),
217  m_chanId(chanid),
218  m_chanNum(std::move(channum)),
219  m_chanSign(std::move(chansign)),
220  m_chanName(std::move(channame)),
221  m_chanPlaybackFilters(std::move(chanplaybackfilters)),
222  m_recGroup(std::move(recgroup)),
223  m_playGroup(std::move(playgroup)),
224  m_seriesId(std::move(seriesid)),
225  m_programid(std::move(programid)),
226  m_storageGroup(std::move(storagegroup)),
227  m_startTs(std::move(startts)),
228  m_endTs(std::move(endts)),
229  m_recStartTs(std::move(recstartts)),
230  m_recEndTs(std::move(recendts)),
231  m_programFlags(programflags),
232  m_audioProperties(audioproperties),
233  m_videoProperties(videoproperties),
234  m_subtitleType(subtitletype),
235  m_year(year),
236  m_releaseDate(releasedate),
237  m_lastUpdated(std::move(lastupdated)),
238  m_runtime(runtime),
239  m_runtimeSecs(runtimesecs)
240 {
241  QString manRecSuffix = QString(" (%1)").arg(QObject::tr("Manual Record"));
242  m_baseTitle = title;
243  m_baseTitle.replace(manRecSuffix,"");
244 }
245 
246 // XBMC NFO-style constructor
249  LookupType subtype,
250  QVariant data,
251  LookupStep step,
252  bool automatic,
253  bool handleimages,
254  bool allowoverwrites,
255  bool allowgeneric,
256  bool preferdvdorder,
257  QString host,
258  QString filename,
259  const QString &title,
260  QStringList categories,
261  const float userrating,
262  QString subtitle,
263  QString tagline,
264  QString description,
265  uint season,
266  uint episode,
267  QString certification,
268  const uint year,
269  const QDate releasedate,
270  const uint runtime,
271  const uint runtimesecs,
272  QString inetref,
273  PeopleMap people,
274  QString trailerURL,
275  ArtworkMap artwork,
276  DownloadMap downloads) :
277  ReferenceCounter("MetadataLookup"),
278 
279  m_type(type),
280  m_subtype(subtype),
281  m_data(std::move(data)),
282  m_step(step),
283  m_automatic(automatic),
284  m_handleImages(handleimages),
285  m_allowOverwrites(allowoverwrites),
286  m_allowGeneric(allowgeneric),
287  m_dvdOrder(preferdvdorder),
288  m_host(std::move(host)),
289  m_filename(std::move(filename)),
290  m_title(title),
291  m_categories(std::move(categories)),
292  m_userRating(userrating),
293  m_subtitle(std::move(subtitle)),
294  m_tagline(std::move(tagline)),
295  m_description(std::move(description)),
296  m_season(season),
297  m_episode(episode),
298  m_certification(std::move(certification)),
299  m_year(year),
300  m_releaseDate(releasedate),
301  m_runtime(runtime),
302  m_runtimeSecs(runtimesecs),
303  m_inetRef(std::move(inetref)),
304  m_people(std::move(people)),
305  m_trailerURL(std::move(trailerURL)),
306  m_artwork(std::move(artwork)),
307  m_downloads(std::move(downloads))
308 {
309  QString manRecSuffix = QString(" (%1)").arg(QObject::tr("Manual Record"));
310  m_baseTitle = title;
311  m_baseTitle.replace(manRecSuffix,"");
312 }
313 
314 QList<PersonInfo> MetadataLookup::GetPeople(PeopleType type) const
315 {
316  QList<PersonInfo> ret;
317  // QMultiMap::values() returns items in reverse order which we need to
318  // correct by iterating back over the list
319  // See http://qt-project.org/doc/qt-4.8/qmultimap.html#details
320  // Specifically "The items that share the same key are available from "
321  // "most recently to least recently inserted."
322  QListIterator<PersonInfo> it(m_people.values(type));
323  it.toBack();
324  while (it.hasPrevious())
325  ret.append(it.previous());
326 
327  return ret;
328 }
329 
331 {
332  ArtworkList ret;
333 
334  // QMultiMap::values() returns items in reverse order which we need to
335  // correct by iterating back over the list
336  // See http://qt-project.org/doc/qt-4.8/qmultimap.html#details
337  // Specifically "The items that share the same key are available from "
338  // "most recently to least recently inserted."
339  QListIterator<ArtworkInfo> it(m_artwork.values(type));
340  it.toBack();
341  while (it.hasPrevious())
342  ret.append(it.previous());
343 
344  return ret;
345 }
346 
347 void MetadataLookup::toMap(InfoMap &metadataMap)
348 {
349  metadataMap["filename"] = m_filename;
350  metadataMap["title"] = m_title;
351  metadataMap["network"] = m_network;
352  metadataMap["status"] = m_status;
353  metadataMap["category"] = m_categories.join(", ");
354  metadataMap["userrating"] = QString::number(m_userRating);
355  metadataMap["ratingcount"] = QString::number(m_ratingCount);
356  metadataMap["language"] = m_language;
357  metadataMap["subtitle"] = m_subtitle;
358  metadataMap["tagline"] = m_tagline;
359  metadataMap["description0"] = metadataMap["description"] = m_description;
360  metadataMap["season"] = QString::number(m_season);
361  metadataMap["episode"] = QString::number(m_episode);
362  metadataMap["chanid"] = QString::number(m_chanId);
363  metadataMap["channum"] = m_chanNum;
364  metadataMap["callsign"] = m_chanSign;
365  metadataMap["channame"] = m_chanName;
366  metadataMap["playbackfilters"] = m_chanPlaybackFilters;
367  metadataMap["recgroup"] = m_recGroup;
368  metadataMap["playgroup"] = m_playGroup;
369  metadataMap["seriesid"] = m_seriesId;
370  metadataMap["programid"] = m_programid;
371  metadataMap["storagegroup"] = m_storageGroup;
372  metadataMap["startts"] = MythDate::toString(m_startTs, MythDate::kDateFull);
373  metadataMap["endts"] = MythDate::toString(m_endTs, MythDate::kDateFull);
374  metadataMap["recstartts"] = MythDate::toString(m_recStartTs, MythDate::kDateFull);
375  metadataMap["recendts"] = MythDate::toString(m_recEndTs, MythDate::kDateFull);
376  metadataMap["certification"] = m_certification;
377  metadataMap["countries"] = m_countries.join(", ");
378  metadataMap["popularity"] = QString::number(m_popularity);
379  metadataMap["budget"] = QString::number(m_budget);
380  metadataMap["revenue"] = QString::number(m_revenue);
381  metadataMap["album"] = m_album;
382  metadataMap["tracknum"] = QString::number(m_trackNum);
383  metadataMap["system"] = m_system;
384  metadataMap["year"] = QString::number(m_year);
385 
386  metadataMap["releasedate"] = MythDate::toString(
388  metadataMap["lastupdated"] = MythDate::toString(m_lastUpdated, MythDate::kDateFull);
389 
390  metadataMap["runtime"] = QCoreApplication::translate("(Common)",
391  "%n minute(s)",
392  "",
393  m_runtime);
394 
395 
396  metadataMap["runtimesecs"] = QCoreApplication::translate("(Common)",
397  "%n second(s)",
398  "",
399  m_runtimeSecs);
400  metadataMap["inetref"] = m_inetRef;
401  metadataMap["collectionref"] = m_collectionRef;
402  metadataMap["tmsref"] = m_tmsRef;
403  metadataMap["imdb"] = m_imdb;
404  metadataMap["studios"] = m_studios.join(", ");
405  metadataMap["homepage"] = m_homepage;
406  metadataMap["trailer"] = m_trailerURL;
407 }
408 
410 {
411  uint runtimesecs = pginfo->GetRecordingStartTime()
412  .secsTo(pginfo->GetRecordingEndTime());
413  uint runtime = (runtimesecs/60);
414 
416  QVariant::fromValue(pginfo), kLookupData, false, false, false, false, false,
417  pginfo->GetHostname(),pginfo->GetBasename(),pginfo->GetTitle(),
418  QStringList() << pginfo->GetCategory(), pginfo->GetStars() * 10,
419  pginfo->GetSubtitle(), pginfo->GetDescription(), pginfo->GetChanID(),
420  pginfo->GetChanNum(), pginfo->GetChannelSchedulingID(),
421  pginfo->GetChannelName(), pginfo->GetChannelPlaybackFilters(),
422  pginfo->GetRecordingGroup(), pginfo->GetPlaybackGroup(),
423  pginfo->GetSeriesID(), pginfo->GetProgramID(), pginfo->GetStorageGroup(),
424  pginfo->GetScheduledStartTime(), pginfo->GetScheduledEndTime(),
425  pginfo->GetRecordingStartTime(), pginfo->GetRecordingEndTime(),
426  pginfo->GetProgramFlags(), pginfo->GetAudioProperties(),
427  pginfo->GetVideoProperties(), pginfo->GetSubtitleType(),
428  pginfo->GetYearOfInitialRelease(), pginfo->GetOriginalAirDate(),
429  pginfo->GetLastModifiedTime(), runtime, runtimesecs);
430 
431  ret->SetSeason(pginfo->GetSeason());
432  ret->SetEpisode(pginfo->GetEpisode());
433  ret->SetInetref(pginfo->GetInetRef());
434 
435  return ret;
436 }
437 
439 {
440  QDomDocument doc("MythMetadataXML");
441 
442  QDomElement root = doc.createElement("metadata");
443  doc.appendChild(root);
444 
445  for (MetadataLookupList::const_iterator i = list.begin();
446  i != list.end(); ++i)
447  {
448  CreateMetadataXMLItem(*i, root, doc);
449  }
450 
451  return doc;
452 }
453 
454 QDomDocument CreateMetadataXML(MetadataLookup *lookup)
455 {
456  QDomDocument doc("MythMetadataXML");
457 
458  QDomElement root = doc.createElement("metadata");
459  doc.appendChild(root);
460 
461  CreateMetadataXMLItem(lookup, root, doc);
462 
463  return doc;
464 }
465 
466 QDomDocument CreateMetadataXML(ProgramInfo *pginfo)
467 {
468  QDomDocument doc("MythMetadataXML");
469 
470  MetadataLookup *lookup = LookupFromProgramInfo(pginfo);
471  if (lookup)
472  doc = CreateMetadataXML(lookup);
473 
474  lookup->DecrRef();
475  lookup = nullptr;
476 
477  return doc;
478 }
479 
481  QDomElement placetoadd,
482  QDomDocument docroot)
483 {
484  if (!lookup)
485  return;
486 
487  QDomElement item = docroot.createElement("item");
488  placetoadd.appendChild(item);
489  QString RFC822("ddd, d MMMM yyyy hh:mm:ss");
490 
491  // Language
492  if (!lookup->GetLanguage().isEmpty())
493  {
494  QDomElement language = docroot.createElement("language");
495  item.appendChild(language);
496  language.appendChild(docroot.createTextNode(lookup->GetLanguage()));
497  }
498  // Title
499  if (!lookup->GetTitle().isEmpty())
500  {
501  QDomElement title = docroot.createElement("title");
502  item.appendChild(title);
503  title.appendChild(docroot.createTextNode(lookup->GetTitle()));
504  }
505  // Subtitle
506  if (!lookup->GetSubtitle().isEmpty())
507  {
508  QDomElement subtitle = docroot.createElement("subtitle");
509  item.appendChild(subtitle);
510  subtitle.appendChild(docroot.createTextNode(lookup->GetSubtitle()));
511  }
512  // Network
513  if (!lookup->GetNetwork().isEmpty())
514  {
515  QDomElement network = docroot.createElement("network");
516  item.appendChild(network);
517  network.appendChild(docroot.createTextNode(lookup->GetNetwork()));
518  }
519  // Status
520  if (!lookup->GetStatus().isEmpty())
521  {
522  QDomElement status = docroot.createElement("status");
523  item.appendChild(status);
524  status.appendChild(docroot.createTextNode(lookup->GetStatus()));
525  }
526  // Season
527  if (lookup->GetSeason() > 0 || lookup->GetEpisode() > 0)
528  {
529  QDomElement season = docroot.createElement("season");
530  item.appendChild(season);
531  season.appendChild(docroot.createTextNode(
532  QString::number(lookup->GetSeason())));
533  }
534  // Episode
535  if (lookup->GetSeason() > 0 || lookup->GetEpisode() > 0)
536  {
537  QDomElement episode = docroot.createElement("episode");
538  item.appendChild(episode);
539  episode.appendChild(docroot.createTextNode(
540  QString::number(lookup->GetEpisode())));
541  }
542  // Tagline
543  if (!lookup->GetTagline().isEmpty())
544  {
545  QDomElement tagline = docroot.createElement("tagline");
546  item.appendChild(tagline);
547  tagline.appendChild(docroot.createTextNode(lookup->GetTagline()));
548  }
549  // Plot
550  if (!lookup->GetDescription().isEmpty())
551  {
552  QDomElement desc = docroot.createElement("description");
553  item.appendChild(desc);
554  desc.appendChild(docroot.createTextNode(lookup->GetDescription()));
555  }
556  // Album Name
557  if (!lookup->GetAlbumTitle().isEmpty())
558  {
559  QDomElement albumname = docroot.createElement("albumname");
560  item.appendChild(albumname);
561  albumname.appendChild(docroot.createTextNode(lookup->GetAlbumTitle()));
562  }
563  // Inetref
564  if (!lookup->GetInetref().isEmpty())
565  {
566  QDomElement inetref = docroot.createElement("inetref");
567  item.appendChild(inetref);
568  inetref.appendChild(docroot.createTextNode(lookup->GetInetref()));
569  }
570  // Collectionref
571  if (!lookup->GetCollectionref().isEmpty())
572  {
573  QDomElement collectionref = docroot.createElement("collectionref");
574  item.appendChild(collectionref);
575  collectionref.appendChild(docroot.createTextNode(lookup->GetCollectionref()));
576  }
577  // TMSref/SeriesID
578  if (!lookup->GetTMSref().isEmpty())
579  {
580  QDomElement tmsref = docroot.createElement("tmsref");
581  item.appendChild(tmsref);
582  tmsref.appendChild(docroot.createTextNode(lookup->GetTMSref()));
583  }
584  // IMDB
585  if (!lookup->GetIMDB().isEmpty())
586  {
587  QDomElement imdb = docroot.createElement("imdb");
588  item.appendChild(imdb);
589  imdb.appendChild(docroot.createTextNode(lookup->GetIMDB()));
590  }
591  // Home Page
592  if (!lookup->GetHomepage().isEmpty())
593  {
594  QDomElement homepage = docroot.createElement("homepage");
595  item.appendChild(homepage);
596  homepage.appendChild(docroot.createTextNode(lookup->GetHomepage()));
597  }
598  // Trailer
599  if (!lookup->GetTrailerURL().isEmpty())
600  {
601  QDomElement trailer = docroot.createElement("trailer");
602  item.appendChild(trailer);
603  trailer.appendChild(docroot.createTextNode(lookup->GetTrailerURL()));
604  }
605  // Chan ID
606  if (lookup->GetChanId() > 0)
607  {
608  QDomElement chanid = docroot.createElement("chanid");
609  item.appendChild(chanid);
610  chanid.appendChild(docroot.createTextNode(
611  QString::number(lookup->GetChanId())));
612  }
613  // Channel Number
614  if (!lookup->GetChanNum().isEmpty())
615  {
616  QDomElement channum = docroot.createElement("channum");
617  item.appendChild(channum);
618  channum.appendChild(docroot.createTextNode(lookup->GetChanNum()));
619  }
620  // Callsign
621  if (!lookup->GetChanSign().isEmpty())
622  {
623  QDomElement callsign = docroot.createElement("chansign");
624  item.appendChild(callsign);
625  callsign.appendChild(docroot.createTextNode(lookup->GetChanSign()));
626  }
627  // Channel Name
628  if (!lookup->GetChanName().isEmpty())
629  {
630  QDomElement channame = docroot.createElement("channame");
631  item.appendChild(channame);
632  channame.appendChild(docroot.createTextNode(lookup->GetChanName()));
633  }
634  // Playback Filters
635  if (!lookup->GetChanPlaybackFilters().isEmpty())
636  {
637  QDomElement filters = docroot.createElement("filters");
638  item.appendChild(filters);
639  filters.appendChild(docroot.createTextNode(
640  lookup->GetChanPlaybackFilters()));
641  }
642  // Recording Group
643  if (!lookup->GetRecGroup().isEmpty())
644  {
645  QDomElement recgroup = docroot.createElement("recgroup");
646  item.appendChild(recgroup);
647  recgroup.appendChild(docroot.createTextNode(lookup->GetRecGroup()));
648  }
649  // Playback Group
650  if (!lookup->GetPlayGroup().isEmpty())
651  {
652  QDomElement playgroup = docroot.createElement("playgroup");
653  item.appendChild(playgroup);
654  playgroup.appendChild(docroot.createTextNode(lookup->GetPlayGroup()));
655  }
656  // SeriesID
657  if (!lookup->GetSeriesId().isEmpty())
658  {
659  QDomElement seriesid = docroot.createElement("seriesid");
660  item.appendChild(seriesid);
661  seriesid.appendChild(docroot.createTextNode(lookup->GetSeriesId()));
662  }
663  // ProgramID
664  if (!lookup->GetProgramId().isEmpty())
665  {
666  QDomElement programid = docroot.createElement("programid");
667  item.appendChild(programid);
668  programid.appendChild(docroot.createTextNode(lookup->GetProgramId()));
669  }
670  // Storage Group
671  if (!lookup->GetStorageGroup().isEmpty())
672  {
673  QDomElement sgroup = docroot.createElement("storagegroup");
674  item.appendChild(sgroup);
675  sgroup.appendChild(docroot.createTextNode(lookup->GetStorageGroup()));
676  }
677  // Start TS
678  if (!lookup->GetStartTS().isNull())
679  {
680  QDomElement startts = docroot.createElement("startts");
681  item.appendChild(startts);
682  startts.appendChild(docroot.createTextNode(
683  lookup->GetStartTS().toString(RFC822)));
684  }
685  // End TS
686  if (!lookup->GetEndTS().isNull())
687  {
688  QDomElement endts = docroot.createElement("endts");
689  item.appendChild(endts);
690  endts.appendChild(docroot.createTextNode(
691  lookup->GetEndTS().toString(RFC822)));
692  }
693  // Rec Start TS
694  if (!lookup->GetRecStartTS().isNull())
695  {
696  QDomElement recstartts = docroot.createElement("recstartts");
697  item.appendChild(recstartts);
698  recstartts.appendChild(docroot.createTextNode(
699  lookup->GetRecStartTS().toString(RFC822)));
700  }
701  // Rec End TS
702  if (!lookup->GetRecEndTS().isNull())
703  {
704  QDomElement recendts = docroot.createElement("recendts");
705  item.appendChild(recendts);
706  recendts.appendChild(docroot.createTextNode(
707  lookup->GetRecEndTS().toString(RFC822)));
708  }
709  // Program Flags
710  if (lookup->GetProgramFlags() > 0)
711  {
712  QDomElement progflags = docroot.createElement("programflags");
713  item.appendChild(progflags);
714  progflags.appendChild(docroot.createTextNode(
715  QString::number(lookup->GetProgramFlags())));
716  }
717  // Audio Properties
718  if (lookup->GetAudioProperties() > 0)
719  {
720  QDomElement audioprops = docroot.createElement("audioproperties");
721  item.appendChild(audioprops);
722  audioprops.appendChild(docroot.createTextNode(
723  QString::number(lookup->GetAudioProperties())));
724  }
725  // Video Properties
726  if (lookup->GetVideoProperties() > 0)
727  {
728  QDomElement videoprops = docroot.createElement("videoproperties");
729  item.appendChild(videoprops);
730  videoprops.appendChild(docroot.createTextNode(
731  QString::number(lookup->GetVideoProperties())));
732  }
733  // Subtitle Type
734  if (lookup->GetSubtitleType() > 0)
735  {
736  QDomElement subprops = docroot.createElement("subtitletype");
737  item.appendChild(subprops);
738  subprops.appendChild(docroot.createTextNode(
739  QString::number(lookup->GetSubtitleType())));
740  }
741  // Release Date
742  if (!lookup->GetReleaseDate().isNull())
743  {
744  QDomElement releasedate = docroot.createElement("releasedate");
745  item.appendChild(releasedate);
746  releasedate.appendChild(docroot.createTextNode(
747  lookup->GetReleaseDate().toString("yyyy-MM-dd")));
748  }
749  // Last Updated
750  if (!lookup->GetLastUpdated().isNull())
751  {
752  QDomElement lastupdated = docroot.createElement("lastupdated");
753  item.appendChild(lastupdated);
754  lastupdated.appendChild(docroot.createTextNode(
755  lookup->GetLastUpdated().toString(RFC822)));
756  }
757  // User Rating
758  if (lookup->GetUserRating() > 0)
759  {
760  QDomElement userrating = docroot.createElement("userrating");
761  item.appendChild(userrating);
762  userrating.appendChild(docroot.createTextNode(QString::number(
763  lookup->GetUserRating())));
764  }
765  // Rating Count
766  if (lookup->GetRatingCount() > 0)
767  {
768  QDomElement ratingcount = docroot.createElement("ratingcount");
769  item.appendChild(ratingcount);
770  ratingcount.appendChild(docroot.createTextNode(QString::number(
771  lookup->GetRatingCount())));
772  }
773  // Track Number
774  if (lookup->GetTrackNumber() > 0)
775  {
776  QDomElement tracknum = docroot.createElement("tracknum");
777  item.appendChild(tracknum);
778  tracknum.appendChild(docroot.createTextNode(QString::number(
779  lookup->GetTrackNumber())));
780  }
781  // Popularity
782  if (lookup->GetPopularity() > 0)
783  {
784  QDomElement popularity = docroot.createElement("popularity");
785  item.appendChild(popularity);
786  popularity.appendChild(docroot.createTextNode(QString::number(
787  lookup->GetPopularity())));
788  }
789  // Budget
790  if (lookup->GetBudget() > 0)
791  {
792  QDomElement budget = docroot.createElement("budget");
793  item.appendChild(budget);
794  budget.appendChild(docroot.createTextNode(QString::number(
795  lookup->GetBudget())));
796  }
797  // Revenue
798  if (lookup->GetRevenue() > 0)
799  {
800  QDomElement revenue = docroot.createElement("revenue");
801  item.appendChild(revenue);
802  revenue.appendChild(docroot.createTextNode(QString::number(
803  lookup->GetRevenue())));
804  }
805  // Runtime
806  if (lookup->GetRuntime() > 0)
807  {
808  QDomElement runtime = docroot.createElement("runtime");
809  item.appendChild(runtime);
810  runtime.appendChild(docroot.createTextNode(QString::number(
811  lookup->GetRuntime())));
812  }
813  // Runtimesecs
814  if (lookup->GetRuntimeSeconds() > 0)
815  {
816  QDomElement runtimesecs = docroot.createElement("runtimesecs");
817  item.appendChild(runtimesecs);
818  runtimesecs.appendChild(docroot.createTextNode(QString::number(
819  lookup->GetRuntimeSeconds())));
820  }
821 
822  if (!lookup->GetCertification().isEmpty())
823  AddCertifications(lookup, item, docroot);
824  if (!lookup->GetCategories().empty())
825  AddCategories(lookup, item, docroot);
826  if (!lookup->GetStudios().empty())
827  AddStudios(lookup, item, docroot);
828  if (!lookup->GetCountries().empty())
829  AddCountries(lookup, item, docroot);
830 }
831 
833  QDomElement placetoadd,
834  QDomDocument docroot)
835 {
836  QString certstr = lookup->GetCertification();
837  QDomElement certifications = docroot.createElement("certifications");
838  placetoadd.appendChild(certifications);
839 
840  QDomElement cert = docroot.createElement("certification");
841  certifications.appendChild(cert);
842  cert.setAttribute("locale", gCoreContext->GetLocale()->GetCountryCode());
843  cert.setAttribute("name", certstr);
844 }
845 
847  QDomElement placetoadd,
848  QDomDocument docroot)
849 {
850  QStringList cats = lookup->GetCategories();
851  QDomElement categories = docroot.createElement("categories");
852  placetoadd.appendChild(categories);
853 
854  for (QStringList::const_iterator i = cats.begin();
855  i != cats.end(); ++i)
856  {
857  QDomElement cat = docroot.createElement("category");
858  categories.appendChild(cat);
859  cat.setAttribute("type", "genre");
860  cat.setAttribute("name", *i);
861  }
862 }
863 
865  QDomElement placetoadd,
866  QDomDocument docroot)
867 {
868  QStringList studs = lookup->GetStudios();
869  QDomElement studios = docroot.createElement("studios");
870  placetoadd.appendChild(studios);
871 
872  for (QStringList::const_iterator i = studs.begin();
873  i != studs.end(); ++i)
874  {
875  QDomElement stud = docroot.createElement("studio");
876  studios.appendChild(stud);
877  stud.setAttribute("name", *i);
878  }
879 }
880 
882  QDomElement placetoadd,
883  QDomDocument docroot)
884 {
885  QStringList counts = lookup->GetCountries();
886  QDomElement countries = docroot.createElement("countries");
887  placetoadd.appendChild(countries);
888 
889  for (QStringList::const_iterator i = counts.begin();
890  i != counts.end(); ++i)
891  {
892  QDomElement count = docroot.createElement("country");
893  countries.appendChild(count);
894  count.setAttribute("name", *i);
895  }
896 }
897 
898 MetadataLookup* ParseMetadataItem(const QDomElement& item,
899  MetadataLookup *lookup,
900  bool passseas)
901 {
902  if (!lookup)
903  return new MetadataLookup();
904 
905  uint season = 0;
906  uint episode = 0;
907  uint chanid = 0;
908  uint programflags = 0;
909  uint audioproperties = 0;
910  uint videoproperties = 0;
911  uint subtitletype = 0;
912  uint tracknum = 0;
913  uint budget = 0;
914  uint revenue = 0;
915  uint year = 0;
916  uint runtime = 0;
917  uint runtimesecs = 0;
918  uint ratingcount = 0;
919  QString title;
920  QString network;
921  QString status;
922  QString subtitle;
923  QString tagline;
924  QString description;
925  QString certification;
926  QString channum;
927  QString chansign;
928  QString channame;
929  QString chanplaybackfilters;
930  QString recgroup;
931  QString playgroup;
932  QString seriesid;
933  QString programid;
934  QString storagegroup;
935  QString album;
936  QString system;
937  QString inetref;
938  QString collectionref;
939  QString tmsref;
940  QString imdb;
941  QString homepage;
942  QString trailerURL;
943  QString language;
944  QStringList categories;
945  QStringList countries;
946  QStringList studios;
947  float userrating = 0;
948  float popularity = 0;
949  QDate releasedate;
950  QDateTime lastupdated;
951  QDateTime startts;
952  QDateTime endts;
953  QDateTime recstartts;
954  QDateTime recendts;
955  PeopleMap people;
956  ArtworkMap artwork;
957 
958  // Get the easy parses
959  language = item.firstChildElement("language").text();
960  title = Parse::UnescapeHTML(item.firstChildElement("title").text());
961  network = Parse::UnescapeHTML(item.firstChildElement("network").text());
962  status = Parse::UnescapeHTML(item.firstChildElement("status").text());
963  subtitle = Parse::UnescapeHTML(item.firstChildElement("subtitle").text());
964  tagline = Parse::UnescapeHTML(item.firstChildElement("tagline").text());
965  description = Parse::UnescapeHTML(item.firstChildElement("description").text());
966  album = Parse::UnescapeHTML(item.firstChildElement("albumname").text());
967  inetref = item.firstChildElement("inetref").text();
968  collectionref = item.firstChildElement("collectionref").text();
969  tmsref = item.firstChildElement("tmsref").text();
970  imdb = item.firstChildElement("imdb").text();
971  homepage = item.firstChildElement("homepage").text();
972  trailerURL = item.firstChildElement("trailer").text();
973 
974  // ProgramInfo specific parsing
975  chanid = item.firstChildElement("chanid").text().toUInt();
976  channum = item.firstChildElement("channum").text();
977  chansign = item.firstChildElement("chansign").text();
978  channame = item.firstChildElement("channame").text();
979  chanplaybackfilters = item.firstChildElement("chanplaybackfilters").text();
980  recgroup = item.firstChildElement("recgroup").text();
981  playgroup = item.firstChildElement("playgroup").text();
982  seriesid = item.firstChildElement("seriesid").text();
983  programid = item.firstChildElement("programid").text();
984  storagegroup = item.firstChildElement("storagegroup").text();
985  startts = RFC822TimeToQDateTime(item.
986  firstChildElement("startts").text());
987  endts = RFC822TimeToQDateTime(item.
988  firstChildElement("endts").text());
989  recstartts = RFC822TimeToQDateTime(item.
990  firstChildElement("recstartts").text());
991  recendts = RFC822TimeToQDateTime(item.
992  firstChildElement("recendts").text());
993  programflags = item.firstChildElement("programflags").text().toUInt();
994  audioproperties = item.firstChildElement("audioproperties").text().toUInt();
995  videoproperties = item.firstChildElement("videoproperties").text().toUInt();
996  subtitletype = item.firstChildElement("subtitletype").text().toUInt();
997 
998  QString tmpDate = item.firstChildElement("releasedate").text();
999  if (!tmpDate.isEmpty())
1000  releasedate = QDate::fromString(tmpDate, "yyyy-MM-dd");
1001  lastupdated = RFC822TimeToQDateTime(item.
1002  firstChildElement("lastupdated").text());
1003 
1004  userrating = item.firstChildElement("userrating").text().toFloat();
1005  ratingcount = item.firstChildElement("ratingcount").text().toUInt();
1006  tracknum = item.firstChildElement("tracknum").text().toUInt();
1007  popularity = item.firstChildElement("popularity").text().toFloat();
1008  budget = item.firstChildElement("budget").text().toUInt();
1009  revenue = item.firstChildElement("revenue").text().toUInt();
1010  year = item.firstChildElement("year").text().toUInt();
1011  if (!year && !releasedate.isNull())
1012  year = releasedate.toString("yyyy").toUInt();
1013  runtime = item.firstChildElement("runtime").text().toUInt();
1014  runtimesecs = item.firstChildElement("runtimesecs").text().toUInt();
1015 
1016  QDomElement systems = item.firstChildElement("systems");
1017  if (!systems.isNull())
1018  {
1019  QDomElement firstSystem = systems.firstChildElement("system");
1020  if (!firstSystem.isNull())
1021  system = firstSystem.text();
1022  }
1023 
1024  // TODO: Once TMDB supports certification per-locale, come back and match
1025  // locale of myth to certification locale.
1026  QDomElement certifications = item.firstChildElement("certifications");
1027  QList< QPair<QString,QString> > ratinglist;
1028  if (!certifications.isNull())
1029  {
1030  QDomElement cert = certifications.firstChildElement("certification");
1031  if (!cert.isNull())
1032  {
1033  while (!cert.isNull())
1034  {
1035  if (cert.hasAttribute("locale") && cert.hasAttribute("name"))
1036  {
1037  QPair<QString,QString> newcert(cert.attribute("locale"),
1038  cert.attribute("name"));
1039  ratinglist.append(newcert);
1040  }
1041  cert = cert.nextSiblingElement("certification");
1042  }
1043  }
1044  }
1045  // HACK: To go away when someone supports ratings by locale.
1046  if (!ratinglist.isEmpty())
1047  certification = ratinglist.takeFirst().second;
1048 
1049  // Categories
1050  QDomElement categoriesxml = item.firstChildElement("categories");
1051  if (!categoriesxml.isNull())
1052  {
1053  QDomElement cat = categoriesxml.firstChildElement("category");
1054  if (!cat.isNull())
1055  {
1056  while (!cat.isNull())
1057  {
1058  if (cat.hasAttribute("name"))
1059  categories.append(cat.attribute("name"));
1060  cat = cat.nextSiblingElement("category");
1061  }
1062  }
1063  }
1064 
1065  // Countries
1066  QDomElement countriesxml = item.firstChildElement("countries");
1067  if (!countriesxml.isNull())
1068  {
1069  QDomElement cntry = countriesxml.firstChildElement("country");
1070  if (!cntry.isNull())
1071  {
1072  while (!cntry.isNull())
1073  {
1074  if (cntry.hasAttribute("name"))
1075  countries.append(cntry.attribute("name"));
1076  cntry = cntry.nextSiblingElement("country");
1077  }
1078  }
1079  }
1080 
1081  // Studios
1082  QDomElement studiosxml = item.firstChildElement("studios");
1083  if (!studiosxml.isNull())
1084  {
1085  QDomElement studio = studiosxml.firstChildElement("studio");
1086  if (!studio.isNull())
1087  {
1088  while (!studio.isNull())
1089  {
1090  if (studio.hasAttribute("name"))
1091  studios.append(studio.attribute("name"));
1092  studio = studio.nextSiblingElement("studio");
1093  }
1094  }
1095  }
1096 
1097  // People
1098  QDomElement peoplexml = item.firstChildElement("people");
1099  if (!peoplexml.isNull())
1100  {
1101  people = ParsePeople(peoplexml);
1102  }
1103 
1104  // Artwork
1105  QDomElement artworkxml = item.firstChildElement("images");
1106  if (!artworkxml.isNull())
1107  {
1108  artwork = ParseArtwork(artworkxml);
1109  }
1110 
1111  // Have to handle season and episode a little differently.
1112  // If the query object comes in with a season or episode number,
1113  // we want to pass that through. However, if we are doing a title/subtitle
1114  // lookup, we need to parse for season and episode.
1115  if (passseas)
1116  {
1117  season = lookup->GetSeason();
1118  episode = lookup->GetEpisode();
1119  }
1120 
1121  if (lookup->GetPreferDVDOrdering())
1122  {
1123  if (!season)
1124  {
1125  season = item.firstChildElement("dvdseason").text().toUInt();
1126  }
1127  if (!episode)
1128  {
1129  episode = item.firstChildElement("dvdepisode").text().toUInt();
1130  }
1131  }
1132 
1133  if (!season)
1134  {
1135  season = item.firstChildElement("season").text().toUInt();
1136  }
1137  if (!episode)
1138  {
1139  episode = item.firstChildElement("episode").text().toUInt();
1140  }
1141  LOG(VB_GENERAL, LOG_INFO, QString("Result Found, Season %1 Episode %2")
1142  .arg(season).arg(episode));
1143 
1144  return new MetadataLookup(lookup->GetType(), lookup->GetSubtype(),
1145  lookup->GetData(), lookup->GetStep(), lookup->GetAutomatic(),
1146  lookup->GetHandleImages(), lookup->GetAllowOverwrites(),
1147  lookup->GetAllowGeneric(), lookup->GetPreferDVDOrdering(), lookup->GetHost(),
1148  lookup->GetFilename(), title, network, status, categories, userrating,
1149  ratingcount, language, subtitle, tagline, description, season,
1150  episode, chanid, channum, chansign, channame,
1151  chanplaybackfilters, recgroup, playgroup, seriesid, programid,
1152  storagegroup, startts, endts, recstartts, recendts, programflags,
1153  audioproperties, videoproperties, subtitletype, certification,
1154  countries, popularity, budget, revenue, album, tracknum, system, year,
1155  releasedate, lastupdated, runtime, runtimesecs, inetref, collectionref,
1156  tmsref, imdb, people, studios, homepage, trailerURL, artwork, DownloadMap());
1157 }
1158 
1159 MetadataLookup* ParseMetadataMovieNFO(const QDomElement& item,
1160  MetadataLookup *lookup)
1161 {
1162  if (!lookup)
1163  return new MetadataLookup();
1164 
1165  uint year = 0;
1166  uint runtime = 0;
1167  uint runtimesecs = 0;
1168  uint season = 0;
1169  uint episode = 0;
1170  QString title;
1171  QString subtitle;
1172  QString tagline;
1173  QString description;
1174  QString inetref;
1175  QString trailer;
1176  QString certification;
1177  float userrating = 0;
1178  QDate releasedate;
1179  QStringList categories;
1180  PeopleMap people;
1181  ArtworkMap artwork;
1182 
1183  // Get the easy parses
1184  QString titletmp;
1185  if (item.tagName() == "movie")
1186  title = Parse::UnescapeHTML(item.firstChildElement("title").text());
1187  else if (item.tagName() == "episodedetails")
1188  subtitle = Parse::UnescapeHTML(item.firstChildElement("title").text());
1189  userrating = item.firstChildElement("rating").text().toFloat();
1190  year = item.firstChildElement("year").text().toUInt();
1191  season = item.firstChildElement("season").text().toUInt();
1192  episode = item.firstChildElement("episode").text().toUInt();
1193  description = Parse::UnescapeHTML(item.firstChildElement("plot").text());
1194  tagline = Parse::UnescapeHTML(item.firstChildElement("tagline").text());
1195  inetref = item.firstChildElement("id").text();
1196  trailer = item.firstChildElement("trailer").text();
1197  certification = item.firstChildElement("mpaa").text();
1198  categories.append(item.firstChildElement("genre").text());
1199 
1200  QString tmpDate = item.firstChildElement("releasedate").text();
1201  if (!tmpDate.isEmpty())
1202  releasedate = QDate::fromString(tmpDate, "yyyy-MM-dd");
1203  else if (year > 0)
1204  releasedate = QDate::fromString(QString::number(year), "yyyy");
1205 
1206  runtime = item.firstChildElement("runtime").text()
1207  .remove(QRegExp("[A-Za-z]"))
1208  .trimmed().toUInt();
1209  runtimesecs = runtime * 60;
1210 
1211  QDomElement actor = item.firstChildElement("actor");
1212  if (!actor.isNull())
1213  {
1214  while (!actor.isNull())
1215  {
1216  PersonInfo info;
1217  info.name = actor.firstChildElement("name").text();
1218  info.role = actor.firstChildElement("role").text();
1219  info.thumbnail = actor.firstChildElement("thumb").text();
1220  people.insert(kPersonActor, info);
1221  actor = actor.nextSiblingElement("actor");
1222  }
1223  }
1224 
1225  QString director = item.firstChildElement("director").text();
1226  if (!director.isEmpty())
1227  {
1228  PersonInfo info;
1229  info.name = director;
1230  people.insert(kPersonDirector, info);
1231  }
1232 
1233  return new MetadataLookup(lookup->GetType(), lookup->GetSubtype(),
1234  lookup->GetData(), lookup->GetStep(),
1235  lookup->GetAutomatic(), lookup->GetHandleImages(),
1236  lookup->GetAllowOverwrites(), lookup->GetAllowGeneric(),
1237  lookup->GetPreferDVDOrdering(), lookup->GetHost(),
1238  lookup->GetFilename(), title, categories,
1239  userrating, subtitle, tagline, description, season, episode,
1240  certification, year, releasedate, runtime, runtimesecs,
1241  inetref, people, trailer, artwork, DownloadMap());
1242 }
1243 
1244 PeopleMap ParsePeople(const QDomElement& people)
1245 {
1246  PeopleMap ret;
1247 
1248  QDomElement person = people.firstChildElement("person");
1249  if (!person.isNull())
1250  {
1251  while (!person.isNull())
1252  {
1253  if (person.hasAttribute("job"))
1254  {
1255  QString jobstring = person.attribute("job");
1257  if (jobstring.toLower() == "actor")
1258  type = kPersonActor; // NOLINT(bugprone-branch-clone)
1259  else if (jobstring.toLower() == "author")
1260  type = kPersonAuthor;
1261  else if (jobstring.toLower() == "producer")
1263  else if (jobstring.toLower() == "executive producer")
1265  else if (jobstring.toLower() == "director")
1267  else if (jobstring.toLower() == "cinematographer")
1269  else if (jobstring.toLower() == "composer")
1271  else if (jobstring.toLower() == "editor")
1272  type = kPersonEditor;
1273  else if (jobstring.toLower() == "casting")
1275  else if (jobstring.toLower() == "artist")
1276  type = kPersonArtist;
1277  else if (jobstring.toLower() == "album artist")
1279  else if (jobstring.toLower() == "guest star")
1281  else
1282  type = kPersonActor;
1283 
1284  PersonInfo info;
1285  if (person.hasAttribute("name"))
1286  info.name = person.attribute("name");
1287  if (person.hasAttribute("character"))
1288  info.role = person.attribute("character");
1289  if (person.hasAttribute("thumb"))
1290  info.thumbnail = person.attribute("thumb");
1291  if (person.hasAttribute("url"))
1292  info.url = person.attribute("url");
1293 
1294  ret.insert(type,info);
1295  }
1296  person = person.nextSiblingElement("person");
1297  }
1298  }
1299  return ret;
1300 }
1301 
1302 ArtworkMap ParseArtwork(const QDomElement& artwork)
1303 {
1304  ArtworkMap ret;
1305 
1306  QDomElement image = artwork.firstChildElement("image");
1307  if (!image.isNull())
1308  {
1309  while (!image.isNull())
1310  {
1311  if (image.hasAttribute("type"))
1312  {
1313  QString typestring = image.attribute("type");
1315  if (typestring.toLower() == "coverart")
1316  type = kArtworkCoverart; // NOLINT(bugprone-branch-clone)
1317  else if (typestring.toLower() == "fanart")
1318  type = kArtworkFanart;
1319  else if (typestring.toLower() == "banner")
1320  type = kArtworkBanner;
1321  else if (typestring.toLower() == "screenshot")
1323  else if (typestring.toLower() == "poster")
1324  type = kArtworkPoster;
1325  else if (typestring.toLower() == "back cover")
1327  else if (typestring.toLower() == "inside cover")
1329  else if (typestring.toLower() == "cd image")
1331  else
1333 
1334  ArtworkInfo info;
1335  if (image.hasAttribute("thumb"))
1336  info.thumbnail = image.attribute("thumb");
1337  if (image.hasAttribute("url"))
1338  info.url = image.attribute("url");
1339  if (image.hasAttribute("width"))
1340  info.width = image.attribute("width").toUInt();
1341  else
1342  info.width = 0;
1343  if (image.hasAttribute("height"))
1344  info.height = image.attribute("height").toUInt();
1345  else
1346  info.height = 0;
1347 
1348  ret.insert(type,info);
1349  }
1350  image = image.nextSiblingElement("image");
1351  }
1352  }
1353  return ret;
1354 }
1355 
1356 int editDistance( const QString& s, const QString& t )
1357 {
1358 #define D( i, j ) d[(i) * n + (j)]
1359  int m = s.length() + 1;
1360  int n = t.length() + 1;
1361  int *d = new int[m * n];
1362 
1363  for ( int i = 0; i < m; i++ )
1364  D( i, 0 ) = i;
1365  for ( int j = 0; j < n; j++ )
1366  D( 0, j ) = j;
1367  for ( int i = 1; i < m; i++ )
1368  {
1369  for ( int j = 1; j < n; j++ )
1370  {
1371  if ( s[i - 1] == t[j - 1] )
1372  D( i, j ) = D( i - 1, j - 1 );
1373  else
1374  {
1375  int x = D( i - 1, j );
1376  int y = D( i - 1, j - 1 );
1377  int z = D( i, j - 1 );
1378  D( i, j ) = 1 + qMin( qMin(x, y), z );
1379  }
1380  }
1381  }
1382  int result = D( m - 1, n - 1 );
1383  delete[] d;
1384  return result;
1385 #undef D
1386 }
1387 
1388 QString nearestName(const QString& actual, const QStringList& candidates)
1389 {
1390  int deltaBest = 10000;
1391  int numBest = 0;
1392  int tolerance = gCoreContext->GetNumSetting("MetadataLookupTolerance", 5);
1393  QString best;
1394 
1395  QStringList::ConstIterator i = candidates.begin();
1396  while ( i != candidates.end() )
1397  {
1398  QString candidate = *i;
1399  int delta = editDistance( actual.toLower(), candidate.toLower() );
1400  if ( delta < deltaBest )
1401  {
1402  deltaBest = delta;
1403  numBest = 1;
1404  best = *i;
1405  }
1406  else if ( delta == deltaBest )
1407  {
1408  numBest++;
1409  }
1410  ++i;
1411  }
1412 
1413  if ( numBest == 1 && deltaBest <= tolerance &&
1414  actual.length() + best.length() >= 5 )
1415  return best;
1416  return QString();
1417 }
1418 
1419 QDateTime RFC822TimeToQDateTime(const QString& t)
1420 {
1421  QMap<QString, int> TimezoneOffsets;
1422 
1423  if (t.size() < 20)
1424  return QDateTime();
1425 
1426  QString time = t.simplified();
1427  short int hoursShift = 0;
1428  short int minutesShift = 0;
1429 
1430  QStringList tmp = time.split(' ');
1431  if (tmp.isEmpty())
1432  return QDateTime();
1433  if (tmp. at(0).contains(QRegExp("\\D")))
1434  tmp.removeFirst();
1435  if (tmp.size() != 5)
1436  return QDateTime();
1437  QString ltimezone = tmp.takeAt(tmp.size() -1);
1438  if (ltimezone.size() == 5)
1439  {
1440  bool ok = false;
1441  int tz = ltimezone.toInt(&ok);
1442  if(ok)
1443  {
1444  hoursShift = tz / 100;
1445  minutesShift = tz % 100;
1446  }
1447  }
1448  else
1449  hoursShift = TimezoneOffsets.value(ltimezone, 0);
1450 
1451  if (tmp.at(0).size() == 1)
1452  tmp[0].prepend("0");
1453  tmp [1].truncate(3);
1454 
1455  time = tmp.join(" ");
1456 
1457  QDateTime result;
1458  if (tmp.at(2).size() == 4)
1459  result = QLocale::c().toDateTime(time, "dd MMM yyyy hh:mm:ss");
1460  else
1461  result = QLocale::c().toDateTime(time, "dd MMM yy hh:mm:ss");
1462  if (result.isNull() || !result.isValid())
1463  return QDateTime();
1464  result = result.addSecs(hoursShift * 3600 * (-1) + minutesShift *60 * (-1));
1465  result.setTimeSpec(Qt::UTC);
1466  return result;
1467 }
static QString UnescapeHTML(const QString &escaped)
Definition: rssparse.cpp:1130
QStringList GetCategories() const
float GetStars(void) const
Definition: programinfo.h:436
QString GetNetwork() const
QString GetChanPlaybackFilters() const
MetadataLookup * ParseMetadataItem(const QDomElement &item, MetadataLookup *lookup, bool passseas)
QString GetTrailerURL() const
ArtworkList GetArtwork(VideoArtworkType type) const
QString url
MythLocale * GetLocale(void) const
QString GetStatus() const
QString GetSeriesId() const
const QString m_seriesId
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:380
QString GetIMDB() const
MetadataType
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
const QDateTime m_recStartTs
QString nearestName(const QString &actual, const QStringList &candidates)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
General purpose reference counter.
QString GetDescription() const
VideoArtworkType
QString GetTitle(void) const
Definition: programinfo.h:355
const QString m_chanNum
QDomDocument CreateMetadataXML(MetadataLookupList list)
QString GetTMSref() const
const QString m_homepage
QString GetChanNum() const
QString m_collectionRef
const QString m_language
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
uint GetAudioProperties() const
QList< PersonInfo > GetPeople(PeopleType type) const
QString GetPlayGroup() const
static int x0
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:370
uint GetAudioProperties(void) const
Definition: programinfo.h:490
QString name
static guint32 * tmp
Definition: goom_core.c:35
uint GetRuntimeSeconds() const
QString GetChannelPlaybackFilters(void) const
Definition: programinfo.h:381
QString GetCountryCode() const
Definition: mythlocale.cpp:58
QList< ArtworkInfo > ArtworkList
uint GetTrackNumber() const
QString GetAlbumTitle() const
uint GetVideoProperties(void) const
Definition: programinfo.h:488
bool GetAutomatic() const
QString GetInetRef(void) const
Definition: programinfo.h:431
QString GetSubtitle() const
QDate GetOriginalAirDate(void) const
Definition: programinfo.h:422
QString GetStorageGroup(void) const
Definition: programinfo.h:416
QStringList GetStudios() const
MetadataType GetType() const
float GetUserRating() const
uint GetSeason() const
QString GetTitle() const
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:384
const QString m_chanPlaybackFilters
const QString m_recGroup
const QStringList m_countries
uint GetEpisode() const
uint GetVideoProperties() const
Holds information on recordings and videos.
Definition: programinfo.h:67
QString GetTagline() const
void toMap(InfoMap &map)
uint GetRevenue() const
ArtworkMap ParseArtwork(const QDomElement &artwork)
LookupStep
const QString m_chanName
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:377
uint32_t GetProgramFlags(void) const
Definition: programinfo.h:466
const QString m_trailerURL
uint GetSubtitleType() const
QString GetDescription(void) const
Definition: programinfo.h:359
QString GetBasename(void) const
Definition: programinfo.h:338
static const uint16_t * d
QString GetProgramId() const
QStringList GetCountries() const
Default local time.
Definition: mythdate.h:16
float GetPopularity() const
bool GetAllowGeneric() const
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QString GetSubtitle(void) const
Definition: programinfo.h:357
void AddCategories(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
void AddCountries(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
QString GetLanguage() const
bool GetAllowOverwrites() const
QString GetRecordingGroup(void) const
Definition: programinfo.h:413
uint GetSeason(void) const
Definition: programinfo.h:360
const QString m_certification
unsigned int uint
Definition: compat.h:140
const QString m_description
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:391
QString GetInetref() const
bool GetPreferDVDOrdering() const
const QDateTime m_recEndTs
QString role
int editDistance(const QString &s, const QString &t)
LookupType GetSubtype() const
MetadataLookup * LookupFromProgramInfo(ProgramInfo *pginfo)
void SetSeason(uint season)
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
QString GetPlaybackGroup(void) const
Definition: programinfo.h:414
void AddStudios(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
QVariant GetData() const
uint GetRatingCount() const
void AddCertifications(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
MetadataLookup * ParseMetadataMovieNFO(const QDomElement &item, MetadataLookup *lookup)
const QDate m_releaseDate
LookupStep GetStep() const
QString GetSeriesID(void) const
Definition: programinfo.h:429
uint GetChanId() const
const QString m_chanSign
uint GetYearOfInitialRelease(void) const
Definition: programinfo.h:417
QString thumbnail
QDate GetReleaseDate() const
int GetNumSetting(const QString &key, int defaultval=0)
const QDateTime m_startTs
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QMap< VideoArtworkType, ArtworkInfo > DownloadMap
uint GetSubtitleType(void) const
Definition: programinfo.h:486
const QString m_storageGroup
const ArtworkMap m_artwork
QString GetCollectionref() const
const QDateTime m_lastUpdated
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:366
const PeopleMap m_people
QString GetHomepage() const
QMultiMap< PeopleType, PersonInfo > PeopleMap
#define D(i, j)
QDateTime GetLastUpdated() const
const QStringList m_studios
QString GetProgramID(void) const
Definition: programinfo.h:430
bool GetHandleImages() const
const QString m_playGroup
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:398
const QString m_tagline
uint GetRuntime() const
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:406
PeopleMap ParsePeople(const QDomElement &people)
QDateTime GetLastModifiedTime(void) const
Definition: programinfo.h:423
QString GetHostname(void) const
Definition: programinfo.h:415
uint GetProgramFlags() const
QString GetCategory(void) const
Definition: programinfo.h:363
QString GetChanSign() const
QMultiMap< VideoArtworkType, ArtworkInfo > ArtworkMap
QDateTime GetRecStartTS() const
const QDateTime m_endTs
QDateTime GetRecEndTS() const
QDateTime GetStartTS() const
QString GetHost() const
LookupType
PeopleType
const QStringList m_categories
void CreateMetadataXMLItem(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
QString GetRecGroup() const
QDateTime GetEndTS() const
QDateTime RFC822TimeToQDateTime(const QString &t)
QString GetFilename() const
QString GetCertification() const
uint GetEpisode(void) const
Definition: programinfo.h:361
QString GetChanName() const
const QString m_programid
QString GetStorageGroup() const
uint GetBudget() const