MythTV  master
videometadata.cpp
Go to the documentation of this file.
1 #include <cmath> // for isnan()
2 
3 #include <QFile>
4 #include <QDir>
5 #include <QFileInfo>
6 #include <QRegExp>
7 
8 #include "mythcorecontext.h"
9 #include "mythmiscutil.h"
10 #include "mythcontext.h"
11 #include "mythdb.h"
12 #include "storagegroup.h"
13 #include "remotefile.h"
14 #include "remoteutil.h"
15 #include "mythdate.h"
16 #include "mythlogging.h"
17 #include "globals.h"
18 #include "dbaccess.h"
20 #include "videoutils.h"
21 #include "programinfo.h" // for format_season_and_episode
22 #include "mythsorthelper.h"
23 
24 using namespace std;
25 
27 {
28  public:
32 
33  public:
34  VideoMetadataImp(const QString &filename, const QString &sortFilename,
35  const QString &hash, const QString &trailer,
36  const QString &coverfile, const QString &screenshot, const QString &banner,
37  const QString &fanart, const QString &title, const QString &sortTitle,
38  const QString &subtitle, const QString &sortSubtitle,
39  const QString &tagline, int year, const QDate &releasedate,
40  const QString &inetref, int collectionref, const QString &homepage,
41  const QString &director, const QString &studio,
42  const QString &plot, float userrating,
43  const QString &rating, int length, int playcount,
44  int season, int episode, const QDate &insertdate,
45  int id, ParentalLevel::Level showlevel, int categoryID,
46  int childID, bool browse, bool watched,
47  const QString &playcommand, const QString &category,
48  const genre_list &genres,
49  const country_list &countries,
50  const cast_list &cast,
51  const QString &host = "",
52  bool processed = false,
53  VideoContentType contenttype = kContentUnknown) :
54  m_title(title), m_sortTitle(sortTitle), m_subtitle(subtitle),
55  m_sortSubtitle(sortSubtitle), m_tagline(tagline),
56  m_inetref(inetref), m_collectionref(collectionref), m_homepage(homepage),
57  m_director(director), m_studio(studio),
58  m_plot(plot), m_rating(rating), m_playcommand(playcommand), m_category(category),
59  m_genres(genres), m_countries(countries), m_cast(cast),
60  m_filename(filename), m_sortFilename(sortFilename), m_hash(hash),
61  m_trailer(trailer), m_coverfile(coverfile),
62  m_screenshot(screenshot), m_banner(banner), m_fanart(fanart),
63  m_host(host), m_categoryID(categoryID), m_childID(childID),
64  m_year(year), m_releasedate(releasedate), m_length(length), m_playcount(playcount),
65  m_season(season), m_episode(episode), m_insertdate(insertdate), m_showlevel(showlevel),
66  m_browse(browse), m_watched(watched), m_id(id),
67  m_userrating(userrating), m_processed(processed),
68  m_contenttype(contenttype)
69  {
70  // Try to glean data if none provided.
71  if (title.isEmpty() and subtitle.isEmpty()
72  and season == 0 and episode == 0)
73  {
74  m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
75  m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
76  m_season = VideoMetadata::FilenameToMeta(m_filename, 2).toInt();
77  m_episode = VideoMetadata::FilenameToMeta(m_filename, 3).toInt();
78  }
79 
80  VideoCategory::GetCategory().get(m_categoryID, m_category);
81 
82  ensureSortFields();
83  }
84 
85  explicit VideoMetadataImp(MSqlQuery &query)
86  {
87  fromDBRow(query);
88  ensureSortFields();
89  }
90 
92  {
93  *this = other;
94  }
95 
97  {
98  if (this != &rhs)
99  {
100  m_title = rhs.m_title;
101  m_sortTitle = rhs.m_sortTitle;
102  m_subtitle = rhs.m_subtitle;
103  m_sortSubtitle = rhs.m_sortSubtitle;
104  m_tagline = rhs.m_tagline;
105  m_inetref = rhs.m_inetref;
106  m_collectionref = rhs.m_collectionref;
107  m_homepage = rhs.m_homepage;
108  m_director = rhs.m_director;
109  m_studio = rhs.m_studio;
110  m_plot = rhs.m_plot;
111  m_rating = rhs.m_rating;
112  m_playcommand = rhs.m_playcommand;
113  m_category = rhs.m_category;
114  m_genres = rhs.m_genres;
115  m_countries = rhs.m_countries;
116  m_cast = rhs.m_cast;
117  m_filename = rhs.m_filename;
118  m_sortFilename = rhs.m_sortFilename;
119  m_hash = rhs.m_hash;
120  m_trailer = rhs.m_trailer;
121  m_coverfile = rhs.m_coverfile;
122  m_screenshot = rhs.m_screenshot;
123  m_banner = rhs.m_banner;
124  m_fanart = rhs.m_fanart;
125 
126  m_categoryID = rhs.m_categoryID;
127  m_childID = rhs.m_childID;
128  m_year = rhs.m_year;
129  m_releasedate = rhs.m_releasedate;
130  m_length = rhs.m_length;
131  m_playcount = rhs.m_playcount;
132  m_season = rhs.m_season;
133  m_episode = rhs.m_episode;
134  m_insertdate = rhs.m_insertdate;
135  m_showlevel = rhs.m_showlevel;
136  m_browse = rhs.m_browse;
137  m_watched = rhs.m_watched;
138  m_id = rhs.m_id;
139  m_userrating = rhs.m_userrating;
140  m_host = rhs.m_host;
141  m_processed = rhs.m_processed;
142  m_contenttype = rhs.m_contenttype;
143 
144  // No DB vars
145  m_prefix = rhs.m_prefix;
146 
147  ensureSortFields();
148  }
149 
150  return *this;
151  }
152 
153  void ensureSortFields(void)
154  {
155  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
156  if (m_sortTitle.isEmpty() and not m_title.isEmpty())
157  m_sortTitle = sh->doTitle(m_title);
158  if (m_sortSubtitle.isEmpty() and not m_subtitle.isEmpty())
159  m_sortSubtitle = sh->doTitle(m_subtitle);
160  if (m_sortFilename.isEmpty() and not m_filename.isEmpty())
161  m_sortFilename = sh->doPathname(m_filename);
162  }
163 
164  public:
165  const QString &GetPrefix() const { return m_prefix; }
166  void SetPrefix(const QString &prefix) { m_prefix = prefix; }
167 
168  const QString &getTitle() const { return m_title; }
169  const QString &getSortTitle() const { return m_sortTitle; }
170  void SetTitle(const QString& title, const QString& sortTitle = "")
171  {
172  m_title = title;
173  m_sortTitle = sortTitle;
174  ensureSortFields();
175  }
176 
177  const QString &getSubtitle() const { return m_subtitle; }
178  const QString &getSortSubtitle() const { return m_sortSubtitle; }
179  void SetSubtitle(const QString &subtitle, const QString &sortSubtitle = "") {
180  m_subtitle = subtitle;
181  m_sortSubtitle = sortSubtitle;
182  ensureSortFields();
183  }
184 
185  const QString &GetTagline() const { return m_tagline; }
186  void SetTagline(const QString &tagline) { m_tagline = tagline; }
187 
188  const QString &GetInetRef() const { return m_inetref; }
189  void SetInetRef(const QString &inetRef) { m_inetref = inetRef; }
190 
191  int GetCollectionRef() const { return m_collectionref; }
192  void SetCollectionRef(int collectionref) { m_collectionref = collectionref; }
193 
194  const QString &GetHomepage() const { return m_homepage; }
195  void SetHomepage(const QString &homepage) { m_homepage = homepage; }
196 
197  const QString &getDirector() const { return m_director; }
198  void SetDirector(const QString &director) { m_director = director; }
199 
200  const QString &getStudio() const { return m_studio; }
201  void SetStudio(const QString &studio) { m_studio = studio; }
202 
203  const QString &getPlot() const { return m_plot; }
204  void SetPlot(const QString &plot) { m_plot = plot; }
205 
206  const QString &GetRating() const { return m_rating; }
207  void SetRating(const QString &rating) { m_rating = rating; }
208 
209  const QString &getPlayCommand() const { return m_playcommand; }
210  void SetPlayCommand(const QString &playCommand)
211  {
212  m_playcommand = playCommand;
213  }
214 
215  const QString &GetCategory() const { return m_category; }
216 // void SetCategory(const QString &category) { m_category = category; }
217 
218  const genre_list &getGenres() const { return m_genres; }
219  void SetGenres(const genre_list &genres) { m_genres = genres; }
220 
221  const country_list &GetCountries() const { return m_countries; }
222  void SetCountries(const country_list &countries)
223  {
224  m_countries = countries;
225  }
226 
227  const cast_list &GetCast() const { return m_cast; }
228  void SetCast(const cast_list &cast) { m_cast = cast; }
229 
230  const QString &GetHost() const { return m_host; }
231  void SetHost(const QString &host) { m_host = host; }
232 
233  const QString &getFilename() const { return m_filename; }
234  const QString &getSortFilename() const { return m_sortFilename; }
235  void SetFilename(const QString &filename, const QString &sortFilename = "")
236  {
237  m_filename = filename;
238  m_sortFilename = sortFilename;
239  ensureSortFields();
240  }
241 
242  bool sortBefore(const VideoMetadataImp *rhs) const;
243 
244  const QString &GetHash() const { return m_hash; }
245  void SetHash(const QString &hash) { m_hash = hash; }
246 
247  const QString &GetTrailer() const { return m_trailer; }
248  void SetTrailer(const QString &trailer) { m_trailer = trailer; }
249 
250  const QString &GetCoverFile() const { return m_coverfile; }
251  void SetCoverFile(const QString &coverFile) { m_coverfile = coverFile; }
252 
253  const QString &GetScreenshot() const { return m_screenshot; }
254  void SetScreenshot(const QString &screenshot) { m_screenshot = screenshot; }
255 
256  const QString &GetBanner() const { return m_banner; }
257  void SetBanner(const QString &banner) { m_banner = banner; }
258 
259  const QString &GetFanart() const { return m_fanart; }
260  void SetFanart(const QString &fanart) { m_fanart = fanart; }
261 
262  int GetCategoryID() const
263  {
264  return m_categoryID;
265  }
266  void SetCategoryID(int id);
267 
268  int GetChildID() const { return m_childID; }
269  void SetChildID(int childID) { m_childID = childID; }
270 
271  int getYear() const { return m_year; }
272  void SetYear(int year) { m_year = year; }
273 
274  QDate getReleaseDate() const { return m_releasedate; }
275  void SetReleaseDate(QDate releasedate) { m_releasedate = releasedate; }
276 
277  int GetLength() const { return m_length; }
278  void SetLength(int length) { m_length = length; }
279 
280  unsigned int GetPlayCount() const { return m_playcount; }
281  void SetPlayCount(int playcount) { m_playcount = playcount; }
282 
283  int GetSeason() const { return m_season; }
284  void SetSeason(int season) { m_season = season; }
285 
286  int GetEpisode() const { return m_episode; }
287  void SetEpisode(int episode) { m_episode = episode; }
288 
289  QDate GetInsertdate() const { return m_insertdate;}
290  void SetInsertdate(QDate date) { m_insertdate = date;}
291 
292  ParentalLevel::Level GetShowLevel() const { return m_showlevel; }
294  {
295  m_showlevel = ParentalLevel(showLevel).GetLevel();
296  }
297 
298  bool GetBrowse() const { return m_browse; }
299  void SetBrowse(bool browse) { m_browse = browse; }
300 
301  bool GetWatched() const { return m_watched; }
302  void SetWatched(bool watched) { m_watched = watched; }
303 
304  unsigned int GetID() const { return m_id; }
305  void SetID(int id) { m_id = id; }
306 
307  float GetUserRating() const { return m_userrating; }
308  void SetUserRating(float userRating) { m_userrating = userRating; }
309 
310  bool GetProcessed() const { return m_processed; }
311  void SetProcessed(bool processed) { m_processed = processed; }
312 
313  VideoContentType GetContentType() const { return m_contenttype; }
314  void SetContentType(VideoContentType contenttype) { m_contenttype = contenttype; }
315 
317 
318  void SaveToDatabase();
319  void UpdateDatabase();
320  bool DeleteFromDatabase();
321 
322  bool DeleteFile();
323 
324  void Reset();
325 
326  bool IsHostSet() const;
327 
328  void GetImageMap(InfoMap &imageMap) const;
329 
330  private:
331  void fillCountries();
332  void updateCountries();
333  void fillGenres();
334  void fillCast();
335  void updateGenres();
336  void updateCast();
337  bool removeDir(const QString &dirName);
338  void fromDBRow(MSqlQuery &query);
339  void saveToDatabase();
340 
341  private:
342  QString m_title;
343  QString m_sortTitle;
344  QString m_subtitle;
345  QString m_sortSubtitle;
346  QString m_tagline;
347  QString m_inetref;
349  QString m_homepage;
350  QString m_director;
351  QString m_studio;
352  QString m_plot;
353  QString m_rating;
354  QString m_playcommand;
355  QString m_category;
359  QString m_filename;
360  QString m_sortFilename;
361  QString m_hash;
362  QString m_trailer;
363  QString m_coverfile;
364  QString m_screenshot;
365  QString m_banner;
366  QString m_fanart;
367  QString m_host;
368 
371  int m_year;
373  int m_length;
375  int m_season;
379  bool m_browse;
380  bool m_watched;
381  unsigned int m_id; // videometadata.intid
385 
386  // not in DB
387  QString m_prefix;
388 };
389 
393 
397 {
398  int ret = naturalCompare(m_sortTitle, rhs->m_sortTitle);
399  if (ret != 0)
400  return (ret == -1);
401  ret = naturalCompare(m_sortFilename, rhs->m_sortFilename);
402  if (ret != 0)
403  return (ret == -1);
404  return (m_id < rhs->m_id);
405 }
406 
407 bool VideoMetadataImp::removeDir(const QString &dirName)
408 {
409  QDir d(dirName);
410 
411  d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
412  QFileInfoList contents = d.entryInfoList();
413  if (contents.empty())
414  {
415  return d.rmdir(dirName);
416  }
417 
418  for (QFileInfoList::iterator p = contents.begin(); p != contents.end(); ++p)
419  {
420  if (p->isDir())
421  {
422  QString fileName = p->fileName();
423  if (!removeDir(fileName))
424  return false;
425  }
426  else
427  {
428  if (!QFile(p->fileName()).remove())
429  return false;
430  }
431  }
432  return d.rmdir(dirName);
433 }
434 
437 {
438  bool isremoved = false;
439 
440  if (!m_host.isEmpty())
441  {
442  QString url = generate_file_url("Videos", m_host, m_filename);
443  isremoved = RemoteFile::DeleteFile(url);
444  }
445  else
446  {
447  QFileInfo fi(m_filename);
448  if (fi.isDir())
449  {
450  isremoved = removeDir(m_filename);
451  }
452  else
453  {
454  isremoved = QFile::remove(m_filename);
455  }
456  }
457 
458  if (!isremoved)
459  {
460  LOG(VB_GENERAL, LOG_DEBUG, QString("Could not delete file: %1")
461  .arg(m_filename));
462  }
463 
464  return isremoved;
465 }
466 
468 {
469  VideoMetadataImp tmp(m_filename, QString(),
472  VIDEO_FANART_DEFAULT, QString(), QString(), QString(), QString(),
473  QString(), VIDEO_YEAR_DEFAULT,
474  QDate(), VIDEO_INETREF_DEFAULT, -1, QString(), VIDEO_DIRECTOR_DEFAULT,
475  QString(), VIDEO_PLOT_DEFAULT, 0.0,
476  VIDEO_RATING_DEFAULT, 0, 0,
477  0, 0, QDate(), m_id,
478  ParentalLevel::plLowest, 0, -1, true, false, "", "",
480  VideoMetadata::cast_list(), m_host, false);
481  tmp.m_prefix = m_prefix;
482 
483  *this = tmp;
484 }
485 
487 {
488  return !m_host.isEmpty();
489 }
490 
492 {
493  m_genres.clear();
495  VideoGenreMap::entry genres;
496  if (vgm.get(m_id, genres))
497  {
499  for (VideoGenreMap::entry::values_type::const_iterator p =
500  genres.values.begin(); p != genres.values.end(); ++p)
501  {
502  // Just add empty string for no-name genres
503  QString name;
504  vg.get(*p, name);
505  m_genres.push_back(genre_list::value_type(*p, name));
506  }
507  }
508 }
509 
511 {
512  m_countries.clear();
514  VideoCountryMap::entry countries;
515  if (vcm.get(m_id, countries))
516  {
518  for (VideoCountryMap::entry::values_type::const_iterator p =
519  countries.values.begin(); p != countries.values.end(); ++p)
520  {
521  // Just add empty string for no-name countries
522  QString name;
523  vc.get(*p, name);
524  m_countries.push_back(country_list::value_type(*p, name));
525  }
526  }
527 }
528 
530 {
531  m_cast.clear();
533  VideoCastMap::entry cast;
534  if (vcm.get(m_id, cast))
535  {
537  for (VideoCastMap::entry::values_type::const_iterator p =
538  cast.values.begin(); p != cast.values.end(); ++p)
539  {
540  // Just add empty string for no-name cast
541  QString name;
542  vc.get(*p, name);
543  m_cast.push_back(cast_list::value_type(*p, name));
544  }
545  }
546 }
547 
553 {
554  m_title = query.value(0).toString();
555  m_director = query.value(1).toString();
556  m_studio = query.value(2).toString();
557  m_plot = query.value(3).toString();
558  m_rating = query.value(4).toString();
559  m_year = query.value(5).toInt();
560  m_releasedate = query.value(6).toDate();
561  m_userrating = (float)query.value(7).toDouble();
562  if (isnan(m_userrating) || m_userrating < 0)
563  m_userrating = 0.0;
564  if (m_userrating > 10.0F)
565  m_userrating = 10.0F;
566  m_length = query.value(8).toInt();
567  m_playcount = query.value(9).toInt();
568  m_filename = query.value(10).toString();
569  m_hash = query.value(11).toString();
570  m_showlevel = ParentalLevel(query.value(12).toInt()).GetLevel();
571  m_coverfile = query.value(13).toString();
572  m_inetref = query.value(14).toString();
573  m_collectionref = query.value(15).toUInt();
574  m_homepage = query.value(16).toString();
575  m_childID = query.value(17).toUInt();
576  m_browse = query.value(18).toBool();
577  m_watched = query.value(19).toBool();
578  m_playcommand = query.value(20).toString();
579  m_categoryID = query.value(21).toInt();
580  m_id = query.value(22).toInt();
581  m_trailer = query.value(23).toString();
582  m_screenshot = query.value(24).toString();
583  m_banner = query.value(25).toString();
584  m_fanart = query.value(26).toString();
585  m_subtitle = query.value(27).toString();
586  m_tagline = query.value(28).toString();
587  m_season = query.value(29).toInt();
588  m_episode = query.value(30).toInt();
589  m_host = query.value(31).toString();
590  m_insertdate = query.value(32).toDate();
591  m_processed = query.value(33).toBool();
592 
593  m_contenttype = ContentTypeFromString(query.value(34).toString());
594 
595  ensureSortFields();
596 
597  VideoCategory::GetCategory().get(m_categoryID, m_category);
598 
599  // Genres
600  fillGenres();
601 
602  //Countries
603  fillCountries();
604 
605  // Cast
606  fillCast();
607 }
608 
610 {
611  if (m_title.isEmpty())
612  m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
613  if (m_hash.isEmpty())
614  m_hash = VideoMetadata::VideoFileHash(m_filename, m_host);
615  if (m_subtitle.isEmpty())
616  m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
617  if (m_director.isEmpty())
618  m_director = VIDEO_DIRECTOR_UNKNOWN;
619  if (m_plot.isEmpty())
620  m_plot = VIDEO_PLOT_DEFAULT;
621  if (m_rating.isEmpty())
622  m_rating = VIDEO_RATING_DEFAULT;
623  ensureSortFields();
624 
625  InfoMap metadataMap;
626  GetImageMap(metadataMap);
627  QString coverfile = metadataMap["coverfile"];
628  QString screenshot = metadataMap["screenshotfile"];
629  QString bannerfile = metadataMap["bannerfile"];
630  QString fanartfile = metadataMap["fanartfile"];
631 
632  if (coverfile.isEmpty() || !RemoteFile::Exists(coverfile))
633  m_coverfile = VIDEO_COVERFILE_DEFAULT;
634  if (screenshot.isEmpty() || !RemoteFile::Exists(screenshot))
635  m_screenshot = VIDEO_SCREENSHOT_DEFAULT;
636  if (bannerfile.isEmpty() || !RemoteFile::Exists(bannerfile))
637  m_banner = VIDEO_BANNER_DEFAULT;
638  if (fanartfile.isEmpty() || !RemoteFile::Exists(fanartfile))
639  m_fanart = VIDEO_FANART_DEFAULT;
640  if (m_trailer.isEmpty())
641  m_trailer = VIDEO_TRAILER_DEFAULT;
642  if (m_inetref.isEmpty())
643  m_inetref = VIDEO_INETREF_DEFAULT;
644  if (isnan(m_userrating))
645  m_userrating = 0.0;
646  if (m_userrating < -10.0F || m_userrating > 10.0F)
647  m_userrating = 0.0;
648  if (m_releasedate.toString().isEmpty())
649  m_releasedate = QDate::fromString("0000-00-00", "YYYY-MM-DD");
650  if (m_contenttype == kContentUnknown)
651  {
652  if (m_season > 0 || m_episode > 0)
653  m_contenttype = kContentTelevision;
654  else
655  m_contenttype = kContentMovie;
656  }
657 
658  bool inserting = m_id == 0;
659 
660  MSqlQuery query(MSqlQuery::InitCon());
661 
662  if (inserting)
663  {
664  m_browse = true;
665 
666  m_watched = false;
667 
668  query.prepare("INSERT INTO videometadata (title,subtitle,tagline,director,studio,plot,"
669  "rating,year,userrating,length,season,episode,filename,hash,"
670  "showlevel,coverfile,inetref,homepage,browse,watched,trailer,"
671  "screenshot,banner,fanart,host,processed,contenttype) VALUES (:TITLE, :SUBTITLE, "
672  ":TAGLINE, :DIRECTOR, :STUDIO, :PLOT, :RATING, :YEAR, :USERRATING, "
673  ":LENGTH, :SEASON, :EPISODE, :FILENAME, :HASH, :SHOWLEVEL, "
674  ":COVERFILE, :INETREF, :HOMEPAGE, :BROWSE, :WATCHED, "
675  ":TRAILER, :SCREENSHOT, :BANNER, :FANART, :HOST, :PROCESSED, :CONTENTTYPE)");
676  }
677  else
678  {
679  query.prepare("UPDATE videometadata SET title = :TITLE, subtitle = :SUBTITLE, "
680  "tagline = :TAGLINE, director = :DIRECTOR, studio = :STUDIO, "
681  "plot = :PLOT, rating= :RATING, year = :YEAR, "
682  "releasedate = :RELEASEDATE, userrating = :USERRATING, "
683  "length = :LENGTH, playcount = :PLAYCOUNT, season = :SEASON, "
684  "episode = :EPISODE, filename = :FILENAME, hash = :HASH, trailer = :TRAILER, "
685  "showlevel = :SHOWLEVEL, coverfile = :COVERFILE, "
686  "screenshot = :SCREENSHOT, banner = :BANNER, fanart = :FANART, "
687  "inetref = :INETREF, collectionref = :COLLECTION, homepage = :HOMEPAGE, "
688  "browse = :BROWSE, watched = :WATCHED, host = :HOST, playcommand = :PLAYCOMMAND, "
689  "childid = :CHILDID, category = :CATEGORY, processed = :PROCESSED, "
690  "contenttype = :CONTENTTYPE WHERE intid = :INTID");
691 
692  query.bindValue(":PLAYCOMMAND", m_playcommand);
693  query.bindValue(":CHILDID", m_childID);
694  query.bindValue(":CATEGORY", m_categoryID);
695  query.bindValue(":INTID", m_id);
696  }
697 
698  query.bindValue(":TITLE", m_title.isNull() ? "" : m_title);
699  query.bindValue(":SUBTITLE", m_subtitle.isNull() ? "" : m_subtitle);
700  query.bindValue(":TAGLINE", m_tagline);
701  query.bindValue(":DIRECTOR", m_director.isNull() ? "" : m_director);
702  query.bindValue(":STUDIO", m_studio);
703  query.bindValue(":PLOT", m_plot);
704  query.bindValue(":RATING", m_rating.isNull() ? "" : m_rating);
705  query.bindValue(":YEAR", m_year);
706  query.bindValue(":RELEASEDATE", m_releasedate);
707  query.bindValue(":USERRATING", m_userrating);
708  query.bindValue(":LENGTH", m_length);
709  query.bindValue(":PLAYCOUNT", m_playcount);
710  query.bindValue(":SEASON", m_season);
711  query.bindValue(":EPISODE", m_episode);
712  query.bindValue(":FILENAME", m_filename);
713  query.bindValue(":HASH", m_hash);
714  query.bindValue(":TRAILER", m_trailer.isNull() ? "" : m_trailer);
715  query.bindValue(":SHOWLEVEL", m_showlevel);
716  query.bindValue(":COVERFILE", m_coverfile.isNull() ? "" : m_coverfile);
717  query.bindValue(":SCREENSHOT", m_screenshot.isNull() ? "" : m_screenshot);
718  query.bindValue(":BANNER", m_banner.isNull() ? "" : m_banner);
719  query.bindValue(":FANART", m_fanart.isNull() ? "" : m_fanart);
720  query.bindValue(":INETREF", m_inetref.isNull() ? "" : m_inetref);
721  query.bindValue(":COLLECTION", m_collectionref);
722  query.bindValue(":HOMEPAGE", m_homepage.isNull() ? "" : m_homepage);
723  query.bindValue(":BROWSE", m_browse);
724  query.bindValue(":WATCHED", m_watched);
725  query.bindValue(":HOST", m_host);
726  query.bindValue(":PROCESSED", m_processed);
727  query.bindValue(":CONTENTTYPE", ContentTypeToString(m_contenttype));
728 
729  if (!query.exec() || !query.isActive())
730  {
731  MythDB::DBError("video metadata update", query);
732  return;
733  }
734 
735  if (inserting)
736  {
737  // Must make sure we have 'id' filled before we call updateGenres or
738  // updateCountries
739 
740  if (!query.exec("SELECT LAST_INSERT_ID()") || !query.next())
741  {
742  MythDB::DBError("metadata id get", query);
743  return;
744  }
745 
746  m_id = query.value(0).toUInt();
747 
748  if (0 == m_id)
749  {
750  LOG(VB_GENERAL, LOG_ERR,
751  QString("%1: The id of the last inserted row to "
752  "videometadata seems to be 0. This is odd.")
753  .arg(__FILE__));
754  return;
755  }
756  }
757 
758  updateGenres();
759  updateCountries();
760  updateCast();
761 }
762 
764 {
765  saveToDatabase();
766 }
767 
769 {
770  saveToDatabase();
771 }
772 
774 {
778 
779  MSqlQuery query(MSqlQuery::InitCon());
780  query.prepare("DELETE FROM videometadata WHERE intid = :ID");
781  query.bindValue(":ID", m_id);
782  if (!query.exec())
783  {
784  MythDB::DBError("delete from videometadata", query);
785  }
786 
787  query.prepare("DELETE FROM filemarkup WHERE filename = :FILENAME");
788  query.bindValue(":FILENAME", m_filename);
789  if (!query.exec())
790  {
791  MythDB::DBError("delete from filemarkup", query);
792  }
793 
794  return true;
795 }
796 
798 {
799  if (id == 0)
800  {
801  m_category = "";
802  m_categoryID = id;
803  }
804  else
805  {
806  if (m_categoryID != id)
807  {
808  QString cat;
810  {
811  m_category = cat;
812  m_categoryID = id;
813  }
814  else
815  {
816  LOG(VB_GENERAL, LOG_ERR, "Unknown category id");
817  }
818  }
819  }
820 }
821 
823 {
825 
826  // ensure that all genres we have are in the DB
827  genre_list::iterator genre = m_genres.begin();
828  while (genre != m_genres.end())
829  {
830  if (!genre->second.trimmed().isEmpty())
831  {
832  genre->first = VideoGenre::getGenre().add(genre->second);
833  VideoGenreMap::getGenreMap().add(m_id, genre->first);
834  ++genre;
835  }
836  else
837  {
838  genre = m_genres.erase(genre);
839  }
840  }
841 }
842 
844 {
845  // remove countries for this video
847 
848  country_list::iterator country = m_countries.begin();
849  while (country != m_countries.end())
850  {
851  if (!country->second.trimmed().isEmpty())
852  {
853  country->first = VideoCountry::getCountry().add(country->second);
854  VideoCountryMap::getCountryMap().add(m_id, country->first);
855  ++country;
856  }
857  else
858  {
859  country = m_countries.erase(country);
860  }
861  }
862 }
863 
865 {
867 
868  // ensure that all cast we have are in the DB
869  cast_list::iterator cast = m_cast.begin();
870  while (cast != m_cast.end())
871  {
872  if (!cast->second.trimmed().isEmpty())
873  {
874  cast->first = VideoCast::GetCast().add(cast->second);
875  VideoCastMap::getCastMap().add(m_id, cast->first);
876  ++cast;
877  }
878  else
879  {
880  cast = m_cast.erase(cast);
881  }
882  }
883 }
884 
886 {
887  QString coverfile;
888  if (IsHostSet()
889  && !GetCoverFile().startsWith("/")
890  && !GetCoverFile().isEmpty()
891  && !IsDefaultCoverFile(GetCoverFile()))
892  {
893  coverfile = generate_file_url("Coverart", GetHost(),
894  GetCoverFile());
895  }
896  else
897  {
898  coverfile = GetCoverFile();
899  }
900 
901  imageMap["coverfile"] = coverfile;
902  imageMap["coverart"] = coverfile;
903 
904  QString screenshotfile;
905  if (IsHostSet() && !GetScreenshot().startsWith("/")
906  && !GetScreenshot().isEmpty())
907  {
908  screenshotfile = generate_file_url("Screenshots",
909  GetHost(), GetScreenshot());
910  }
911  else
912  {
913  screenshotfile = GetScreenshot();
914  }
915 
916  imageMap["screenshotfile"] = screenshotfile;
917  imageMap["screenshot"] = screenshotfile;
918 
919  QString bannerfile;
920  if (IsHostSet() && !GetBanner().startsWith("/")
921  && !GetBanner().isEmpty())
922  {
923  bannerfile = generate_file_url("Banners", GetHost(),
924  GetBanner());
925  }
926  else
927  {
928  bannerfile = GetBanner();
929  }
930 
931  imageMap["bannerfile"] = bannerfile;
932  imageMap["banner"] = bannerfile;
933 
934  QString fanartfile;
935  if (IsHostSet() && !GetFanart().startsWith("/")
936  && !GetFanart().isEmpty())
937  {
938  fanartfile = generate_file_url("Fanart", GetHost(),
939  GetFanart());
940  }
941  else
942  {
943  fanartfile = GetFanart();
944  }
945 
946  imageMap["fanartfile"] = fanartfile;
947  imageMap["fanart"] = fanartfile;
948 
949  QString smartimage = coverfile;
950  if (!screenshotfile.isEmpty () && (GetSeason() > 0 || GetEpisode() > 0))
951  smartimage = screenshotfile;
952  imageMap["smartimage"] = smartimage;
953 }
954 
958 namespace
959 {
960  QString eatBraces(const QString &title, const QString &left_brace,
961  const QString &right_brace)
962  {
963  QString ret(title);
964  bool keep_checking = true;
965 
966  while (keep_checking)
967  {
968  int left_position = ret.indexOf(left_brace);
969  int right_position = ret.indexOf(right_brace);
970  if (left_position == -1 || right_position == -1)
971  {
972  //
973  // No matching sets of these braces left.
974  //
975 
976  keep_checking = false;
977  }
978  else
979  {
980  if (left_position < right_position)
981  {
982  //
983  // We have a matching set like: ( foo )
984  //
985 
986  ret = ret.left(left_position) +
987  ret.right(ret.length() - right_position - 1);
988  }
989  else if (left_position > right_position)
990  {
991  //
992  // We have a matching set like: ) foo (
993  //
994 
995  ret = ret.left(right_position) +
996  ret.right(ret.length() - left_position - 1);
997  }
998  }
999  }
1000 
1001  return ret;
1002  }
1003 }
1004 
1005 int VideoMetadata::UpdateHashedDBRecord(const QString &hash,
1006  const QString &file_name,
1007  const QString &host)
1008 {
1009  MSqlQuery query(MSqlQuery::InitCon());
1010 
1011  query.prepare("SELECT intid,filename FROM videometadata WHERE "
1012  "hash = :HASH");
1013  query.bindValue(":HASH", hash);
1014 
1015  if (!query.exec() || !query.isActive())
1016  {
1017  MythDB::DBError("Video hashed metadata update", query);
1018  return -1;
1019  }
1020 
1021  if (!query.next())
1022  return -1;
1023 
1024  int intid = query.value(0).toInt();
1025  QString oldfilename = query.value(1).toString();
1026 
1027  query.prepare("UPDATE videometadata SET filename = :FILENAME, "
1028  "host = :HOST WHERE intid = :INTID");
1029  query.bindValue(":FILENAME", file_name);
1030  query.bindValue(":HOST", host);
1031  query.bindValue(":INTID", intid);
1032 
1033  if (!query.exec() || !query.isActive())
1034  {
1035  MythDB::DBError("Video hashed metadata update (videometadata)", query);
1036  return -1;
1037  }
1038 
1039  query.prepare("UPDATE filemarkup SET filename = :FILENAME "
1040  "WHERE filename = :OLDFILENAME");
1041  query.bindValue(":FILENAME", file_name);
1042  query.bindValue(":OLDFILENAME", oldfilename);
1043 
1044  if (!query.exec() || !query.isActive())
1045  {
1046  MythDB::DBError("Video hashed metadata update (filemarkup)", query);
1047  return -1;
1048  }
1049 
1050  return intid;
1051 }
1052 
1053 QString VideoMetadata::VideoFileHash(const QString &file_name,
1054  const QString &host)
1055 {
1056  if (host.isEmpty())
1057  return FileHash(file_name);
1058 
1060  {
1061  StorageGroup sgroup("Videos", host);
1062  QString fullname = sgroup.FindFile(file_name);
1063 
1064  return FileHash(fullname);
1065  }
1066 
1067  QString url = generate_file_url("Videos", host, file_name);
1068 
1069  return RemoteFile::GetFileHash(url);
1070 }
1071 
1072 QString VideoMetadata::FilenameToMeta(const QString &file_name, int position)
1073 {
1074  // position 1 returns title, 2 returns season,
1075  // 3 returns episode, 4 returns subtitle
1076 
1077  QString cleanFilename = file_name.left(file_name.lastIndexOf('.'));
1078  cleanFilename.replace(QRegExp("%20"), " ");
1079  cleanFilename.replace(QRegExp("_"), " ");
1080  cleanFilename.replace(QRegExp("\\."), " ");
1081 
1082  /*: Word(s) which should be recognized as "season" when parsing a video
1083  * file name. To list more than one word, separate them with a '|'.
1084  */
1085  QString season_translation = tr("Season", "Metadata file name parsing");
1086 
1087  /*: Word(s) which should be recognized as "episode" when parsing a video
1088  * file name. To list more than one word, separate them with a '|'.
1089  */
1090  QString episode_translation = tr("Episode", "Metadata file name parsing");
1091 
1092  // Primary Regexp
1093  QString separator = "(?:\\s?(?:-|/)?\\s?)?";
1094  QString regexp = QString(
1095  "^(.*[^s0-9])" // Title
1096  "%1" // optional separator
1097  "(?:s|(?:Season|%2))?" // season marker
1098  "%1" // optional separator
1099  "(\\d{1,4})" // Season
1100  "%1" // optional separator
1101  "(?:[ex/]|Episode|%3)" // episode marker
1102  "%1" // optional separator
1103  "(\\d{1,3})" // Episode
1104  "%1" // optional separator
1105  "(.*)$" // Subtitle
1106  ).arg(separator)
1107  .arg(season_translation).arg(episode_translation);
1108  QRegExp filename_parse(regexp,
1109  Qt::CaseInsensitive, QRegExp::RegExp2);
1110 
1111  // Cleanup Regexp
1112  QString regexp2 = QString("(%1(?:(?:Season|%2)%1\\d*%1)*%1)$")
1113  .arg(separator).arg(season_translation);
1114  QRegExp title_parse(regexp2, Qt::CaseInsensitive, QRegExp::RegExp2);
1115 
1116  int pos = filename_parse.indexIn(cleanFilename);
1117  if (pos > -1)
1118  {
1119  QString title = filename_parse.cap(1);
1120  QString season = filename_parse.cap(2);
1121  QString episode = filename_parse.cap(3);
1122  QString subtitle = filename_parse.cap(4);
1123 
1124  // Clean up the title
1125  int pos2 = title_parse.indexIn(title);
1126  if (pos2 > -1)
1127  title = title.left(pos2);
1128  title = title.right(title.length() -
1129  title.lastIndexOf('/') -1);
1130 
1131  // Return requested value
1132  if (position == 1 && !title.isEmpty())
1133  return title.trimmed();
1134  if (position == 2)
1135  return season.trimmed();
1136  if (position == 3)
1137  return episode.trimmed();
1138  if (position == 4)
1139  return subtitle.trimmed();
1140  }
1141  else if (position == 1)
1142  {
1143  QString title = cleanFilename;
1144 
1145  // Clean up the title
1146  title = title.right(title.length() -
1147  title.lastIndexOf('/') -1);
1148 
1149  title = eatBraces(title, "[", "]");
1150  title = eatBraces(title, "(", ")");
1151  title = eatBraces(title, "{", "}");
1152  return title.trimmed();
1153  }
1154  else if (position == 2 || position == 3)
1155  return QString("0");
1156 
1157  return QString();
1158 }
1159 
1160 VideoMetadata::VideoMetadata(const QString &filename, const QString &sortFilename,
1161  const QString &hash, const QString &trailer, const QString &coverfile,
1162  const QString &screenshot, const QString &banner, const QString &fanart,
1163  const QString &title, const QString &sortTitle,
1164  const QString &subtitle, const QString &sortSubtitle, const QString &tagline,
1165  int year, const QDate &releasedate, const QString &inetref, int collectionref,
1166  const QString &homepage, const QString &director, const QString &studio,
1167  const QString &plot, float userrating, const QString &rating,
1168  int length, int playcount, int season, int episode, const QDate &insertdate,
1169  int id, ParentalLevel::Level showlevel, int categoryID,
1170  int childID, bool browse, bool watched,
1171  const QString &playcommand, const QString &category,
1172  const genre_list &genres,
1173  const country_list &countries,
1174  const cast_list &cast,
1175  const QString &host, bool processed,
1176  VideoContentType contenttype)
1177 {
1178  m_imp = new VideoMetadataImp(filename, sortFilename, hash, trailer, coverfile,
1179  screenshot, banner, fanart, title, sortTitle, subtitle,
1180  sortSubtitle, tagline, year, releasedate, inetref,
1181  collectionref, homepage, director, studio, plot, userrating, rating,
1182  length, playcount, season, episode, insertdate, id, showlevel, categoryID,
1183  childID, browse, watched, playcommand, category, genres, countries,
1184  cast, host, processed, contenttype);
1185 }
1186 
1188 {
1189  delete m_imp;
1190 }
1191 
1193 {
1194  m_imp = new VideoMetadataImp(query);
1195 }
1196 
1197 VideoMetadata::VideoMetadata(const VideoMetadata &rhs) : m_imp(nullptr)
1198 {
1199  *this = rhs;
1200 }
1201 
1203 {
1204  if (this != &rhs)
1205  {
1206  m_imp = new VideoMetadataImp(*(rhs.m_imp));
1207  }
1208 
1209  return *this;
1210 }
1211 
1212 void VideoMetadata::toMap(InfoMap &metadataMap)
1213 {
1214  GetImageMap(metadataMap);
1215 
1216  metadataMap["filename"] = GetFilename();
1217  metadataMap["sortfilename"] = GetSortFilename();
1218  metadataMap["title"] = GetTitle();
1219  metadataMap["sorttitle"] = GetSortTitle();
1220  metadataMap["subtitle"] = GetSubtitle();
1221  metadataMap["sortsubtitle"] = GetSortSubtitle();
1222  metadataMap["tagline"] = GetTagline();
1223  metadataMap["director"] = GetDirector();
1224  metadataMap["studio"] = GetStudio();
1225  metadataMap["description0"] = metadataMap["description"] = GetPlot();
1226  metadataMap["genres"] = GetDisplayGenres(*this);
1227  metadataMap["countries"] = GetDisplayCountries(*this);
1228  metadataMap["cast"] = GetDisplayCast(*this).join(", ");
1229  metadataMap["rating"] = GetDisplayRating(GetRating());
1230  metadataMap["length"] = GetDisplayLength(GetLength());
1231  metadataMap["playcount"] = QString::number(GetPlayCount());
1232  metadataMap["year"] = GetDisplayYear(GetYear());
1233 
1234  metadataMap["releasedate"] = MythDate::toString(
1236 
1237  metadataMap["userrating"] = GetDisplayUserRating(GetUserRating());
1238 
1239  if (GetSeason() > 0 || GetEpisode() > 0)
1240  {
1241  metadataMap["season"] = format_season_and_episode(GetSeason(), 1);
1242  metadataMap["episode"] = format_season_and_episode(GetEpisode(), 1);
1243  metadataMap["s##e##"] = metadataMap["s00e00"] = QString("s%1e%2")
1246  metadataMap["##x##"] = metadataMap["00x00"] = QString("%1x%2")
1249  }
1250  else
1251  {
1252  metadataMap["s##e##"] = metadataMap["##x##"] = QString();
1253  metadataMap["s00e00"] = metadataMap["00x00"] = QString();
1254  metadataMap["season"] = metadataMap["episode"] = QString();
1255  }
1256 
1257  GetStateMap(metadataMap);
1258 
1259  metadataMap["insertdate"] = MythDate::toString(
1261  metadataMap["inetref"] = GetInetRef();
1262  metadataMap["homepage"] = GetHomepage();
1263  metadataMap["child_id"] = QString::number(GetChildID());
1264  metadataMap["browseable"] = GetDisplayBrowse(GetBrowse());
1265  metadataMap["watched"] = GetDisplayWatched(GetWatched());
1266  metadataMap["processed"] = GetDisplayProcessed(GetProcessed());
1267  metadataMap["category"] = GetCategory();
1268 }
1269 
1270 
1272 {
1273  stateMap["trailerstate"] = TrailerToState(GetTrailer());
1274  stateMap["userratingstate"] =
1275  QString::number((int)(GetUserRating()));
1276  stateMap["watchedstate"] = WatchedToState(GetWatched());
1277  stateMap["videolevel"] = ParentalLevelToState(GetShowLevel());
1278 }
1279 
1281 {
1282  m_imp->GetImageMap(imageMap);
1283 }
1284 
1285 void ClearMap(InfoMap &metadataMap)
1286 {
1287  metadataMap["coverfile"] = "";
1288  metadataMap["screenshotfile"] = "";
1289  metadataMap["bannerfile"] = "";
1290  metadataMap["fanartfile"] = "";
1291  metadataMap["filename"] = "";
1292  metadataMap["sortfilename"] = "";
1293  metadataMap["title"] = "";
1294  metadataMap["sorttitle"] = "";
1295  metadataMap["subtitle"] = "";
1296  metadataMap["sortsubtitle"] = "";
1297  metadataMap["tagline"] = "";
1298  metadataMap["director"] = "";
1299  metadataMap["studio"] = "";
1300  metadataMap["description"] = "";
1301  metadataMap["description0"] = "";
1302  metadataMap["genres"] = "";
1303  metadataMap["countries"] = "";
1304  metadataMap["cast"] = "";
1305  metadataMap["rating"] = "";
1306  metadataMap["length"] = "";
1307  metadataMap["playcount"] = "";
1308  metadataMap["year"] = "";
1309  metadataMap["releasedate"] = "";
1310  metadataMap["userrating"] = "";
1311  metadataMap["season"] = "";
1312  metadataMap["episode"] = "";
1313  metadataMap["s##e##"] = "";
1314  metadataMap["##x##"] = "";
1315  metadataMap["trailerstate"] = "";
1316  metadataMap["userratingstate"] = "";
1317  metadataMap["watchedstate"] = "";
1318  metadataMap["videolevel"] = "";
1319  metadataMap["insertdate"] = "";
1320  metadataMap["inetref"] = "";
1321  metadataMap["homepage"] = "";
1322  metadataMap["child_id"] = "";
1323  metadataMap["browseable"] = "";
1324  metadataMap["watched"] = "";
1325  metadataMap["category"] = "";
1326  metadataMap["processed"] = "";
1327 }
1328 
1329 const QString &VideoMetadata::GetPrefix() const
1330 {
1331  return m_imp->GetPrefix();
1332 }
1333 
1334 void VideoMetadata::SetPrefix(const QString &prefix)
1335 {
1337 }
1338 
1339 const QString &VideoMetadata::GetTitle() const
1340 {
1341  return m_imp->getTitle();
1342 }
1343 
1344 const QString &VideoMetadata::GetSortTitle() const
1345 {
1346  return m_imp->getSortTitle();
1347 }
1348 
1349 void VideoMetadata::SetTitle(const QString &title, const QString &sortTitle)
1350 {
1351  m_imp->SetTitle(title, sortTitle);
1352 }
1353 
1354 const QString &VideoMetadata::GetSubtitle() const
1355 {
1356  return m_imp->getSubtitle();
1357 }
1358 
1359 const QString &VideoMetadata::GetSortSubtitle() const
1360 {
1361  return m_imp->getSortSubtitle();
1362 }
1363 
1364 void VideoMetadata::SetSubtitle(const QString &subtitle, const QString &sortSubtitle)
1365 {
1366  m_imp->SetSubtitle(subtitle, sortSubtitle);
1367 }
1368 
1369 const QString &VideoMetadata::GetTagline() const
1370 {
1371  return m_imp->GetTagline();
1372 }
1373 
1374 void VideoMetadata::SetTagline(const QString &tagline)
1375 {
1376  m_imp->SetTagline(tagline);
1377 }
1378 
1380 {
1381  return m_imp->getYear();
1382 }
1383 
1385 {
1386  m_imp->SetYear(year);
1387 }
1388 
1390 {
1391  return m_imp->getReleaseDate();
1392 }
1393 
1394 void VideoMetadata::SetReleaseDate(QDate releasedate)
1395 {
1396  m_imp->SetReleaseDate(releasedate);
1397 }
1398 
1399 const QString &VideoMetadata::GetInetRef() const
1400 {
1401  return m_imp->GetInetRef();
1402 }
1403 
1404 void VideoMetadata::SetInetRef(const QString &inetRef)
1405 {
1406  m_imp->SetInetRef(inetRef);
1407 }
1408 
1410 {
1411  return m_imp->GetCollectionRef();
1412 }
1413 
1414 void VideoMetadata::SetCollectionRef(int collectionref)
1415 {
1416  m_imp->SetCollectionRef(collectionref);
1417 }
1418 
1419 const QString &VideoMetadata::GetHomepage() const
1420 {
1421  return m_imp->GetHomepage();
1422 }
1423 
1424 void VideoMetadata::SetHomepage(const QString &homepage)
1425 {
1426  m_imp->SetHomepage(homepage);
1427 }
1428 
1429 const QString &VideoMetadata::GetDirector() const
1430 {
1431  return m_imp->getDirector();
1432 }
1433 
1434 void VideoMetadata::SetDirector(const QString &director)
1435 {
1436  m_imp->SetDirector(director);
1437 }
1438 
1439 const QString &VideoMetadata::GetStudio() const
1440 {
1441  return m_imp->getStudio();
1442 }
1443 
1444 void VideoMetadata::SetStudio(const QString &studio)
1445 {
1446  m_imp->SetStudio(studio);
1447 }
1448 
1449 const QString &VideoMetadata::GetPlot() const
1450 {
1451  return m_imp->getPlot();
1452 }
1453 
1454 void VideoMetadata::SetPlot(const QString &plot)
1455 {
1456  m_imp->SetPlot(plot);
1457 }
1458 
1460 {
1461  return m_imp->GetUserRating();
1462 }
1463 
1464 void VideoMetadata::SetUserRating(float userRating)
1465 {
1466  m_imp->SetUserRating(userRating);
1467 }
1468 
1469 const QString &VideoMetadata::GetRating() const
1470 {
1471  return m_imp->GetRating();
1472 }
1473 
1474 void VideoMetadata::SetRating(const QString &rating)
1475 {
1477 }
1478 
1480 {
1481  return m_imp->GetLength();
1482 }
1483 
1485 {
1486  m_imp->SetLength(length);
1487 }
1488 
1489 unsigned int VideoMetadata::GetPlayCount() const
1490 {
1491  return m_imp->GetPlayCount();
1492 }
1493 
1495 {
1496  m_imp->SetPlayCount(count);
1497 }
1498 
1500 {
1501  return m_imp->GetSeason();
1502 }
1503 
1505 {
1506  m_imp->SetSeason(season);
1507 }
1508 
1510 {
1511  return m_imp->GetEpisode();
1512 }
1513 
1514 void VideoMetadata::SetEpisode(int episode)
1515 {
1516  m_imp->SetEpisode(episode);
1517 }
1518 
1520 {
1521  return m_imp->GetInsertdate();
1522 }
1523 
1525 {
1526  m_imp->SetInsertdate(date);
1527 }
1528 
1529 unsigned int VideoMetadata::GetID() const
1530 {
1531  return m_imp->GetID();
1532 }
1533 
1535 {
1536  m_imp->SetID(id);
1537 }
1538 
1540 {
1541  return m_imp->GetChildID();
1542 }
1543 
1544 void VideoMetadata::SetChildID(int childID)
1545 {
1546  m_imp->SetChildID(childID);
1547 }
1548 
1550 {
1551  return m_imp->GetBrowse();
1552 }
1553 
1554 void VideoMetadata::SetBrowse(bool browse)
1555 {
1556  m_imp->SetBrowse(browse);
1557 }
1558 
1560 {
1561  return m_imp->GetWatched();
1562 }
1563 
1564 void VideoMetadata::SetWatched(bool watched)
1565 {
1566  m_imp->SetWatched(watched);
1567 }
1568 
1570 {
1571  return m_imp->GetProcessed();
1572 }
1573 
1574 void VideoMetadata::SetProcessed(bool processed)
1575 {
1576  m_imp->SetProcessed(processed);
1577 }
1578 
1580 {
1581  return m_imp->GetContentType();
1582 }
1583 
1585 {
1586  m_imp->SetContentType(contenttype);
1587 }
1588 
1589 const QString &VideoMetadata::GetPlayCommand() const
1590 {
1591  return m_imp->getPlayCommand();
1592 }
1593 
1594 void VideoMetadata::SetPlayCommand(const QString &playCommand)
1595 {
1596  m_imp->SetPlayCommand(playCommand);
1597 }
1598 
1600 {
1601  return m_imp->GetShowLevel();
1602 }
1603 
1605 {
1606  m_imp->SetShowLevel(showLevel);
1607 }
1608 
1609 const QString &VideoMetadata::GetFilename() const
1610 {
1611  return m_imp->getFilename();
1612 }
1613 
1614 const QString &VideoMetadata::GetSortFilename() const
1615 {
1616  return m_imp->getSortFilename();
1617 }
1618 
1619 const QString &VideoMetadata::GetHash() const
1620 {
1621  return m_imp->GetHash();
1622 }
1623 
1624 void VideoMetadata::SetHash(const QString &hash)
1625 {
1626  return m_imp->SetHash(hash);
1627 }
1628 
1629 const QString &VideoMetadata::GetHost() const
1630 {
1631  return m_imp->GetHost();
1632 }
1633 
1634 void VideoMetadata::SetHost(const QString &host)
1635 {
1636  m_imp->SetHost(host);
1637 }
1638 
1639 void VideoMetadata::SetFilename(const QString &filename, const QString &sortFilename)
1640 {
1641  m_imp->SetFilename(filename, sortFilename);
1642 }
1643 
1644 const QString &VideoMetadata::GetTrailer() const
1645 {
1646  return m_imp->GetTrailer();
1647 }
1648 
1649 void VideoMetadata::SetTrailer(const QString &trailer)
1650 {
1651  m_imp->SetTrailer(trailer);
1652 }
1653 
1654 const QString &VideoMetadata::GetCoverFile() const
1655 {
1656  return m_imp->GetCoverFile();
1657 }
1658 
1659 void VideoMetadata::SetCoverFile(const QString &coverFile)
1660 {
1661  m_imp->SetCoverFile(coverFile);
1662 }
1663 
1664 const QString &VideoMetadata::GetScreenshot() const
1665 {
1666  return m_imp->GetScreenshot();
1667 }
1668 
1669 void VideoMetadata::SetScreenshot(const QString &screenshot)
1670 {
1671  m_imp->SetScreenshot(screenshot);
1672 }
1673 
1674 const QString &VideoMetadata::GetBanner() const
1675 {
1676  return m_imp->GetBanner();
1677 }
1678 
1679 void VideoMetadata::SetBanner(const QString &banner)
1680 {
1681  m_imp->SetBanner(banner);
1682 }
1683 
1684 const QString &VideoMetadata::GetFanart() const
1685 {
1686  return m_imp->GetFanart();
1687 }
1688 
1689 void VideoMetadata::SetFanart(const QString &fanart)
1690 {
1691  m_imp->SetFanart(fanart);
1692 }
1693 
1694 const QString &VideoMetadata::GetCategory() const
1695 {
1696  return m_imp->GetCategory();
1697 }
1698 
1699 //void VideoMetadata::SetCategory(const QString &category)
1700 //{
1701 // m_imp->SetCategory(category);
1702 //}
1703 
1705 {
1706  return m_imp->getGenres();
1707 }
1708 
1710 {
1711  m_imp->SetGenres(genres);
1712 }
1713 
1715 {
1716  return m_imp->GetCast();
1717 }
1718 
1720 {
1721  m_imp->SetCast(cast);
1722 }
1723 
1725 {
1726  return m_imp->GetCountries();
1727 }
1728 
1730 {
1731  m_imp->SetCountries(countries);
1732 }
1733 
1735 {
1736  return m_imp->GetCategoryID();
1737 }
1738 
1740 {
1741  m_imp->SetCategoryID(id);
1742 }
1743 
1745 {
1746  m_imp->SaveToDatabase();
1747 }
1748 
1750 {
1751  m_imp->UpdateDatabase();
1752 }
1753 
1755 {
1756  return m_imp->DeleteFromDatabase();
1757 }
1758 
1759 #if 0
1760 bool VideoMetadata::fillDataFromID(const VideoMetadataListManager &cache)
1761 {
1762  if (m_imp->getID() == 0)
1763  return false;
1764 
1766  if (mp.get())
1767  {
1768  *this = *mp;
1769  return true;
1770  }
1771 
1772  return false;
1773 }
1774 #endif
1775 
1777 {
1778  if (m_imp->getFilename().isEmpty())
1779  return false;
1780 
1782  cache.byFilename(m_imp->getFilename());
1783  if (mp)
1784  {
1785  *this = *mp;
1786  return true;
1787  }
1788 
1789  return false;
1790 }
1791 
1793 {
1794  return m_imp->DeleteFile();
1795 }
1796 
1798 {
1799  m_imp->Reset();
1800 }
1801 
1803 {
1804  return m_imp->IsHostSet();
1805 }
1806 
1808 {
1809  return m_imp->sortBefore(rhs.m_imp);
1810 }
1811 
1812 bool operator==(const VideoMetadata& a, const VideoMetadata& b)
1813 {
1814  return a.GetFilename() == b.GetFilename();
1815 }
1816 
1817 bool operator!=(const VideoMetadata& a, const VideoMetadata& b)
1818 {
1819  return a.GetFilename() != b.GetFilename();
1820 }
Level GetLevel() const
void SetCategoryID(int id)
void SetHomepage(const QString &homepage)
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
std::vector< cast_entry > cast_list
Definition: videometadata.h:34
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:418
QString GetDisplayRating(const QString &rating)
Definition: videoutils.cpp:211
VideoContentType m_contenttype
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle="")
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
float GetUserRating() const
void SetCollectionRef(int collectionref)
int GetLength() const
VideoContentType GetContentType() const
const QString & GetSortFilename() const
QString GetDisplayUserRating(float userrating)
Definition: videoutils.cpp:151
VideoMetadataImp(const QString &filename, const QString &sortFilename, const QString &hash, const QString &trailer, const QString &coverfile, const QString &screenshot, const QString &banner, const QString &fanart, const QString &title, const QString &sortTitle, const QString &subtitle, const QString &sortSubtitle, const QString &tagline, int year, const QDate &releasedate, const QString &inetref, int collectionref, const QString &homepage, const QString &director, const QString &studio, const QString &plot, float userrating, const QString &rating, int length, int playcount, int season, int episode, const QDate &insertdate, int id, ParentalLevel::Level showlevel, int categoryID, int childID, bool browse, bool watched, const QString &playcommand, const QString &category, const genre_list &genres, const country_list &countries, const cast_list &cast, const QString &host="", bool processed=false, VideoContentType contenttype=kContentUnknown)
bool GetWatched() const
VideoMetadata & operator=(const VideoMetadata &rhs)
void SetID(int id)
const QString & getPlayCommand() const
static VideoCastMap & getCastMap()
Definition: dbaccess.cpp:578
const QString & getPlot() const
void SetUserRating(float userRating)
void SetUserRating(float userRating)
const QString & GetInetRef() const
bool GetBrowse() const
void SetPlayCount(int playcount)
const QString VIDEO_SCREENSHOT_DEFAULT
Definition: globals.cpp:27
void SetContentType(VideoContentType contenttype)
bool get(int id, QString &category)
Definition: dbaccess.cpp:222
QDate GetInsertdate() const
const QString & GetPlayCommand() const
bool FillDataFromFilename(const VideoMetadataListManager &cache)
void SetTrailer(const QString &trailer)
QString GetDisplayCountries(const VideoMetadata &item)
Definition: videoutils.cpp:225
int GetSeason() const
const QString & GetPrefix() const
const QString & GetHash() const
void fromDBRow(MSqlQuery &query)
Sets metadata from a DB row.
const QString & GetFanart() const
int GetChildID() const
void SetHash(const QString &hash)
const QString & GetTrailer() const
void SetTrailer(const QString &trailer)
class VideoMetadataImp * m_imp
int add(int id, int value)
Definition: dbaccess.cpp:450
void SetFanart(const QString &fanart)
void SetRating(const QString &rating)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
void SetTitle(const QString &title, const QString &sortTitle="")
const QString & GetCoverFile() const
QDate GetReleaseDate() const
const QString & GetCategory() const
QString GetDisplayGenres(const VideoMetadata &item)
Definition: videoutils.cpp:218
void SetShowLevel(ParentalLevel::Level showLevel)
void Reset()
Resets to default metadata.
bool DeleteFromDatabase()
void GetImageMap(InfoMap &imageMap)
MPUBLIC QString format_season_and_episode(int seasEp, int digits)
const QString & GetHash() const
bool IsHostSet() const
bool IsHostSet() const
void SetPrefix(const QString &prefix)
const QString & GetDirector() const
unsigned int GetPlayCount() const
const QString & GetRating() const
int add(const QString &name)
Definition: dbaccess.cpp:217
const QString & GetPrefix() const
const QString & GetBanner() const
void SetPlot(const QString &plot)
void SetDirector(const QString &director)
void SetInsertdate(QDate date)
const QString & getSortTitle() const
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void SetHomepage(const QString &homepage)
static VideoCategory & GetCategory()
Definition: dbaccess.cpp:492
std::vector< country_entry > country_list
Definition: videometadata.h:33
bool IsDefaultCoverFile(const QString &coverfile)
Definition: videoutils.cpp:127
ParentalLevel::Level GetShowLevel() const
bool operator!=(const VideoMetadata &a, const VideoMetadata &b)
VideoMetadataImp & operator=(const VideoMetadataImp &rhs)
QStringList GetDisplayCast(const VideoMetadata &item)
Definition: videoutils.cpp:232
void SetGenres(const genre_list &genres)
unsigned int m_id
void SetInsertdate(QDate date)
void SetPlayCommand(const QString &playCommand)
void SetStudio(const QString &studio)
static guint32 * tmp
Definition: goom_core.c:35
void SetFilename(const QString &filename, const QString &sortFilename="")
unsigned int GetID() const
void SetYear(int year)
static VideoCountryMap & getCountryMap()
Definition: dbaccess.cpp:563
void SetTagline(const QString &tagline)
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle="")
const QString & GetTrailer() const
void SetCountries(const country_list &countries)
const QString & GetCategory() const
int GetCollectionRef() const
int getYear() const
void SetInetRef(const QString &inetRef)
bool IsThisHost(const QString &addr)
is this address mapped to this host
VideoMetadata::cast_list cast_list
bool GetWatched() const
const QString & GetFanart() const
unsigned char b
Definition: ParseText.cpp:329
const QString & GetHomepage() const
void SetStudio(const QString &studio)
VideoMetadata::genre_list genre_list
QVariant value(int i) const
Definition: mythdbcon.h:198
int GetLength() const
ParentalLevel::Level GetShowLevel() const
int GetYear() const
void SetCoverFile(const QString &coverFile)
void ClearMap(InfoMap &metadataMap)
static VideoCountry & getCountry()
Definition: dbaccess.cpp:506
const QString & GetTagline() const
void SetScreenshot(const QString &screenshot)
QDate GetInsertdate() const
QString TrailerToState(const QString &trailerFile)
Definition: videoutils.cpp:263
const QString VIDEO_PLOT_DEFAULT
Definition: globals.cpp:32
def rating(profile, smoonURL, gate)
Definition: scan.py:25
int GetCategoryID() const
unsigned int GetPlayCount() const
VideoMetadataPtr byFilename(const QString &file_name) const
void SetChildID(int childID)
void SetPrefix(const QString &prefix)
values_type values
Definition: dbaccess.h:43
float GetUserRating() const
void SetCountries(const country_list &countries)
const QString & GetPlot() const
QDate getReleaseDate() const
VideoMetadataImp(const VideoMetadataImp &other)
void SetSeason(int season)
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
const QString & getSubtitle() const
QString GetDisplayWatched(bool watched)
Definition: videoutils.cpp:178
int GetEpisode() const
const QString VIDEO_TRAILER_DEFAULT
Definition: globals.cpp:26
static const uint16_t * d
int GetChildID() const
bool GetProcessed() const
void SetEpisode(int episode)
const QString & GetSortTitle() const
bool sortBefore(const VideoMetadata &rhs) const
const QString & getTitle() const
void GetImageMap(InfoMap &imageMap) const
const QString & getFilename() const
void SetFilename(const QString &filename, const QString &sortFilename="")
bool isActive(void) const
Definition: mythdbcon.h:204
Default local time.
Definition: mythdate.h:16
void toMap(InfoMap &metadataMap)
bool GetProcessed() const
bool operator==(const VideoMetadata &a, const VideoMetadata &b)
const QString & GetRating() const
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
static QString FilenameToMeta(const QString &file_name, int position)
void SetEpisode(int episode)
void SetInetRef(const QString &inetRef)
const QString & GetHomepage() const
std::vector< genre_entry > genre_list
Definition: videometadata.h:32
const char * name
Definition: ParseText.cpp:328
static int UpdateHashedDBRecord(const QString &hash, const QString &file_name, const QString &host)
static QString VideoFileHash(const QString &file_name, const QString &host)
int GetCategoryID() const
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
static VideoCast & GetCast()
Definition: dbaccess.cpp:534
int GetCollectionRef() const
const QString & GetHost() const
QString GetDisplayYear(int year)
Definition: videoutils.cpp:206
void SetProcessed(bool processed)
bool DeleteFile()
Deletes the file associated with a metadata entry.
void SetTagline(const QString &tagline)
const QString & GetScreenshot() const
const QString & getSortFilename() const
void SetReleaseDate(QDate releasedate)
const cast_list & GetCast() const
void remove(int id, int value)
Definition: dbaccess.cpp:460
void SetHash(const QString &hash)
void SetCast(const cast_list &cast)
bool sortBefore(const VideoMetadataImp *rhs) const
Returns true if the object should appear before the argument.
void SetTitle(const QString &title, const QString &sortTitle="")
const QString & getStudio() const
const QString & GetHost() const
void SetFanart(const QString &fanart)
void SetHost(const QString &host)
VideoContentType ContentTypeFromString(const QString &type)
Definition: videoutils.cpp:283
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:461
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
const country_list & GetCountries() const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool removeDir(const QString &dirName)
const QString & GetFilename() const
void SetScreenshot(const QString &screenshot)
QString WatchedToState(bool watched)
Definition: videoutils.cpp:273
const QString VIDEO_DIRECTOR_UNKNOWN
Definition: globals.cpp:9
void SetWatched(bool watched)
static VideoGenreMap & getGenreMap()
Definition: dbaccess.cpp:548
void SetID(int id)
unsigned int GetID() const
const QString VIDEO_INETREF_DEFAULT
Definition: globals.cpp:24
void SetGenres(const genre_list &genres)
QString GetDisplayLength(int length)
Definition: videoutils.cpp:156
const QString & getDirector() const
void ensureSortFields(void)
void SetLength(int length)
const QString & GetTagline() const
QString FindFile(const QString &filename)
static VideoGenre & getGenre()
Definition: dbaccess.cpp:520
const cast_list & GetCast() const
void SetShowLevel(ParentalLevel::Level showLevel)
int GetSeason() const
void SetYear(int year)
const QString & GetBanner() const
QString ContentTypeToString(VideoContentType type)
Definition: videoutils.cpp:301
void SetCoverFile(const QString &coverFile)
const QString VIDEO_COVERFILE_DEFAULT
Definition: globals.cpp:25
VideoMetadataPtr byID(unsigned int db_id) const
bool GetBrowse() const
void SetLength(int length)
void GetStateMap(InfoMap &stateMap)
void SetRating(const QString &rating)
void SetChildID(int childID)
void SetSeason(int season)
QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
Definition: videoutils.h:65
const QString & GetScreenshot() const
T * get() const
Definition: quicksp.h:65
VideoMetadata(const QString &filename=QString(), const QString &sortFilename=QString(), const QString &hash=QString(), const QString &trailer=QString(), const QString &coverfile=QString(), const QString &screenshot=QString(), const QString &banner=QString(), const QString &fanart=QString(), const QString &title=QString(), const QString &sortTitle=QString(), const QString &subtitle=QString(), const QString &sortSubtitle=QString(), const QString &tagline=QString(), int year=VIDEO_YEAR_DEFAULT, const QDate &releasedate=QDate(), const QString &inetref=QString(), int collectionref=0, const QString &homepage=QString(), const QString &director=QString(), const QString &studio=QString(), const QString &plot=QString(), float userrating=0.0, const QString &rating=QString(), int length=0, int playcount=0, int season=0, int episode=0, const QDate &insertdate=QDate(), int id=0, ParentalLevel::Level showlevel=ParentalLevel::plLowest, int categoryID=0, int childID=-1, bool browse=true, bool watched=false, const QString &playcommand=QString(), const QString &category=QString(), const genre_list &genres=genre_list(), const country_list &countries=country_list(), const cast_list &cast=cast_list(), const QString &host="", bool processed=false, VideoContentType contenttype=kContentUnknown)
void SetProcessed(bool processed)
void SetPlayCommand(const QString &playCommand)
void SetBrowse(bool browse)
const QString VIDEO_RATING_DEFAULT
Definition: globals.cpp:30
const QString & GetSubtitle() const
VideoContentType
void SetHost(const QString &host)
const QString & GetCoverFile() const
Add year to string if not included.
Definition: mythdate.h:22
QString GetDisplayProcessed(bool processed)
Definition: videoutils.cpp:192
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
const genre_list & GetGenres() const
QString GetDisplayBrowse(bool browse)
Definition: videoutils.cpp:164
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
const QString VIDEO_FANART_DEFAULT
Definition: globals.cpp:29
const QString & GetInetRef() const
bool IsMasterBackend(void)
is this the actual MBE process
const QString & GetStudio() const
void SetWatched(bool watched)
const QString & GetTitle() const
void SetBanner(const QString &banner)
void SetDirector(const QString &director)
bool get(int id, entry &values)
Definition: dbaccess.cpp:455
const QString VIDEO_DIRECTOR_DEFAULT
Definition: globals.cpp:23
void SetContentType(VideoContentType contenttype)
QString FileHash(const QString &filename)
int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
int GetEpisode() const
const QString & getSortSubtitle() const
void SetPlot(const QString &plot)
country_list m_countries
void SetPlayCount(int count)
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
VideoMetadata::country_list country_list
void SetBanner(const QString &banner)
VideoMetadataImp(MSqlQuery &query)
VideoContentType GetContentType() const
void SetBrowse(bool browse)
void SetReleaseDate(QDate releasedate)
void SetCategoryID(int id)
const genre_list & getGenres() const
static QString GetFileHash(const QString &url)
Definition: remotefile.cpp:553
const QString & GetSortSubtitle() const
const QString VIDEO_BANNER_DEFAULT
Definition: globals.cpp:28
ParentalLevel::Level m_showlevel
void SetCollectionRef(int collectionref)
const country_list & GetCountries() const
QString ParentalLevelToState(const ParentalLevel &level)
Definition: videoutils.cpp:239
void SetCast(const cast_list &cast)
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.