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