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  const QString &host,
29  const QString &filename,
30  const QString &title,
31  const QString &network,
32  const QString &status,
33  const QStringList &categories,
34  const float userrating,
35  uint ratingcount,
36  const QString &language,
37  const QString &subtitle,
38  const QString &tagline,
39  const QString &description,
40  uint season,
41  uint episode,
42  uint chanid,
43  const QString &channum,
44  const QString &chansign,
45  const QString &channame,
46  const QString &chanplaybackfilters,
47  const QString &recgroup,
48  const QString &playgroup,
49  const QString &seriesid,
50  const QString &programid,
51  const QString &storagegroup,
52  const QDateTime &startts,
53  const QDateTime &endts,
54  const QDateTime &recstartts,
55  const QDateTime &recendts,
56  uint programflags,
57  uint audioproperties,
58  uint videoproperties,
59  uint subtitletype,
60  const QString &certification,
61  const QStringList &countries,
62  const float popularity,
63  const uint budget,
64  const uint revenue,
65  const QString &album,
66  uint tracknum,
67  const QString &system,
68  const uint year,
69  const QDate &releasedate,
70  const QDateTime &lastupdated,
71  const uint runtime,
72  const uint runtimesecs,
73  const QString &inetref,
74  const QString &collectionref,
75  const QString &tmsref,
76  const QString &imdb,
77  const PeopleMap& people,
78  const QStringList &studios,
79  const QString &homepage,
80  const QString &trailerURL,
81  const 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(host),
95  m_filename(filename),
96  m_title(title),
97  m_network(network),
98  m_status(status),
99  m_categories(categories),
100  m_userrating(userrating),
101  m_ratingcount(ratingcount),
102  m_language(language),
103  m_subtitle(subtitle),
104  m_tagline(tagline),
105  m_description(description),
106  m_season(season),
107  m_episode(episode),
108  m_chanid(chanid),
109  m_channum(channum),
110  m_chansign(chansign),
111  m_channame(channame),
112  m_chanplaybackfilters(chanplaybackfilters),
113  m_recgroup(recgroup),
114  m_playgroup(playgroup),
115  m_seriesid(seriesid),
116  m_programid(programid),
117  m_storagegroup(storagegroup),
118  m_startts(startts),
119  m_endts(endts),
120  m_recstartts(recstartts),
121  m_recendts(recendts),
122  m_programflags(programflags),
123  m_audioproperties(audioproperties),
124  m_videoproperties(videoproperties),
125  m_subtitletype(subtitletype),
126  m_certification(certification),
127  m_countries(countries),
128  m_popularity(popularity),
129  m_budget(budget),
130  m_revenue(revenue),
131  m_album(album),
132  m_tracknum(tracknum),
133  m_system(system),
134  m_year(year),
135  m_releasedate(releasedate),
136  m_lastupdated(lastupdated),
137  m_runtime(runtime),
138  m_runtimesecs(runtimesecs),
139  m_inetref(inetref),
140  m_collectionref(collectionref),
141  m_tmsref(tmsref),
142  m_imdb(imdb),
143  m_people(people),
144  m_studios(studios),
145  m_homepage(homepage),
146  m_trailerURL(trailerURL),
147  m_artwork(artwork),
148  m_downloads(std::move(downloads))
149 {
150  QString manRecSuffix = QString(" (%1)").arg(QObject::tr("Manual Record"));
151  m_base_title = title;
152  m_base_title.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  const QString &host,
167  const QString &filename,
168  const QString &title,
169  const QStringList &categories,
170  const float userrating,
171  const QString &subtitle,
172  const QString &description,
173  uint chanid,
174  const QString &channum,
175  const QString &chansign,
176  const QString &channame,
177  const QString &chanplaybackfilters,
178  const QString &recgroup,
179  const QString &playgroup,
180  const QString &seriesid,
181  const QString &programid,
182  const QString &storagegroup,
183  const QDateTime &startts,
184  const QDateTime &endts,
185  const QDateTime &recstartts,
186  const QDateTime &recendts,
187  uint programflags,
188  uint audioproperties,
189  uint videoproperties,
190  uint subtitletype,
191  const uint year,
192  const QDate &releasedate,
193  const 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(host),
208  m_filename(filename),
209  m_title(title),
210  m_categories(categories),
211  m_userrating(userrating),
212  m_ratingcount(0),
213  m_subtitle(subtitle),
214  m_description(description),
215  m_season(0),
216  m_episode(0),
217  m_chanid(chanid),
218  m_channum(channum),
219  m_chansign(chansign),
220  m_channame(channame),
221  m_chanplaybackfilters(chanplaybackfilters),
222  m_recgroup(recgroup),
223  m_playgroup(playgroup),
224  m_seriesid(seriesid),
225  m_programid(programid),
226  m_storagegroup(storagegroup),
227  m_startts(startts),
228  m_endts(endts),
229  m_recstartts(recstartts),
230  m_recendts(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(lastupdated),
238  m_runtime(runtime),
239  m_runtimesecs(runtimesecs)
240 {
241  QString manRecSuffix = QString(" (%1)").arg(QObject::tr("Manual Record"));
242  m_base_title = title;
243  m_base_title.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  const QString &host,
258  const QString &filename,
259  const QString &title,
260  const QStringList &categories,
261  const float userrating,
262  const QString &subtitle,
263  const QString &tagline,
264  const QString &description,
265  uint season,
266  uint episode,
267  const QString &certification,
268  const uint year,
269  const QDate releasedate,
270  const uint runtime,
271  const uint runtimesecs,
272  const QString &inetref,
273  const PeopleMap& people,
274  const QString &trailerURL,
275  const 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(host),
289  m_filename(filename),
290  m_title(title),
291  m_categories(categories),
292  m_userrating(userrating),
293  m_subtitle(subtitle),
294  m_tagline(tagline),
295  m_description(description),
296  m_season(season),
297  m_episode(episode),
298  m_certification(certification),
299  m_year(year),
300  m_releasedate(releasedate),
301  m_runtime(runtime),
302  m_runtimesecs(runtimesecs),
303  m_inetref(inetref),
304  m_people(people),
305  m_trailerURL(trailerURL),
306  m_artwork(artwork),
307  m_downloads(std::move(downloads))
308 {
309  QString manRecSuffix = QString(" (%1)").arg(QObject::tr("Manual Record"));
310  m_base_title = title;
311  m_base_title.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  qVariantFromValue(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, episode = 0, chanid = 0, programflags = 0,
906  audioproperties = 0, videoproperties = 0, subtitletype = 0,
907  tracknum = 0, budget = 0, revenue = 0,
908  year = 0, runtime = 0, runtimesecs = 0, ratingcount = 0;
909  QString title, network, status, subtitle, tagline, description, certification,
910  channum, chansign, channame, chanplaybackfilters, recgroup,
911  playgroup, seriesid, programid, storagegroup, album, system,
912  inetref, collectionref, tmsref, imdb, homepage, trailerURL, language;
913  QStringList categories, countries, studios;
914  float userrating = 0;
915  float popularity = 0;
916  QDate releasedate;
917  QDateTime lastupdated, startts, endts, recstartts, recendts;
918  PeopleMap people;
919  ArtworkMap artwork;
920 
921  // Get the easy parses
922  language = item.firstChildElement("language").text();
923  title = Parse::UnescapeHTML(item.firstChildElement("title").text());
924  network = Parse::UnescapeHTML(item.firstChildElement("network").text());
925  status = Parse::UnescapeHTML(item.firstChildElement("status").text());
926  subtitle = Parse::UnescapeHTML(item.firstChildElement("subtitle").text());
927  tagline = Parse::UnescapeHTML(item.firstChildElement("tagline").text());
928  description = Parse::UnescapeHTML(item.firstChildElement("description").text());
929  album = Parse::UnescapeHTML(item.firstChildElement("albumname").text());
930  inetref = item.firstChildElement("inetref").text();
931  collectionref = item.firstChildElement("collectionref").text();
932  tmsref = item.firstChildElement("tmsref").text();
933  imdb = item.firstChildElement("imdb").text();
934  homepage = item.firstChildElement("homepage").text();
935  trailerURL = item.firstChildElement("trailer").text();
936 
937  // ProgramInfo specific parsing
938  chanid = item.firstChildElement("chanid").text().toUInt();
939  channum = item.firstChildElement("channum").text();
940  chansign = item.firstChildElement("chansign").text();
941  channame = item.firstChildElement("channame").text();
942  chanplaybackfilters = item.firstChildElement("chanplaybackfilters").text();
943  recgroup = item.firstChildElement("recgroup").text();
944  playgroup = item.firstChildElement("playgroup").text();
945  seriesid = item.firstChildElement("seriesid").text();
946  programid = item.firstChildElement("programid").text();
947  storagegroup = item.firstChildElement("storagegroup").text();
948  startts = RFC822TimeToQDateTime(item.
949  firstChildElement("startts").text());
950  endts = RFC822TimeToQDateTime(item.
951  firstChildElement("endts").text());
952  recstartts = RFC822TimeToQDateTime(item.
953  firstChildElement("recstartts").text());
954  recendts = RFC822TimeToQDateTime(item.
955  firstChildElement("recendts").text());
956  programflags = item.firstChildElement("programflags").text().toUInt();
957  audioproperties = item.firstChildElement("audioproperties").text().toUInt();
958  videoproperties = item.firstChildElement("videoproperties").text().toUInt();
959  subtitletype = item.firstChildElement("subtitletype").text().toUInt();
960 
961  QString tmpDate = item.firstChildElement("releasedate").text();
962  if (!tmpDate.isEmpty())
963  releasedate = QDate::fromString(tmpDate, "yyyy-MM-dd");
964  lastupdated = RFC822TimeToQDateTime(item.
965  firstChildElement("lastupdated").text());
966 
967  userrating = item.firstChildElement("userrating").text().toFloat();
968  ratingcount = item.firstChildElement("ratingcount").text().toUInt();
969  tracknum = item.firstChildElement("tracknum").text().toUInt();
970  popularity = item.firstChildElement("popularity").text().toFloat();
971  budget = item.firstChildElement("budget").text().toUInt();
972  revenue = item.firstChildElement("revenue").text().toUInt();
973  year = item.firstChildElement("year").text().toUInt();
974  if (!year && !releasedate.isNull())
975  year = releasedate.toString("yyyy").toUInt();
976  runtime = item.firstChildElement("runtime").text().toUInt();
977  runtimesecs = item.firstChildElement("runtimesecs").text().toUInt();
978 
979  QDomElement systems = item.firstChildElement("systems");
980  if (!systems.isNull())
981  {
982  QDomElement firstSystem = systems.firstChildElement("system");
983  if (!firstSystem.isNull())
984  system = firstSystem.text();
985  }
986 
987  // TODO: Once TMDB supports certification per-locale, come back and match
988  // locale of myth to certification locale.
989  QDomElement certifications = item.firstChildElement("certifications");
990  QList< QPair<QString,QString> > ratinglist;
991  if (!certifications.isNull())
992  {
993  QDomElement cert = certifications.firstChildElement("certification");
994  if (!cert.isNull())
995  {
996  while (!cert.isNull())
997  {
998  if (cert.hasAttribute("locale") && cert.hasAttribute("name"))
999  {
1000  QPair<QString,QString> newcert(cert.attribute("locale"),
1001  cert.attribute("name"));
1002  ratinglist.append(newcert);
1003  }
1004  cert = cert.nextSiblingElement("certification");
1005  }
1006  }
1007  }
1008  // HACK: To go away when someone supports ratings by locale.
1009  if (!ratinglist.isEmpty())
1010  certification = ratinglist.takeFirst().second;
1011 
1012  // Categories
1013  QDomElement categoriesxml = item.firstChildElement("categories");
1014  if (!categoriesxml.isNull())
1015  {
1016  QDomElement cat = categoriesxml.firstChildElement("category");
1017  if (!cat.isNull())
1018  {
1019  while (!cat.isNull())
1020  {
1021  if (cat.hasAttribute("name"))
1022  categories.append(cat.attribute("name"));
1023  cat = cat.nextSiblingElement("category");
1024  }
1025  }
1026  }
1027 
1028  // Countries
1029  QDomElement countriesxml = item.firstChildElement("countries");
1030  if (!countriesxml.isNull())
1031  {
1032  QDomElement cntry = countriesxml.firstChildElement("country");
1033  if (!cntry.isNull())
1034  {
1035  while (!cntry.isNull())
1036  {
1037  if (cntry.hasAttribute("name"))
1038  countries.append(cntry.attribute("name"));
1039  cntry = cntry.nextSiblingElement("country");
1040  }
1041  }
1042  }
1043 
1044  // Studios
1045  QDomElement studiosxml = item.firstChildElement("studios");
1046  if (!studiosxml.isNull())
1047  {
1048  QDomElement studio = studiosxml.firstChildElement("studio");
1049  if (!studio.isNull())
1050  {
1051  while (!studio.isNull())
1052  {
1053  if (studio.hasAttribute("name"))
1054  studios.append(studio.attribute("name"));
1055  studio = studio.nextSiblingElement("studio");
1056  }
1057  }
1058  }
1059 
1060  // People
1061  QDomElement peoplexml = item.firstChildElement("people");
1062  if (!peoplexml.isNull())
1063  {
1064  people = ParsePeople(peoplexml);
1065  }
1066 
1067  // Artwork
1068  QDomElement artworkxml = item.firstChildElement("images");
1069  if (!artworkxml.isNull())
1070  {
1071  artwork = ParseArtwork(artworkxml);
1072  }
1073 
1074  // Have to handle season and episode a little differently.
1075  // If the query object comes in with a season or episode number,
1076  // we want to pass that through. However, if we are doing a title/subtitle
1077  // lookup, we need to parse for season and episode.
1078  if (passseas)
1079  {
1080  season = lookup->GetSeason();
1081  episode = lookup->GetEpisode();
1082  }
1083 
1084  if (lookup->GetPreferDVDOrdering())
1085  {
1086  if (!season)
1087  {
1088  season = item.firstChildElement("dvdseason").text().toUInt();
1089  }
1090  if (!episode)
1091  {
1092  episode = item.firstChildElement("dvdepisode").text().toUInt();
1093  }
1094  }
1095 
1096  if (!season)
1097  {
1098  season = item.firstChildElement("season").text().toUInt();
1099  }
1100  if (!episode)
1101  {
1102  episode = item.firstChildElement("episode").text().toUInt();
1103  }
1104  LOG(VB_GENERAL, LOG_INFO, QString("Result Found, Season %1 Episode %2")
1105  .arg(season).arg(episode));
1106 
1107  return new MetadataLookup(lookup->GetType(), lookup->GetSubtype(),
1108  lookup->GetData(), lookup->GetStep(), lookup->GetAutomatic(),
1109  lookup->GetHandleImages(), lookup->GetAllowOverwrites(),
1110  lookup->GetAllowGeneric(), lookup->GetPreferDVDOrdering(), lookup->GetHost(),
1111  lookup->GetFilename(), title, network, status, categories, userrating,
1112  ratingcount, language, subtitle, tagline, description, season,
1113  episode, chanid, channum, chansign, channame,
1114  chanplaybackfilters, recgroup, playgroup, seriesid, programid,
1115  storagegroup, startts, endts, recstartts, recendts, programflags,
1116  audioproperties, videoproperties, subtitletype, certification,
1117  countries, popularity, budget, revenue, album, tracknum, system, year,
1118  releasedate, lastupdated, runtime, runtimesecs, inetref, collectionref,
1119  tmsref, imdb, people, studios, homepage, trailerURL, artwork, DownloadMap());
1120 }
1121 
1122 MetadataLookup* ParseMetadataMovieNFO(const QDomElement& item,
1123  MetadataLookup *lookup)
1124 {
1125  if (!lookup)
1126  return new MetadataLookup();
1127 
1128  uint year = 0, runtime = 0, runtimesecs = 0,
1129  season = 0, episode = 0;
1130  QString title, subtitle, tagline, description,
1131  inetref, trailer, certification;
1132  float userrating = 0;
1133  QDate releasedate;
1134  QStringList categories;
1135  PeopleMap people;
1136  ArtworkMap artwork;
1137 
1138  // Get the easy parses
1139  QString titletmp;
1140  if (item.tagName() == "movie")
1141  title = Parse::UnescapeHTML(item.firstChildElement("title").text());
1142  else if (item.tagName() == "episodedetails")
1143  subtitle = Parse::UnescapeHTML(item.firstChildElement("title").text());
1144  userrating = item.firstChildElement("rating").text().toFloat();
1145  year = item.firstChildElement("year").text().toUInt();
1146  season = item.firstChildElement("season").text().toUInt();
1147  episode = item.firstChildElement("episode").text().toUInt();
1148  description = Parse::UnescapeHTML(item.firstChildElement("plot").text());
1149  tagline = Parse::UnescapeHTML(item.firstChildElement("tagline").text());
1150  inetref = item.firstChildElement("id").text();
1151  trailer = item.firstChildElement("trailer").text();
1152  certification = item.firstChildElement("mpaa").text();
1153  categories.append(item.firstChildElement("genre").text());
1154 
1155  QString tmpDate = item.firstChildElement("releasedate").text();
1156  if (!tmpDate.isEmpty())
1157  releasedate = QDate::fromString(tmpDate, "yyyy-MM-dd");
1158  else if (year > 0)
1159  releasedate = QDate::fromString(QString::number(year), "yyyy");
1160 
1161  runtime = item.firstChildElement("runtime").text()
1162  .remove(QRegExp("[A-Za-z]"))
1163  .trimmed().toUInt();
1164  runtimesecs = runtime * 60;
1165 
1166  QDomElement actor = item.firstChildElement("actor");
1167  if (!actor.isNull())
1168  {
1169  while (!actor.isNull())
1170  {
1171  PersonInfo info;
1172  info.name = actor.firstChildElement("name").text();
1173  info.role = actor.firstChildElement("role").text();
1174  info.thumbnail = actor.firstChildElement("thumb").text();
1175  people.insert(kPersonActor, info);
1176  actor = actor.nextSiblingElement("actor");
1177  }
1178  }
1179 
1180  QString director = item.firstChildElement("director").text();
1181  if (!director.isEmpty())
1182  {
1183  PersonInfo info;
1184  info.name = director;
1185  people.insert(kPersonDirector, info);
1186  }
1187 
1188  return new MetadataLookup(lookup->GetType(), lookup->GetSubtype(),
1189  lookup->GetData(), lookup->GetStep(),
1190  lookup->GetAutomatic(), lookup->GetHandleImages(),
1191  lookup->GetAllowOverwrites(), lookup->GetAllowGeneric(),
1192  lookup->GetPreferDVDOrdering(), lookup->GetHost(),
1193  lookup->GetFilename(), title, categories,
1194  userrating, subtitle, tagline, description, season, episode,
1195  certification, year, releasedate, runtime, runtimesecs,
1196  inetref, people, trailer, artwork, DownloadMap());
1197 }
1198 
1199 PeopleMap ParsePeople(const QDomElement& people)
1200 {
1201  PeopleMap ret;
1202 
1203  QDomElement person = people.firstChildElement("person");
1204  if (!person.isNull())
1205  {
1206  while (!person.isNull())
1207  {
1208  if (person.hasAttribute("job"))
1209  {
1210  QString jobstring = person.attribute("job");
1211  PeopleType type;
1212  if (jobstring.toLower() == "actor")
1213  type = kPersonActor;
1214  else if (jobstring.toLower() == "author")
1215  type = kPersonAuthor;
1216  else if (jobstring.toLower() == "producer")
1218  else if (jobstring.toLower() == "executive producer")
1220  else if (jobstring.toLower() == "director")
1222  else if (jobstring.toLower() == "cinematographer")
1224  else if (jobstring.toLower() == "composer")
1226  else if (jobstring.toLower() == "editor")
1227  type = kPersonEditor;
1228  else if (jobstring.toLower() == "casting")
1230  else if (jobstring.toLower() == "artist")
1231  type = kPersonArtist;
1232  else if (jobstring.toLower() == "album artist")
1234  else if (jobstring.toLower() == "guest star")
1236  else
1237  type = kPersonActor;
1238 
1239  PersonInfo info;
1240  if (person.hasAttribute("name"))
1241  info.name = person.attribute("name");
1242  if (person.hasAttribute("character"))
1243  info.role = person.attribute("character");
1244  if (person.hasAttribute("thumb"))
1245  info.thumbnail = person.attribute("thumb");
1246  if (person.hasAttribute("url"))
1247  info.url = person.attribute("url");
1248 
1249  ret.insert(type,info);
1250  }
1251  person = person.nextSiblingElement("person");
1252  }
1253  }
1254  return ret;
1255 }
1256 
1257 ArtworkMap ParseArtwork(const QDomElement& artwork)
1258 {
1259  ArtworkMap ret;
1260 
1261  QDomElement image = artwork.firstChildElement("image");
1262  if (!image.isNull())
1263  {
1264  while (!image.isNull())
1265  {
1266  if (image.hasAttribute("type"))
1267  {
1268  QString typestring = image.attribute("type");
1270  if (typestring.toLower() == "coverart")
1272  else if (typestring.toLower() == "fanart")
1273  type = kArtworkFanart;
1274  else if (typestring.toLower() == "banner")
1275  type = kArtworkBanner;
1276  else if (typestring.toLower() == "screenshot")
1278  else if (typestring.toLower() == "poster")
1279  type = kArtworkPoster;
1280  else if (typestring.toLower() == "back cover")
1282  else if (typestring.toLower() == "inside cover")
1284  else if (typestring.toLower() == "cd image")
1286  else
1288 
1289  ArtworkInfo info;
1290  if (image.hasAttribute("thumb"))
1291  info.thumbnail = image.attribute("thumb");
1292  if (image.hasAttribute("url"))
1293  info.url = image.attribute("url");
1294  if (image.hasAttribute("width"))
1295  info.width = image.attribute("width").toUInt();
1296  else
1297  info.width = 0;
1298  if (image.hasAttribute("height"))
1299  info.height = image.attribute("height").toUInt();
1300  else
1301  info.height = 0;
1302 
1303  ret.insert(type,info);
1304  }
1305  image = image.nextSiblingElement("image");
1306  }
1307  }
1308  return ret;
1309 }
1310 
1311 int editDistance( const QString& s, const QString& t )
1312 {
1313 #define D( i, j ) d[(i) * n + (j)]
1314  int i;
1315  int j;
1316  int m = s.length() + 1;
1317  int n = t.length() + 1;
1318  int *d = new int[m * n];
1319  int result;
1320 
1321  for ( i = 0; i < m; i++ )
1322  D( i, 0 ) = i;
1323  for ( j = 0; j < n; j++ )
1324  D( 0, j ) = j;
1325  for ( i = 1; i < m; i++ )
1326  {
1327  for ( j = 1; j < n; j++ )
1328  {
1329  if ( s[i - 1] == t[j - 1] )
1330  D( i, j ) = D( i - 1, j - 1 );
1331  else
1332  {
1333  int x = D( i - 1, j );
1334  int y = D( i - 1, j - 1 );
1335  int z = D( i, j - 1 );
1336  D( i, j ) = 1 + qMin( qMin(x, y), z );
1337  }
1338  }
1339  }
1340  result = D( m - 1, n - 1 );
1341  delete[] d;
1342  return result;
1343 #undef D
1344 }
1345 
1346 QString nearestName(const QString& actual, const QStringList& candidates)
1347 {
1348  int deltaBest = 10000;
1349  int numBest = 0;
1350  int tolerance = gCoreContext->GetNumSetting("MetadataLookupTolerance", 5);
1351  QString best;
1352 
1353  QStringList::ConstIterator i = candidates.begin();
1354  while ( i != candidates.end() )
1355  {
1356  QString candidate = *i;
1357  int delta = editDistance( actual.toLower(), candidate.toLower() );
1358  if ( delta < deltaBest )
1359  {
1360  deltaBest = delta;
1361  numBest = 1;
1362  best = *i;
1363  }
1364  else if ( delta == deltaBest )
1365  {
1366  numBest++;
1367  }
1368  ++i;
1369  }
1370 
1371  if ( numBest == 1 && deltaBest <= tolerance &&
1372  actual.length() + best.length() >= 5 )
1373  return best;
1374  return QString();
1375 }
1376 
1377 QDateTime RFC822TimeToQDateTime(const QString& t)
1378 {
1379  QMap<QString, int> TimezoneOffsets;
1380 
1381  if (t.size() < 20)
1382  return QDateTime();
1383 
1384  QString time = t.simplified();
1385  short int hoursShift = 0, minutesShift = 0;
1386 
1387  QStringList tmp = time.split(' ');
1388  if (tmp.isEmpty())
1389  return QDateTime();
1390  if (tmp. at(0).contains(QRegExp("\\D")))
1391  tmp.removeFirst();
1392  if (tmp.size() != 5)
1393  return QDateTime();
1394  QString ltimezone = tmp.takeAt(tmp.size() -1);
1395  if (ltimezone.size() == 5)
1396  {
1397  bool ok;
1398  int tz = ltimezone.toInt(&ok);
1399  if(ok)
1400  {
1401  hoursShift = tz / 100;
1402  minutesShift = tz % 100;
1403  }
1404  }
1405  else
1406  hoursShift = TimezoneOffsets.value(ltimezone, 0);
1407 
1408  if (tmp.at(0).size() == 1)
1409  tmp[0].prepend("0");
1410  tmp [1].truncate(3);
1411 
1412  time = tmp.join(" ");
1413 
1414  QDateTime result;
1415  if (tmp.at(2).size() == 4)
1416  result = QLocale::c().toDateTime(time, "dd MMM yyyy hh:mm:ss");
1417  else
1418  result = QLocale::c().toDateTime(time, "dd MMM yy hh:mm:ss");
1419  if (result.isNull() || !result.isValid())
1420  return QDateTime();
1421  result = result.addSecs(hoursShift * 3600 * (-1) + minutesShift *60 * (-1));
1422  result.setTimeSpec(Qt::UTC);
1423  return result;
1424 }
QStringList GetCategories() const
float GetStars(void) const
Definition: programinfo.h:434
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
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:378
QString GetIMDB() const
const QString m_storagegroup
MetadataType
const QDate m_releasedate
QString nearestName(const QString &actual, const QStringList &candidates)
QString m_base_title
General purpose reference counter.
void SetInetref(const QString &inetref)
QString GetDescription() const
VideoArtworkType
QString GetTitle(void) const
Definition: programinfo.h:353
QDomDocument CreateMetadataXML(MetadataLookupList list)
const QString m_recgroup
QString GetTMSref() const
const QString m_homepage
QString GetChanNum() const
const QString m_language
unsigned int uint
Definition: compat.h:140
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
const QString m_chanplaybackfilters
QString GetChanNum(void) const
This is the channel "number", in the form 1, 1_2, 1-2, 1#1, etc.
Definition: programinfo.h:368
uint GetAudioProperties(void) const
Definition: programinfo.h:488
QString name
static guint32 * tmp
Definition: goom_core.c:35
uint GetRuntimeSeconds() const
QString GetChannelPlaybackFilters(void) const
Definition: programinfo.h:379
QString GetCountryCode() const
Definition: mythlocale.cpp:58
uint GetTrackNumber() const
QString GetAlbumTitle() const
uint GetVideoProperties(void) const
Definition: programinfo.h:486
bool GetAutomatic() const
QString GetInetRef(void) const
Definition: programinfo.h:429
QString GetSubtitle() const
QDate GetOriginalAirDate(void) const
Definition: programinfo.h:420
QString GetStorageGroup(void) const
Definition: programinfo.h:414
QStringList GetStudios() const
MetadataType GetType() const
float GetUserRating() const
uint GetSeason() const
QString GetTitle() const
const QString m_chansign
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:382
const QStringList m_countries
uint GetEpisode() const
uint GetVideoProperties() const
Holds information on recordings and videos.
Definition: programinfo.h:66
QString GetTagline() const
void toMap(InfoMap &map)
uint GetRevenue() const
ArtworkMap ParseArtwork(const QDomElement &artwork)
LookupStep
QString GetChannelSchedulingID(void) const
This is the unique programming identifier of a channel.
Definition: programinfo.h:375
uint32_t GetProgramFlags(void) const
Definition: programinfo.h:464
const QString m_trailerURL
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
uint GetSubtitleType() const
QString GetDescription(void) const
Definition: programinfo.h:357
QString GetBasename(void) const
Definition: programinfo.h:336
static const uint16_t * d
QString GetProgramId() const
QStringList GetCountries() const
unsigned char t
Definition: ParseText.cpp:329
const QDateTime m_recstartts
float GetPopularity() const
bool GetAllowGeneric() const
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
QString GetSubtitle(void) const
Definition: programinfo.h:355
void AddCategories(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
Default local time.
Definition: mythdate.h:16
void AddCountries(MetadataLookup *lookup, QDomElement placetoadd, QDomDocument docroot)
QString GetLanguage() const
bool GetAllowOverwrites() const
QString GetRecordingGroup(void) const
Definition: programinfo.h:411
const QDateTime m_endts
uint GetSeason(void) const
Definition: programinfo.h:358
const QString m_certification
const QString m_description
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:389
QString GetInetref() const
bool GetPreferDVDOrdering() const
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
const QString m_channame
const QDateTime m_recendts
QString GetPlaybackGroup(void) const
Definition: programinfo.h:412
const QString m_channum
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)
LookupStep GetStep() const
QString GetSeriesID(void) const
Definition: programinfo.h:427
uint GetChanId() const
QList< ArtworkInfo > ArtworkList
uint GetYearOfInitialRelease(void) const
Definition: programinfo.h:415
static QString UnescapeHTML(const QString &)
Definition: rssparse.cpp:1116
QString thumbnail
QDate GetReleaseDate() const
int GetNumSetting(const QString &key, int defaultval=0)
QMap< VideoArtworkType, ArtworkInfo > DownloadMap
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
uint GetSubtitleType(void) const
Definition: programinfo.h:484
const ArtworkMap m_artwork
QString GetCollectionref() const
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:364
const PeopleMap m_people
const QString m_playgroup
QString GetHomepage() const
#define D(i, j)
QDateTime GetLastUpdated() const
const QStringList m_studios
QString GetProgramID(void) const
Definition: programinfo.h:428
bool GetHandleImages() const
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:396
const QString m_tagline
uint GetRuntime() const
QMultiMap< PeopleType, PersonInfo > PeopleMap
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:404
PeopleMap ParsePeople(const QDomElement &people)
QDateTime GetLastModifiedTime(void) const
Definition: programinfo.h:421
const QString m_seriesid
QString GetHostname(void) const
Definition: programinfo.h:413
uint GetProgramFlags() const
void SetEpisode(uint episode)
QString m_collectionref
QString GetCategory(void) const
Definition: programinfo.h:361
QString GetChanSign() const
QDateTime GetRecStartTS() const
QDateTime GetRecEndTS() const
QDateTime GetStartTS() const
QString GetHost() const
QMultiMap< VideoArtworkType, ArtworkInfo > ArtworkMap
LookupType
PeopleType
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
const QDateTime m_lastupdated
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
const QDateTime m_startts
QString GetCertification() const
uint GetEpisode(void) const
Definition: programinfo.h:359
QString GetChanName() const
const QString m_programid
QString GetStorageGroup() const
uint GetBudget() const