MythTV  master
rssparse.cpp
Go to the documentation of this file.
1 #include <QFile>
2 #include <QDataStream>
3 #include <QDomDocument>
4 #include <QDomImplementation>
5 #include <QHash>
6 #include <QLocale>
7 #include <QUrl>
8 #include <QFileInfo>
9 
10 #include "rssparse.h"
11 #include "mythcontext.h"
12 #include "mythdirs.h"
13 #include "mythdate.h"
14 #include "programinfo.h" // for format_season_and_episode()
15 #include "mythsorthelper.h"
16 
17 #if QT_VERSION < QT_VERSION_CHECK(5,15,2)
18 #define capturedView capturedRef
19 #endif
20 
21 ResultItem::ResultItem(const QString& title, const QString& sortTitle,
22  const QString& subtitle, const QString& sortSubtitle,
23  const QString& desc, const QString& URL,
24  const QString& thumbnail, const QString& mediaURL,
25  const QString& author, const QDateTime& date,
26  const QString& time, const QString& rating,
27  const off_t filesize, const QString& player,
28  const QStringList& playerargs, const QString& download,
29  const QStringList& downloadargs, const uint width,
30  const uint height, const QString& language,
31  const bool downloadable, const QStringList& countries,
32  const uint season, const uint episode,
33  const bool customhtml)
34 {
35  m_title = title;
36  m_sorttitle = sortTitle;
37  m_subtitle = subtitle;
38  m_sortsubtitle = sortSubtitle;
39  m_desc = desc;
40  m_url = URL;
41  m_thumbnail = thumbnail;
42  m_mediaURL = mediaURL;
43  m_author = author;
44  if (!date.isNull())
45  m_date = date;
46  else
47  m_date = QDateTime();
48  m_time = time;
49  m_rating = rating;
50  m_filesize = filesize;
51  m_player = player;
52  m_playerargs = playerargs;
53  m_download = download;
54  m_downloadargs = downloadargs;
55  m_width = width;
56  m_height = height;
57  m_language = language;
58  m_downloadable = downloadable;
59  m_countries = countries;
60  m_season = season;
61  m_episode = episode;
62  m_customhtml = customhtml;
63 
65 }
66 
68 {
69  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
70 
71  if (m_sorttitle.isEmpty() and not m_title.isEmpty())
72  m_sorttitle = sh->doTitle(m_title);
73  if (m_sortsubtitle.isEmpty() and not m_subtitle.isEmpty())
74  m_sortsubtitle = sh->doTitle(m_subtitle);
75 }
76 
77 void ResultItem::toMap(InfoMap &metadataMap)
78 {
79  metadataMap["title"] = m_title;
80  metadataMap["sorttitle"] = m_sorttitle;
81  metadataMap["subtitle"] = m_subtitle;
82  metadataMap["sortsubtitle"] = m_sortsubtitle;
83  metadataMap["description"] = m_desc;
84  metadataMap["url"] = m_url;
85  metadataMap["thumbnail"] = m_thumbnail;
86  metadataMap["mediaurl"] = m_mediaURL;
87  metadataMap["author"] = m_author;
88 
89  if (m_date.isNull())
90  metadataMap["date"] = QString();
91  else
92  metadataMap["date"] = MythDate::toString(m_date, MythDate::kDateFull);
93 
94  if (m_time.toInt() == 0)
95  metadataMap["length"] = QString();
96  else
97  {
98  QTime time(0,0,0,0);
99  int secs = m_time.toInt();
100  QTime fin = time.addSecs(secs);
101  QString format;
102  if (secs >= 3600)
103  format = "H:mm:ss";
104  else if (secs >= 600)
105  format = "mm:ss";
106  else if (secs >= 60)
107  format = "m:ss";
108  else
109  format = ":ss";
110  metadataMap["length"] = fin.toString(format);
111  }
112 
113  if (m_rating == nullptr || m_rating.isNull())
114  metadataMap["rating"] = QString();
115  else
116  metadataMap["rating"] = m_rating;
117 
118  if (m_filesize == -1)
119  metadataMap["filesize"] = QString();
120  else if (m_filesize == 0 && !m_downloadable)
121  metadataMap["filesize"] = QObject::tr("Web Only");
122  else if (m_filesize == 0 && m_downloadable)
123  metadataMap["filesize"] = QObject::tr("Downloadable");
124  else
125  metadataMap["filesize"] = QString::number(m_filesize);
126 
127  QString tmpSize = QString("%1 ")
128  .arg(m_filesize / 1024.0 / 1024.0, 0,'f',2);
129  tmpSize += QObject::tr("MB", "Megabytes");
130  if (m_filesize == -1)
131  metadataMap["filesize_str"] = QString();
132  else if (m_filesize == 0 && !m_downloadable)
133  metadataMap["filesize_str"] = QObject::tr("Web Only");
134  else if (m_filesize == 0 && m_downloadable)
135  metadataMap["filesize_str"] = QObject::tr("Downloadable");
136  else
137  metadataMap["filesize"] = tmpSize;
138 
139  metadataMap["player"] = m_player;
140  metadataMap["playerargs"] = m_playerargs.join(", ");
141  metadataMap["downloader"] = m_download;
142  metadataMap["downloadargs"] = m_downloadargs.join(", ");
143  if (m_width == 0)
144  metadataMap["width"] = QString();
145  else
146  metadataMap["width"] = QString::number(m_width);
147  if (m_height == 0)
148  metadataMap["height"] = QString();
149  else
150  metadataMap["height"] = QString::number(m_height);
151  if (m_width == 0 || m_height == 0)
152  metadataMap["resolution"] = QString();
153  else
154  metadataMap["resolution"] = QString("%1x%2").arg(m_width).arg(m_height);
155  metadataMap["language"] = m_language;
156  metadataMap["countries"] = m_countries.join(", ");
157 
158 
159  if (m_season > 0 || m_episode > 0)
160  {
161  metadataMap["season"] = format_season_and_episode(m_season, 1);
162  metadataMap["episode"] = format_season_and_episode(m_episode, 1);
163  metadataMap["s##e##"] = metadataMap["s00e00"] = QString("s%1e%2")
166  metadataMap["##x##"] = metadataMap["00x00"] = QString("%1x%2")
169  }
170  else
171  {
172  metadataMap["season"] = QString();
173  metadataMap["episode"] = QString();
174  metadataMap["s##e##"] = metadataMap["s00e00"] = QString();
175  metadataMap["##x##"] = metadataMap["00x00"] = QString();
176  }
177 }
178 
179 namespace
180 {
181  QList<QDomNode> GetDirectChildrenNS(const QDomElement& elem,
182  const QString& ns, const QString& name)
183  {
184  QList<QDomNode> result;
185  QDomNodeList unf = elem.elementsByTagNameNS(ns, name);
186  for (int i = 0, size = unf.size(); i < size; ++i)
187  if (unf.at(i).parentNode() == elem)
188  result << unf.at(i);
189  return result;
190  }
191 }
192 
194 {
196  {
197  QString m_url;
198  QString m_rating;
199  QString m_ratingScheme;
200  QString m_title;
201  QString m_description;
202  QString m_keywords;
203  QString m_copyrightUrl;
206  int m_ratingCount {0};
207  int m_ratingMin {0};
208  int m_ratingMax {0};
209  int m_views {0};
210  int m_favs {0};
211  QString m_tags;
212  QList<MRSSThumbnail> m_thumbnails;
213  QList<MRSSCredit> m_credits;
214  QList<MRSSComment> m_comments;
215  QList<MRSSPeerLink> m_peerLinks;
216  QList<MRSSScene> m_scenes;
217 
218  ArbitraryLocatedData() = default;
219 
224  {
225  if (!child.m_url.isEmpty())
226  m_url = child.m_url;
227  if (!child.m_rating.isEmpty())
228  m_rating = child.m_rating;
229  if (!child.m_ratingScheme.isEmpty())
231  if (!child.m_title.isEmpty())
232  m_title = child.m_title;
233  if (!child.m_description.isEmpty())
235  if (!child.m_keywords.isEmpty())
236  m_keywords = child.m_keywords;
237  if (!child.m_copyrightUrl.isEmpty())
239  if (!child.m_copyrightText.isEmpty())
241  if (child.m_ratingAverage != 0)
243  if (child.m_ratingCount != 0)
245  if (child.m_ratingMin != 0)
246  m_ratingMin = child.m_ratingMin;
247  if (child.m_ratingMax != 0)
248  m_ratingMax = child.m_ratingMax;
249  if (child.m_views != 0)
250  m_views = child.m_views;
251  if (child.m_favs != 0)
252  m_favs = child.m_favs;
253  if (!child.m_tags.isEmpty())
254  m_tags = child.m_tags;
255 
256  m_thumbnails += child.m_thumbnails;
257  m_credits += child.m_credits;
258  m_comments += child.m_comments;
259  m_peerLinks += child.m_peerLinks;
260  m_scenes += child.m_scenes;
261  return *this;
262  }
263  };
264 
265 
266 public:
267  MRSSParser() = default;
268 
269  QList<MRSSEntry> operator() (const QDomElement& item)
270  {
271  QList<MRSSEntry> result;
272 
273  QDomNodeList groups = item.elementsByTagNameNS(Parse::kMediaRSS,
274  "group");
275 
276  for (int i = 0; i < groups.size(); ++i)
277  result += CollectChildren(groups.at(i).toElement());
278 
279  result += CollectChildren(item);
280 
281  return result;
282  }
283 
284 private:
285 
286  static QList<MRSSEntry> CollectChildren(const QDomElement& holder)
287  {
288  QList<MRSSEntry> result;
289  QDomNodeList entries = holder.elementsByTagNameNS(Parse::kMediaRSS,
290  "content");
291 
292  for (int i = 0; i < entries.size(); ++i)
293  {
294  MRSSEntry entry;
295 
296  QDomElement en = entries.at(i).toElement();
298 
299  if (en.hasAttribute("url"))
300  entry.URL = en.attribute("url");
301  else
302  entry.URL = d.m_url;
303 
304  entry.Size = en.attribute("fileSize").toInt();
305  entry.Type = en.attribute("type");
306  entry.Medium = en.attribute("medium");
307  entry.IsDefault = (en.attribute("isDefault") == "true");
308  entry.Expression = en.attribute("expression");
309  if (entry.Expression.isEmpty())
310  entry.Expression = "full";
311  entry.Bitrate = en.attribute("bitrate").toInt();
312  entry.Framerate = en.attribute("framerate").toDouble();
313  entry.SamplingRate = en.attribute("samplingrate").toDouble();
314  entry.Channels = en.attribute("channels").toInt();
315  if (!en.attribute("duration").isNull())
316  entry.Duration = en.attribute("duration").toInt();
317  else
318  entry.Duration = 0;
319  if (!en.attribute("width").isNull())
320  entry.Width = en.attribute("width").toInt();
321  else
322  entry.Width = 0;
323  if (!en.attribute("height").isNull())
324  entry.Height = en.attribute("height").toInt();
325  else
326  entry.Height = 0;
327  if (!en.attribute("lang").isNull())
328  entry.Lang = en.attribute("lang");
329  else
330  entry.Lang = QString();
331 
332  if (!en.attribute("rating").isNull())
333  entry.Rating = d.m_rating;
334  else
335  entry.Rating = QString();
336  entry.RatingScheme = d.m_ratingScheme;
337  entry.Title = d.m_title;
338  entry.Description = d.m_description;
339  entry.Keywords = d.m_keywords;
340  entry.CopyrightURL = d.m_copyrightUrl;
341  entry.CopyrightText = d.m_copyrightText;
342  if (d.m_ratingAverage != 0)
343  entry.RatingAverage = d.m_ratingAverage;
344  else
345  entry.RatingAverage = 0;
346  entry.RatingCount = d.m_ratingCount;
347  entry.RatingMin = d.m_ratingMin;
348  entry.RatingMax = d.m_ratingMax;
349  entry.Views = d.m_views;
350  entry.Favs = d.m_favs;
351  entry.Tags = d.m_tags;
352  entry.Thumbnails = d.m_thumbnails;
353  entry.Credits = d.m_credits;
354  entry.Comments = d.m_comments;
355  entry.PeerLinks = d.m_peerLinks;
356  entry.Scenes = d.m_scenes;
357 
358  result << entry;
359  }
360  return result;
361  }
362 
363  static ArbitraryLocatedData GetArbitraryLocatedDataFor(const QDomElement& holder)
364  {
365  ArbitraryLocatedData result;
366 
367  QList<QDomElement> parents;
368  QDomElement parent = holder;
369  while (!parent.isNull())
370  {
371  parents.prepend(parent);
372  parent = parent.parentNode().toElement();
373  }
374 
375  for (const auto& p : qAsConst(parents))
376  result += CollectArbitraryLocatedData(p);
377 
378  return result;
379  }
380 
381  static QString GetURL(const QDomElement& element)
382  {
383  QList<QDomNode> elems = GetDirectChildrenNS(element, Parse::kMediaRSS,
384  "player");
385  if (elems.empty())
386  return QString();
387 
388  return elems.at(0).toElement().attribute("url");
389  }
390 
391  static QString GetTitle(const QDomElement& element)
392  {
393  QList<QDomNode> elems = GetDirectChildrenNS(element, Parse::kMediaRSS,
394  "title");
395 
396  if (elems.empty())
397  return QString();
398 
399  QDomElement telem = elems.at(0).toElement();
400  return Parse::UnescapeHTML(telem.text());
401  }
402 
403  static QString GetDescription(const QDomElement& element)
404  {
405  QList<QDomNode> elems = GetDirectChildrenNS(element, Parse::kMediaRSS,
406  "description");
407 
408  if (elems.empty())
409  return QString();
410 
411  QDomElement telem = elems.at(0).toElement();
412  return Parse::UnescapeHTML(telem.text());
413  }
414 
415  static QString GetKeywords(const QDomElement& element)
416  {
417  QList<QDomNode> elems = GetDirectChildrenNS(element, Parse::kMediaRSS,
418  "keywords");
419 
420  if (elems.empty())
421  return QString();
422 
423  QDomElement telem = elems.at(0).toElement();
424  return telem.text();
425  }
426 
427  static int GetInt(const QDomElement& elem, const QString& attrname)
428  {
429  if (elem.hasAttribute(attrname))
430  {
431  bool ok = false;
432  int result = elem.attribute(attrname).toInt(&ok);
433  if (ok)
434  return result;
435  }
436  return int();
437  }
438 
439  static QList<MRSSThumbnail> GetThumbnails(const QDomElement& element)
440  {
441  QList<MRSSThumbnail> result;
442  QList<QDomNode> thumbs = GetDirectChildrenNS(element, Parse::kMediaRSS,
443  "thumbnail");
444  for (const auto& dom : qAsConst(thumbs))
445  {
446  QDomElement thumbNode = dom.toElement();
447  int widthOpt = GetInt(thumbNode, "width");
448  int width = widthOpt ? widthOpt : 0;
449  int heightOpt = GetInt(thumbNode, "height");
450  int height = heightOpt ? heightOpt : 0;
451  MRSSThumbnail thumb =
452  {
453  thumbNode.attribute("url"),
454  width,
455  height,
456  thumbNode.attribute("time")
457  };
458  result << thumb;
459  }
460  return result;
461  }
462 
463  static QList<MRSSCredit> GetCredits(const QDomElement& element)
464  {
465  QList<MRSSCredit> result;
466  QList<QDomNode> credits = GetDirectChildrenNS(element, Parse::kMediaRSS,
467  "credit");
468 
469  for (const auto& dom : qAsConst(credits))
470  {
471  QDomElement creditNode = dom.toElement();
472  if (!creditNode.hasAttribute("role"))
473  continue;
474  MRSSCredit credit =
475  {
476  creditNode.attribute("role"),
477  creditNode.text()
478  };
479  result << credit;
480  }
481  return result;
482  }
483 
484  static QList<MRSSComment> GetComments(const QDomElement& element)
485  {
486  QList<MRSSComment> result;
487  QList<QDomNode> commParents = GetDirectChildrenNS(element, Parse::kMediaRSS,
488  "comments");
489 
490  if (!commParents.empty())
491  {
492  QDomNodeList comments = commParents.at(0).toElement()
493  .elementsByTagNameNS(Parse::kMediaRSS,
494  "comment");
495  for (int i = 0; i < comments.size(); ++i)
496  {
497  MRSSComment comment =
498  {
499  QObject::tr("Comments"),
500  comments.at(i).toElement().text()
501  };
502  result << comment;
503  }
504  }
505 
506  QList<QDomNode> respParents = GetDirectChildrenNS(element, Parse::kMediaRSS,
507  "responses");
508 
509  if (!respParents.empty())
510  {
511  QDomNodeList responses = respParents.at(0).toElement()
512  .elementsByTagNameNS(Parse::kMediaRSS,
513  "response");
514  for (int i = 0; i < responses.size(); ++i)
515  {
516  MRSSComment comment =
517  {
518  QObject::tr("Responses"),
519  responses.at(i).toElement().text()
520  };
521  result << comment;
522  }
523  }
524 
525  QList<QDomNode> backParents = GetDirectChildrenNS(element, Parse::kMediaRSS,
526  "backLinks");
527 
528  if (!backParents.empty())
529  {
530  QDomNodeList backlinks = backParents.at(0).toElement()
531  .elementsByTagNameNS(Parse::kMediaRSS,
532  "backLink");
533  for (int i = 0; i < backlinks.size(); ++i)
534  {
535  MRSSComment comment =
536  {
537  QObject::tr("Backlinks"),
538  backlinks.at(i).toElement().text()
539  };
540  result << comment;
541  }
542  }
543  return result;
544  }
545 
546  static QList<MRSSPeerLink> GetPeerLinks(const QDomElement& element)
547  {
548  QList<MRSSPeerLink> result;
549  QList<QDomNode> links = GetDirectChildrenNS(element, Parse::kMediaRSS,
550  "peerLink");
551 
552  for (const auto& dom : qAsConst(links))
553  {
554  QDomElement linkNode = dom.toElement();
555  MRSSPeerLink pl =
556  {
557  linkNode.attribute("type"),
558  linkNode.attribute("href")
559  };
560  result << pl;
561  }
562  return result;
563  }
564 
565  static QList<MRSSScene> GetScenes(const QDomElement& element)
566  {
567  QList<MRSSScene> result;
568  QList<QDomNode> scenesNode = GetDirectChildrenNS(element, Parse::kMediaRSS,
569  "scenes");
570 
571  if (!scenesNode.empty())
572  {
573  QDomNodeList scenesNodes = scenesNode.at(0).toElement()
574  .elementsByTagNameNS(Parse::kMediaRSS, "scene");
575 
576  for (int i = 0; i < scenesNodes.size(); ++i)
577  {
578  QDomElement sceneNode = scenesNodes.at(i).toElement();
579  MRSSScene scene =
580  {
581  sceneNode.firstChildElement("sceneTitle").text(),
582  sceneNode.firstChildElement("sceneDescription").text(),
583  sceneNode.firstChildElement("sceneStartTime").text(),
584  sceneNode.firstChildElement("sceneEndTime").text()
585  };
586  result << scene;
587  }
588  }
589  return result;
590  }
591 
592  static ArbitraryLocatedData CollectArbitraryLocatedData(const QDomElement& element)
593  {
594 
595  QString rating;
596  QString rscheme;
597  {
598  QList<QDomNode> elems = GetDirectChildrenNS(element, Parse::kMediaRSS,
599  "rating");
600 
601  if (!elems.empty())
602  {
603  QDomElement relem = elems.at(0).toElement();
604  rating = relem.text();
605  if (relem.hasAttribute("scheme"))
606  rscheme = relem.attribute("scheme");
607  else
608  rscheme = "urn:simple";
609  }
610  }
611 
612  QString curl;
613  QString ctext;
614  {
615  QList<QDomNode> elems = GetDirectChildrenNS(element, Parse::kMediaRSS,
616  "copyright");
617 
618  if (!elems.empty())
619  {
620  QDomElement celem = elems.at(0).toElement();
621  ctext = celem.text();
622  if (celem.hasAttribute("url"))
623  curl = celem.attribute("url");
624  }
625  }
626 
627  int raverage = 0;
628  int rcount = 0;
629  int rmin = 0;
630  int rmax = 0;
631  int views = 0;
632  int favs = 0;
633  QString tags;
634  {
635  QList<QDomNode> comms = GetDirectChildrenNS(element, Parse::kMediaRSS,
636  "community");
637  if (!comms.empty())
638  {
639  QDomElement comm = comms.at(0).toElement();
640  QDomNodeList stars = comm.elementsByTagNameNS(Parse::kMediaRSS,
641  "starRating");
642  if (stars.size())
643  {
644  QDomElement ratingDom = stars.at(0).toElement();
645  raverage = GetInt(ratingDom, "average");
646  rcount = GetInt(ratingDom, "count");
647  rmin = GetInt(ratingDom, "min");
648  rmax = GetInt(ratingDom, "max");
649  }
650 
651  QDomNodeList stats = comm.elementsByTagNameNS(Parse::kMediaRSS,
652  "statistics");
653  if (stats.size())
654  {
655  QDomElement stat = stats.at(0).toElement();
656  views = GetInt(stat, "views");
657  favs = GetInt(stat, "favorites");
658  }
659 
660  QDomNodeList tagsNode = comm.elementsByTagNameNS(Parse::kMediaRSS,
661  "tags");
662  if (tagsNode.size())
663  {
664  QDomElement tag = tagsNode.at(0).toElement();
665  tags = tag.text();
666  }
667  }
668  }
669 
670  ArbitraryLocatedData result;
671  result.m_url = GetURL(element);
672  result.m_rating = rating;
673  result.m_ratingScheme = rscheme;
674  result.m_title = GetTitle(element);
675  result.m_description = GetDescription(element);
676  result.m_keywords = GetKeywords(element);
677  result.m_copyrightUrl = curl;
678  result.m_copyrightText = ctext;
679  result.m_ratingAverage = raverage;
680  result.m_ratingCount = rcount;
681  result.m_ratingMin = rmin;
682  result.m_ratingMax = rmax;
683  result.m_views = views;
684  result.m_favs = favs;
685  result.m_tags = tags;
686  result.m_thumbnails = GetThumbnails(element);
687  result.m_credits = GetCredits(element);
688  result.m_comments = GetComments(element);
689  result.m_peerLinks = GetPeerLinks(element);
690  result.m_scenes = GetScenes(element);
691 
692  return result;
693  }
694 };
695 
696 
697 //========================================================================================
698 // Search Construction, Destruction
699 //========================================================================================
700 
701 const QString Parse::kDC = "http://purl.org/dc/elements/1.1/";
702 const QString Parse::kWFW = "http://wellformedweb.org/CommentAPI/";
703 const QString Parse::kAtom = "http://www.w3.org/2005/Atom";
704 const QString Parse::kRDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
705 const QString Parse::kSlash = "http://purl.org/rss/1.0/modules/slash/";
706 const QString Parse::kEnc = "http://purl.oclc.org/net/rss_2.0/enc#";
707 const QString Parse::kITunes = "http://www.itunes.com/dtds/podcast-1.0.dtd";
708 const QString Parse::kGeoRSSSimple = "http://www.georss.org/georss";
709 const QString Parse::kGeoRSSW3 = "http://www.w3.org/2003/01/geo/wgs84_pos#";
710 const QString Parse::kMediaRSS = "http://search.yahoo.com/mrss/";
711 const QString Parse::kMythRSS = "http://www.mythtv.org/wiki/MythNetvision_Grabber_Script_Format";
712 
713 QMap<QString, int> Parse::m_timezoneOffsets {
714  { "EDT" , -4 },
715  { "EST" , -5 }
716 };
717 
718 ResultItem::resultList Parse::parseRSS(const QDomDocument& domDoc)
719 {
721 
722  QString document = domDoc.toString();
723  LOG(VB_GENERAL, LOG_DEBUG, "Will Be Parsing: " + document);
724 
725  QDomElement root = domDoc.documentElement();
726  QDomElement channel = root.firstChildElement("channel");
727  while (!channel.isNull())
728  {
729  QDomElement item = channel.firstChildElement("item");
730  while (!item.isNull())
731  {
732  vList.append(ParseItem(item));
733  item = item.nextSiblingElement("item");
734  }
735  channel = channel.nextSiblingElement("channel");
736  }
737 
738  return vList;
739 }
740 
741 ResultItem* Parse::ParseItem(const QDomElement& item)
742 {
743  QString title("");
744  QString subtitle("");
745  QString description("");
746  QString url("");
747  QString author("");
748  QString duration("");
749  QString rating("");
750  QString thumbnail("");
751  QString mediaURL("");
752  QString player("");
753  QString language("");
754  QString download("");
755  off_t filesize = 0;
756  uint width = 0;
757  uint height = 0;
758  uint season = 0;
759  uint episode = 0;
760  QDateTime date;
761  QStringList playerargs;
762  QStringList downloadargs;
763  QStringList countries;
764  bool downloadable = true;
765  bool customhtml = false;
766 
767  // Get the title of the article/video
768  title = item.firstChildElement("title").text();
769  title = UnescapeHTML(title);
770  if (title.isEmpty())
771  title = "";
772 
773  // Get the subtitle of this item.
774  QDomNodeList subt = item.elementsByTagNameNS(kMythRSS, "subtitle");
775  if (subt.size())
776  {
777  subtitle = subt.at(0).toElement().text();
778  }
779 
780  // Parse the description of the article/video
781  QDomElement descriptiontemp = item.firstChildElement("description");
782  if (!descriptiontemp.isNull())
783  description = descriptiontemp.text();
784  if (description.isEmpty())
785  {
786  QDomNodeList nodes = item.elementsByTagNameNS(kITunes, "summary");
787  if (nodes.size())
788  description = nodes.at(0).toElement().text();
789  }
790  // Unescape and remove HTML tags from the description.
791  if (description.isEmpty())
792  description = "";
793  else
794  description = UnescapeHTML(description);
795 
796  // Get the link (web playable)
797  url = item.firstChildElement("link").text();
798 
799  // Parse the item author
800  QDomElement authortemp = item.firstChildElement("author");
801  if (!authortemp.isNull())
802  author = authortemp.text();
803  if (author.isEmpty())
804  author = GetAuthor(item);
805 
806  // Turn the RFC-822 pubdate into a QDateTime
807  date = RFC822TimeToQDateTime(item.firstChildElement("pubDate").text());
808  if (!date.isValid() || date.isNull())
809  date = GetDCDateTime(item);
810  if (!date.isValid() || date.isNull())
811  date = MythDate::current();
812 
813  // Parse the insane iTunes duration (HH:MM:SS or H:MM:SS or MM:SS or M:SS or SS)
814  QDomNodeList dur = item.elementsByTagNameNS(kITunes, "duration");
815  if (dur.size())
816  {
817  QString itunestime = dur.at(0).toElement().text();
818  QString dateformat;
819 
820  if (itunestime.count() == 8)
821  dateformat = "hh:mm:ss";
822  else if (itunestime.count() == 7)
823  dateformat = "h:mm:ss";
824  else if (itunestime.count() == 5)
825  dateformat = "mm:ss";
826  else if (itunestime.count() == 4)
827  dateformat = "m:ss";
828  else if (itunestime.count() == 2)
829  dateformat = "ss";
830  else
831  duration = "0";
832 
833  if (!dateformat.isNull())
834  {
835  QTime itime = QTime::fromString(itunestime, dateformat);
836  if (itime.isValid())
837  {
838  int seconds = itime.second() + (itime.minute() * 60) + (itime.hour() * 3600);
839  duration = QString::number(seconds);
840  }
841  }
842  }
843 
844  // Get the rating
845  QDomElement ratingtemp = item.firstChildElement("rating");
846  if (!ratingtemp.isNull())
847  rating = ratingtemp.text();
848 
849  // Get the external player binary
850  QDomElement playertemp = item.firstChildElement("player");
851  if (!playertemp.isNull())
852  player = playertemp.text();
853 
854  // Get the arguments to pass to the external player
855  QDomElement playerargstemp = item.firstChildElement("playerargs");
856  if (!playerargstemp.isNull())
857  playerargs = playerargstemp.text().split(" ");
858 
859  // Get the external downloader binary/script
860  QDomElement downloadtemp = item.firstChildElement("download");
861  if (!downloadtemp.isNull())
862  download = downloadtemp.text();
863 
864  // Get the arguments to pass to the external downloader
865  QDomElement downloadargstemp = item.firstChildElement("downloadargs");
866  if (!downloadargstemp.isNull())
867  downloadargs = downloadargstemp.text().split(" ");
868 
869  // Get the countries in which this item is playable
870  QDomNodeList cties = item.elementsByTagNameNS(kMythRSS, "country");
871  if (cties.size())
872  {
873  int i = 0;
874  while (i < cties.size())
875  {
876  countries.append(cties.at(i).toElement().text());
877  i++;
878  }
879  }
880 
881  // Get the season number of this item.
882  QDomNodeList seas = item.elementsByTagNameNS(kMythRSS, "season");
883  if (seas.size())
884  {
885  season = seas.at(0).toElement().text().toUInt();
886  }
887 
888  // Get the Episode number of this item.
889  QDomNodeList ep = item.elementsByTagNameNS(kMythRSS, "episode");
890  if (ep.size())
891  {
892  episode = ep.at(0).toElement().text().toUInt();
893  }
894 
895  // Does this grabber return custom HTML?
896  QDomNodeList html = item.elementsByTagNameNS(kMythRSS, "customhtml");
897  if (html.size())
898  {
899  QString htmlstring = html.at(0).toElement().text();
900  if (htmlstring.contains("true", Qt::CaseInsensitive) || htmlstring == "1" ||
901  htmlstring.contains("yes", Qt::CaseInsensitive))
902  customhtml = true;
903  }
904 
905  QList<MRSSEntry> enclosures = GetMediaRSS(item);
906 
907  if (!enclosures.empty())
908  {
909  MRSSEntry media = enclosures.takeAt(0);
910 
911  QList<MRSSThumbnail> thumbs = media.Thumbnails;
912  if (!thumbs.empty())
913  {
914  MRSSThumbnail thumb = thumbs.takeAt(0);
915  thumbnail = thumb.URL;
916  }
917 
918  mediaURL = media.URL;
919 
920  width = media.Width;
921  height = media.Height;
922  language = media.Lang;
923 
924  if (duration.isEmpty())
925  duration = QString::number(media.Duration);
926 
927  if (filesize == 0)
928  filesize = media.Size;
929 
930  if (rating.isEmpty())
931  rating = QString::number(media.RatingAverage);
932  }
933  if (mediaURL.isEmpty())
934  {
935  QList<Enclosure> stdEnc = GetEnclosures(item);
936 
937  if (!stdEnc.empty())
938  {
939  Enclosure e = stdEnc.takeAt(0);
940 
941  mediaURL = e.URL;
942 
943  if (filesize == 0)
944  filesize = e.Length;
945  }
946  }
947 
948  if (mediaURL.isNull() || mediaURL == url)
949  downloadable = false;
950 
951  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
952  return(new ResultItem(title, sh->doTitle(title),
953  subtitle, sh->doTitle(subtitle), description,
954  url, thumbnail, mediaURL, author, date, duration,
955  rating, filesize, player, playerargs,
956  download, downloadargs, width, height,
957  language, downloadable, countries, season,
958  episode, customhtml));
959 }
960 
961 QString Parse::GetLink(const QDomElement& parent)
962 {
963  QString result;
964  QDomElement link = parent.firstChildElement("link");
965  while(!link.isNull())
966  {
967  if (!link.hasAttribute("rel") || link.attribute("rel") == "alternate")
968  {
969  if (!link.hasAttribute("href"))
970  result = link.text();
971  else
972  result = link.attribute("href");
973  break;
974  }
975  link = link.nextSiblingElement("link");
976  }
977  return result;
978 }
979 
980 QString Parse::GetAuthor(const QDomElement& parent)
981 {
982  QString result("");
983  QDomNodeList nodes = parent.elementsByTagNameNS(kITunes,
984  "author");
985  if (nodes.size())
986  {
987  result = nodes.at(0).toElement().text();
988  return result;
989  }
990 
991  nodes = parent.elementsByTagNameNS(kDC,
992  "creator");
993  if (nodes.size())
994  {
995  result = nodes.at(0).toElement().text();
996  return result;
997  }
998 
999  return result;
1000 }
1001 
1002 QString Parse::GetCommentsRSS(const QDomElement& parent)
1003 {
1004  QString result;
1005  QDomNodeList nodes = parent.elementsByTagNameNS(kWFW,
1006  "commentRss");
1007  if (nodes.size())
1008  result = nodes.at(0).toElement().text();
1009  return result;
1010 }
1011 
1012 QString Parse::GetCommentsLink(const QDomElement& parent)
1013 {
1014  QString result;
1015  QDomNodeList nodes = parent.elementsByTagNameNS("", "comments");
1016  if (nodes.size())
1017  result = nodes.at(0).toElement().text();
1018  return result;
1019 }
1020 
1021 QDateTime Parse::GetDCDateTime(const QDomElement& parent)
1022 {
1023  QDomNodeList dates = parent.elementsByTagNameNS(kDC, "date");
1024  if (!dates.size())
1025  return QDateTime();
1026  return FromRFC3339(dates.at(0).toElement().text());
1027 }
1028 
1029 QDateTime Parse::RFC822TimeToQDateTime(const QString& t)
1030 {
1031  if (t.size() < 20)
1032  return QDateTime();
1033 
1034  QString time = t.simplified();
1035  short int hoursShift = 0;
1036  short int minutesShift = 0;
1037 
1038  QStringList tmp = time.split(' ');
1039  if (tmp.isEmpty())
1040  return QDateTime();
1041  if (tmp.at(0).contains(QRegularExpression(R"(\D)")))
1042  tmp.removeFirst();
1043  if (tmp.size() != 5)
1044  return QDateTime();
1045  QString tmpTimezone = tmp.takeAt(tmp.size() -1);
1046  if (tmpTimezone.size() == 5)
1047  {
1048  bool ok = false;
1049  int tz = tmpTimezone.toInt(&ok);
1050  if(ok)
1051  {
1052  hoursShift = tz / 100;
1053  minutesShift = tz % 100;
1054  }
1055  }
1056  else
1057  hoursShift = m_timezoneOffsets.value(tmpTimezone, 0);
1058 
1059  if (tmp.at(0).size() == 1)
1060  tmp[0].prepend("0");
1061  tmp [1].truncate(3);
1062 
1063  time = tmp.join(" ");
1064 
1065  QDateTime result;
1066  if (tmp.at(2).size() == 4)
1067  result = QLocale::c().toDateTime(time, "dd MMM yyyy hh:mm:ss");
1068  else
1069  result = QLocale::c().toDateTime(time, "dd MMM yy hh:mm:ss");
1070  if (result.isNull() || !result.isValid())
1071  return QDateTime();
1072  result = result.addSecs(hoursShift * 3600 * (-1) + minutesShift *60 * (-1));
1073  result.setTimeSpec(Qt::UTC);
1074  return result;
1075 }
1076 
1077 QDateTime Parse::FromRFC3339(const QString& t)
1078 {
1079  if (t.size() < 19)
1080  return QDateTime();
1081  QDateTime result = MythDate::fromString(t.left(19).toUpper());
1082  static const QRegularExpression fractionalSeconds { R"(\.(\d+))" };
1083  auto match = fractionalSeconds.match(t);
1084  if (match.hasMatch())
1085  {
1086  bool ok = false;
1087  int fractional = match.capturedView(1).toInt(&ok);
1088  if (ok)
1089  {
1090  if (fractional < 100)
1091  fractional *= 10;
1092  if (fractional <10)
1093  fractional *= 100;
1094  result = result.addMSecs(fractional);
1095  }
1096  }
1097  static const QRegularExpression timeZone { R"((\+|\-)(\d\d):(\d\d)$)" };
1098  match = timeZone.match(t);
1099  if (match.hasMatch())
1100  {
1101  short int multiplier = -1;
1102  if (match.captured(1) == "-")
1103  multiplier = 1;
1104  int hoursShift = match.capturedView(2).toInt();
1105  int minutesShift = match.capturedView(3).toInt();
1106  result = result.addSecs(hoursShift * 3600 * multiplier + minutesShift * 60 * multiplier);
1107  }
1108  result.setTimeSpec(Qt::UTC);
1109  return result;
1110 }
1111 
1112 QList<Enclosure> Parse::GetEnclosures(const QDomElement& entry)
1113 {
1114  QList<Enclosure> result;
1115  QDomNodeList links = entry.elementsByTagName("enclosure");
1116  for (int i = 0; i < links.size(); ++i)
1117  {
1118  QDomElement link = links.at(i).toElement();
1119 
1120  Enclosure e =
1121  {
1122  link.attribute("url"),
1123  link.attribute("type"),
1124  link.attribute("length", "-1").toLongLong(),
1125  link.attribute("hreflang")
1126  };
1127 
1128  result << e;
1129  }
1130  return result;
1131 }
1132 
1133 QList<MRSSEntry> Parse::GetMediaRSS(const QDomElement& item)
1134 {
1135  return MRSSParser() (item);
1136 }
1137 
1138 QString Parse::UnescapeHTML(const QString& escaped)
1139 {
1140  QString result = escaped;
1141  result.replace("&amp;", "&");
1142  result.replace("&lt;", "<");
1143  result.replace("&gt;", ">");
1144  result.replace("&apos;", "\'");
1145  result.replace("&rsquo;", "\'");
1146  result.replace("&#x2019;", "\'");
1147  result.replace("&quot;", "\"");
1148  result.replace("&#8230;",QChar(8230));
1149  result.replace("&#233;",QChar(233));
1150  result.replace("&mdash;", QChar(8212));
1151  result.replace("&nbsp;", " ");
1152  result.replace("&#160;", QChar(160));
1153  result.replace("&#225;", QChar(225));
1154  result.replace("&#8216;", QChar(8216));
1155  result.replace("&#8217;", QChar(8217));
1156  result.replace("&#039;", "\'");
1157  result.replace("&ndash;", QChar(8211));
1158  result.replace("&auml;", QChar(0x00e4));
1159  result.replace("&ouml;", QChar(0x00f6));
1160  result.replace("&uuml;", QChar(0x00fc));
1161  result.replace("&Auml;", QChar(0x00c4));
1162  result.replace("&Ouml;", QChar(0x00d6));
1163  result.replace("&Uuml;", QChar(0x00dc));
1164  result.replace("&szlig;", QChar(0x00df));
1165  result.replace("&euro;", "€");
1166  result.replace("&#8230;", "...");
1167  result.replace("&#x00AE;", QChar(0x00ae));
1168  result.replace("&#x201C;", QChar(0x201c));
1169  result.replace("&#x201D;", QChar(0x201d));
1170  result.replace("<p>", "\n");
1171 
1172  QRegularExpression stripHTML {"<.*?>"};
1173  result.remove(stripHTML);
1174 
1175  return result;
1176 }
MRSSEntry::Expression
QString Expression
Definition: rssparse.h:78
MRSSParser::GetURL
static QString GetURL(const QDomElement &element)
Definition: rssparse.cpp:381
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
ResultItem::ensureSortFields
void ensureSortFields(void)
Definition: rssparse.cpp:67
ResultItem::m_url
QString m_url
Definition: rssparse.h:166
Parse::kRDF
static const QString kRDF
Definition: rssparse.h:219
Parse::kGeoRSSW3
static const QString kGeoRSSW3
Definition: rssparse.h:224
Parse::RFC822TimeToQDateTime
static QDateTime RFC822TimeToQDateTime(const QString &parent)
Definition: rssparse.cpp:1029
mythburn.dateformat
string dateformat
Definition: mythburn.py:170
getMythSortHelper
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
Definition: mythsorthelper.cpp:133
MRSSParser::ArbitraryLocatedData::m_rating
QString m_rating
Definition: rssparse.cpp:198
ResultItem::m_countries
QStringList m_countries
Definition: rssparse.h:182
ResultItem::m_episode
uint m_episode
Definition: rssparse.h:184
ResultItem::m_sorttitle
QString m_sorttitle
Definition: rssparse.h:162
MRSSEntry::RatingCount
int RatingCount
Definition: rssparse.h:96
MRSSParser::ArbitraryLocatedData::m_ratingMin
int m_ratingMin
Definition: rssparse.cpp:207
MRSSParser::CollectChildren
static QList< MRSSEntry > CollectChildren(const QDomElement &holder)
Definition: rssparse.cpp:286
MRSSEntry::Comments
QList< MRSSComment > Comments
Definition: rssparse.h:104
ResultItem::m_height
uint m_height
Definition: rssparse.h:179
MRSSEntry::Views
int Views
Definition: rssparse.h:99
MRSSEntry::Scenes
QList< MRSSScene > Scenes
Definition: rssparse.h:106
MRSSEntry::RatingScheme
QString RatingScheme
Definition: rssparse.h:89
Parse::kAtom
static const QString kAtom
Definition: rssparse.h:218
Parse::UnescapeHTML
static QString UnescapeHTML(const QString &escaped)
Definition: rssparse.cpp:1138
ResultItem::m_time
QString m_time
Definition: rssparse.h:171
ResultItem::m_customhtml
bool m_customhtml
Definition: rssparse.h:185
ResultItem::m_download
QString m_download
Definition: rssparse.h:176
ResultItem::ResultItem
ResultItem()=default
ResultItem::m_thumbnail
QString m_thumbnail
Definition: rssparse.h:167
MRSSParser::ArbitraryLocatedData::m_ratingAverage
int m_ratingAverage
Definition: rssparse.cpp:205
MRSSParser::ArbitraryLocatedData::m_scenes
QList< MRSSScene > m_scenes
Definition: rssparse.cpp:216
format_season_and_episode
MPUBLIC QString format_season_and_episode(int seasEp, int digits)
Definition: programinfo.cpp:6217
rssparse.h
MRSSParser::ArbitraryLocatedData::m_ratingCount
int m_ratingCount
Definition: rssparse.cpp:206
Parse::kMythRSS
static const QString kMythRSS
Definition: rssparse.h:226
Parse::GetMediaRSS
static QList< MRSSEntry > GetMediaRSS(const QDomElement &item)
Definition: rssparse.cpp:1133
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
ResultItem::m_downloadargs
QStringList m_downloadargs
Definition: rssparse.h:177
mythdirs.h
MRSSScene
Definition: rssparse.h:63
mythsorthelper.h
MRSSEntry::Medium
QString Medium
Definition: rssparse.h:76
MRSSEntry::Favs
int Favs
Definition: rssparse.h:100
MRSSParser::ArbitraryLocatedData::m_url
QString m_url
Definition: rssparse.cpp:197
ResultItem::m_title
QString m_title
Definition: rssparse.h:161
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
MRSSEntry::Lang
QString Lang
Definition: rssparse.h:86
MRSSParser::ArbitraryLocatedData::m_title
QString m_title
Definition: rssparse.cpp:200
MRSSEntry::URL
QString URL
Definition: rssparse.h:73
MRSSParser::GetArbitraryLocatedDataFor
static ArbitraryLocatedData GetArbitraryLocatedDataFor(const QDomElement &holder)
Definition: rssparse.cpp:363
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
ResultItem::m_date
QDateTime m_date
Definition: rssparse.h:170
ResultItem::m_player
QString m_player
Definition: rssparse.h:174
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
MRSSEntry::RatingMax
int RatingMax
Definition: rssparse.h:98
Parse::kSlash
static const QString kSlash
Definition: rssparse.h:220
MRSSParser::GetTitle
static QString GetTitle(const QDomElement &element)
Definition: rssparse.cpp:391
ResultItem::m_desc
QString m_desc
Definition: rssparse.h:165
Parse::kDC
static const QString kDC
Definition: rssparse.h:216
MRSSEntry::Tags
QString Tags
Definition: rssparse.h:101
mythdate.h
programinfo.h
MRSSEntry::Size
qint64 Size
Definition: rssparse.h:74
MRSSParser::ArbitraryLocatedData::m_keywords
QString m_keywords
Definition: rssparse.cpp:202
hardwareprofile.config.p
p
Definition: config.py:33
hardwareprofile.i18n.t
t
Definition: i18n.py:36
MRSSParser::operator()
QList< MRSSEntry > operator()(const QDomElement &item)
Definition: rssparse.cpp:269
MRSSParser::GetPeerLinks
static QList< MRSSPeerLink > GetPeerLinks(const QDomElement &element)
Definition: rssparse.cpp:546
MRSSEntry::RatingMin
int RatingMin
Definition: rssparse.h:97
MRSSEntry::SamplingRate
double SamplingRate
Definition: rssparse.h:81
Parse::kEnc
static const QString kEnc
Definition: rssparse.h:221
ResultItem::m_downloadable
bool m_downloadable
Definition: rssparse.h:181
MRSSEntry::Rating
QString Rating
Definition: rssparse.h:88
hardwareprofile.scan.rating
def rating(profile, smoonURL, gate)
Definition: scan.py:39
MRSSEntry
Definition: rssparse.h:71
MRSSParser::GetInt
static int GetInt(const QDomElement &elem, const QString &attrname)
Definition: rssparse.cpp:427
MRSSEntry::IsDefault
bool IsDefault
Definition: rssparse.h:77
MRSSEntry::CopyrightURL
QString CopyrightURL
Definition: rssparse.h:93
MRSSEntry::RatingAverage
int RatingAverage
Definition: rssparse.h:95
ResultItem::m_author
QString m_author
Definition: rssparse.h:169
MRSSParser::ArbitraryLocatedData::m_copyrightUrl
QString m_copyrightUrl
Definition: rssparse.cpp:203
MRSSThumbnail::URL
QString URL
Definition: rssparse.h:39
MRSSParser::GetThumbnails
static QList< MRSSThumbnail > GetThumbnails(const QDomElement &element)
Definition: rssparse.cpp:439
Parse::m_timezoneOffsets
static QMap< QString, int > m_timezoneOffsets
Definition: rssparse.h:213
ResultItem::m_filesize
off_t m_filesize
Definition: rssparse.h:173
MRSSEntry::CopyrightText
QString CopyrightText
Definition: rssparse.h:94
Parse::GetDCDateTime
static QDateTime GetDCDateTime(const QDomElement &parent)
Definition: rssparse.cpp:1021
MRSSParser::ArbitraryLocatedData::m_peerLinks
QList< MRSSPeerLink > m_peerLinks
Definition: rssparse.cpp:215
ResultItem::m_width
uint m_width
Definition: rssparse.h:178
Parse::kITunes
static const QString kITunes
Definition: rssparse.h:222
ResultItem::m_subtitle
QString m_subtitle
Definition: rssparse.h:163
ResultItem::toMap
void toMap(InfoMap &metadataMap)
Definition: rssparse.cpp:77
Parse::kMediaRSS
static const QString kMediaRSS
Definition: rssparse.h:225
MRSSEntry::Credits
QList< MRSSCredit > Credits
Definition: rssparse.h:103
Enclosure
Describes an enclosure associated with an item.
Definition: rssparse.h:29
uint
unsigned int uint
Definition: compat.h:140
MRSSParser::ArbitraryLocatedData::m_favs
int m_favs
Definition: rssparse.cpp:210
MRSSParser::ArbitraryLocatedData::m_credits
QList< MRSSCredit > m_credits
Definition: rssparse.cpp:213
MRSSEntry::Title
QString Title
Definition: rssparse.h:90
MRSSCredit
Definition: rssparse.h:45
MRSSParser::GetCredits
static QList< MRSSCredit > GetCredits(const QDomElement &element)
Definition: rssparse.cpp:463
MRSSEntry::Type
QString Type
Definition: rssparse.h:75
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
off_t
#define off_t
Definition: mythiowrapper.cpp:240
MRSSParser::ArbitraryLocatedData::m_ratingMax
int m_ratingMax
Definition: rssparse.cpp:208
Parse::GetCommentsLink
static QString GetCommentsLink(const QDomElement &parent)
Definition: rssparse.cpp:1012
Parse::kWFW
static const QString kWFW
Definition: rssparse.h:217
MRSSEntry::PeerLinks
QList< MRSSPeerLink > PeerLinks
Definition: rssparse.h:105
MRSSEntry::Thumbnails
QList< MRSSThumbnail > Thumbnails
Definition: rssparse.h:102
MRSSParser::GetComments
static QList< MRSSComment > GetComments(const QDomElement &element)
Definition: rssparse.cpp:484
MRSSParser::GetDescription
static QString GetDescription(const QDomElement &element)
Definition: rssparse.cpp:403
MRSSParser::ArbitraryLocatedData::m_tags
QString m_tags
Definition: rssparse.cpp:211
MRSSEntry::Height
int Height
Definition: rssparse.h:85
MRSSEntry::Channels
int Channels
Definition: rssparse.h:82
MRSSParser::ArbitraryLocatedData::ArbitraryLocatedData
ArbitraryLocatedData()=default
MRSSEntry::Bitrate
int Bitrate
Definition: rssparse.h:79
MRSSThumbnail
Definition: rssparse.h:37
Parse::GetAuthor
static QString GetAuthor(const QDomElement &parent)
Definition: rssparse.cpp:980
Enclosure::URL
QString URL
Definition: rssparse.h:31
MRSSParser::GetScenes
static QList< MRSSScene > GetScenes(const QDomElement &element)
Definition: rssparse.cpp:565
MRSSParser::ArbitraryLocatedData::m_comments
QList< MRSSComment > m_comments
Definition: rssparse.cpp:214
ResultItem
Definition: rssparse.h:109
Parse::ParseItem
static ResultItem * ParseItem(const QDomElement &item)
Definition: rssparse.cpp:741
Parse::kGeoRSSSimple
static const QString kGeoRSSSimple
Definition: rssparse.h:223
ResultItem::m_sortsubtitle
QString m_sortsubtitle
Definition: rssparse.h:164
MRSSParser
Definition: rssparse.cpp:193
MRSSParser::ArbitraryLocatedData
Definition: rssparse.cpp:195
MRSSParser::CollectArbitraryLocatedData
static ArbitraryLocatedData CollectArbitraryLocatedData(const QDomElement &element)
Definition: rssparse.cpp:592
ResultItem::m_rating
QString m_rating
Definition: rssparse.h:172
MRSSParser::ArbitraryLocatedData::m_description
QString m_description
Definition: rssparse.cpp:201
mythcontext.h
Parse::FromRFC3339
static QDateTime FromRFC3339(const QString &t)
Definition: rssparse.cpp:1077
MRSSEntry::Width
int Width
Definition: rssparse.h:84
MRSSParser::ArbitraryLocatedData::m_views
int m_views
Definition: rssparse.cpp:209
ResultItem::resultList
QList< ResultItem * > resultList
Definition: rssparse.h:114
MythDate::kDateFull
@ kDateFull
Default local time.
Definition: mythdate.h:19
ResultItem::m_playerargs
QStringList m_playerargs
Definition: rssparse.h:175
Enclosure::Length
qint64 Length
Definition: rssparse.h:33
ResultItem::m_season
uint m_season
Definition: rssparse.h:183
MRSSParser::ArbitraryLocatedData::m_ratingScheme
QString m_ratingScheme
Definition: rssparse.cpp:199
Parse::parseRSS
static ResultItem::resultList parseRSS(const QDomDocument &domDoc)
Definition: rssparse.cpp:718
MRSSEntry::Keywords
QString Keywords
Definition: rssparse.h:92
ResultItem::m_language
QString m_language
Definition: rssparse.h:180
Parse::GetLink
static QString GetLink(const QDomElement &parent)
Definition: rssparse.cpp:961
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
MRSSComment
Definition: rssparse.h:51
Parse::GetCommentsRSS
static QString GetCommentsRSS(const QDomElement &parent)
Definition: rssparse.cpp:1002
MRSSParser::ArbitraryLocatedData::operator+=
ArbitraryLocatedData & operator+=(const ArbitraryLocatedData &child)
Updates *this's fields according to the child.
Definition: rssparse.cpp:223
MRSSParser::ArbitraryLocatedData::m_thumbnails
QList< MRSSThumbnail > m_thumbnails
Definition: rssparse.cpp:212
MRSSParser::GetKeywords
static QString GetKeywords(const QDomElement &element)
Definition: rssparse.cpp:415
MRSSEntry::Framerate
double Framerate
Definition: rssparse.h:80
MRSSParser::MRSSParser
MRSSParser()=default
Parse::MRSSParser
friend class MRSSParser
Definition: rssparse.h:191
MRSSEntry::Description
QString Description
Definition: rssparse.h:91
MRSSEntry::Duration
int Duration
Definition: rssparse.h:83
ResultItem::m_mediaURL
QString m_mediaURL
Definition: rssparse.h:168
Parse::GetEnclosures
static QList< Enclosure > GetEnclosures(const QDomElement &entry)
Definition: rssparse.cpp:1112
MRSSParser::ArbitraryLocatedData::m_copyrightText
QString m_copyrightText
Definition: rssparse.cpp:204