MythTV  master
videometadata.cpp
Go to the documentation of this file.
1 #include <cmath> // for isnan()
2 
3 #include <QDir>
4 #include <QFile>
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(QString filename, QString sortFilename,
35  QString hash, QString trailer,
36  QString coverfile, QString screenshot, QString banner,
37  QString fanart, const QString &title, QString sortTitle,
38  const QString &subtitle, QString sortSubtitle,
39  QString tagline, int year, const QDate &releasedate,
40  QString inetref, int collectionref, QString homepage,
41  QString director, QString studio,
42  QString plot, float userrating,
43  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  QString playcommand, QString category,
50  cast_list cast,
51  QString host = "",
52  bool processed = false,
53  VideoContentType contenttype = kContentUnknown) :
54  m_title(title), m_sortTitle(std::move(sortTitle)), m_subtitle(subtitle),
55  m_sortSubtitle(std::move(sortSubtitle)), m_tagline(std::move(tagline)),
56  m_inetref(std::move(inetref)), m_collectionref(collectionref),
57  m_homepage(std::move(homepage)), m_director(std::move(director)),
58  m_studio(std::move(studio)), m_plot(std::move(plot)),
59  m_rating(std::move(rating)), m_playcommand(std::move(playcommand)),
60  m_category(std::move(category)), m_genres(std::move(genres)),
61  m_countries(std::move(countries)), m_cast(std::move(cast)),
62  m_filename(std::move(filename)), m_sortFilename(std::move(sortFilename)),
63  m_hash(std::move(hash)), m_trailer(std::move(trailer)),
64  m_coverfile(std::move(coverfile)), m_screenshot(std::move(screenshot)),
65  m_banner(std::move(banner)), m_fanart(std::move(fanart)),
66  m_host(std::move(host)), m_categoryID(categoryID), m_childID(childID),
67  m_year(year), m_releasedate(releasedate), m_length(length), m_playcount(playcount),
68  m_season(season), m_episode(episode), m_insertdate(insertdate), m_showlevel(showlevel),
69  m_browse(browse), m_watched(watched), m_id(id),
70  m_userrating(userrating), m_processed(processed),
71  m_contenttype(contenttype)
72  {
73  // Try to glean data if none provided.
74  if (title.isEmpty() and subtitle.isEmpty()
75  and season == 0 and episode == 0)
76  {
77  m_title = VideoMetadata::FilenameToMeta(m_filename, 1);
78  m_subtitle = VideoMetadata::FilenameToMeta(m_filename, 4);
79  m_season = VideoMetadata::FilenameToMeta(m_filename, 2).toInt();
80  m_episode = VideoMetadata::FilenameToMeta(m_filename, 3).toInt();
81  }
82 
83  VideoCategory::GetCategory().get(m_categoryID, m_category);
84 
85  ensureSortFields();
86  }
87 
89  {
90  fromDBRow(query);
91  ensureSortFields();
92  }
93 
95  {
96  *this = other;
97  }
98 
100  {
101  if (this != &rhs)
102  {
103  m_title = rhs.m_title;
104  m_sortTitle = rhs.m_sortTitle;
105  m_subtitle = rhs.m_subtitle;
106  m_sortSubtitle = rhs.m_sortSubtitle;
107  m_tagline = rhs.m_tagline;
108  m_inetref = rhs.m_inetref;
109  m_collectionref = rhs.m_collectionref;
110  m_homepage = rhs.m_homepage;
111  m_director = rhs.m_director;
112  m_studio = rhs.m_studio;
113  m_plot = rhs.m_plot;
114  m_rating = rhs.m_rating;
115  m_playcommand = rhs.m_playcommand;
116  m_category = rhs.m_category;
117  m_genres = rhs.m_genres;
118  m_countries = rhs.m_countries;
119  m_cast = rhs.m_cast;
120  m_filename = rhs.m_filename;
121  m_sortFilename = rhs.m_sortFilename;
122  m_hash = rhs.m_hash;
123  m_trailer = rhs.m_trailer;
124  m_coverfile = rhs.m_coverfile;
125  m_screenshot = rhs.m_screenshot;
126  m_banner = rhs.m_banner;
127  m_fanart = rhs.m_fanart;
128 
129  m_categoryID = rhs.m_categoryID;
130  m_childID = rhs.m_childID;
131  m_year = rhs.m_year;
132  m_releasedate = rhs.m_releasedate;
133  m_length = rhs.m_length;
134  m_playcount = rhs.m_playcount;
135  m_season = rhs.m_season;
136  m_episode = rhs.m_episode;
137  m_insertdate = rhs.m_insertdate;
138  m_showlevel = rhs.m_showlevel;
139  m_browse = rhs.m_browse;
140  m_watched = rhs.m_watched;
141  m_id = rhs.m_id;
142  m_userrating = rhs.m_userrating;
143  m_host = rhs.m_host;
144  m_processed = rhs.m_processed;
145  m_contenttype = rhs.m_contenttype;
146 
147  // No DB vars
148  m_prefix = rhs.m_prefix;
149 
150  ensureSortFields();
151  }
152 
153  return *this;
154  }
155 
156  void ensureSortFields(void)
157  {
158  std::shared_ptr<MythSortHelper>sh = getMythSortHelper();
159  if (m_sortTitle.isEmpty() and not m_title.isEmpty())
160  m_sortTitle = sh->doTitle(m_title);
161  if (m_sortSubtitle.isEmpty() and not m_subtitle.isEmpty())
162  m_sortSubtitle = sh->doTitle(m_subtitle);
163  if (m_sortFilename.isEmpty() and not m_filename.isEmpty())
164  m_sortFilename = sh->doPathname(m_filename);
165  }
166 
167  public:
168  const QString &GetPrefix() const { return m_prefix; }
169  void SetPrefix(const QString &prefix) { m_prefix = prefix; }
170 
171  const QString &getTitle() const { return m_title; }
172  const QString &getSortTitle() const { return m_sortTitle; }
173  void SetTitle(const QString& title, const QString& sortTitle = "")
174  {
175  m_title = title;
176  m_sortTitle = sortTitle;
177  ensureSortFields();
178  }
179 
180  const QString &getSubtitle() const { return m_subtitle; }
181  const QString &getSortSubtitle() const { return m_sortSubtitle; }
182  void SetSubtitle(const QString &subtitle, const QString &sortSubtitle = "") {
183  m_subtitle = subtitle;
184  m_sortSubtitle = sortSubtitle;
185  ensureSortFields();
186  }
187 
188  const QString &GetTagline() const { return m_tagline; }
189  void SetTagline(const QString &tagline) { m_tagline = tagline; }
190 
191  const QString &GetInetRef() const { return m_inetref; }
192  void SetInetRef(const QString &inetRef) { m_inetref = inetRef; }
193 
194  int GetCollectionRef() const { return m_collectionref; }
195  void SetCollectionRef(int collectionref) { m_collectionref = collectionref; }
196 
197  const QString &GetHomepage() const { return m_homepage; }
198  void SetHomepage(const QString &homepage) { m_homepage = homepage; }
199 
200  const QString &getDirector() const { return m_director; }
201  void SetDirector(const QString &director) { m_director = director; }
202 
203  const QString &getStudio() const { return m_studio; }
204  void SetStudio(const QString &studio) { m_studio = studio; }
205 
206  const QString &getPlot() const { return m_plot; }
207  void SetPlot(const QString &plot) { m_plot = plot; }
208 
209  const QString &GetRating() const { return m_rating; }
210  void SetRating(const QString &rating) { m_rating = rating; }
211 
212  const QString &getPlayCommand() const { return m_playcommand; }
213  void SetPlayCommand(const QString &playCommand)
214  {
215  m_playcommand = playCommand;
216  }
217 
218  const QString &GetCategory() const { return m_category; }
219 // void SetCategory(const QString &category) { m_category = category; }
220 
221  const genre_list &getGenres() const { return m_genres; }
222  void SetGenres(const genre_list &genres) { m_genres = genres; }
223 
224  const country_list &GetCountries() const { return m_countries; }
226  {
227  m_countries = countries;
228  }
229 
230  const cast_list &GetCast() const { return m_cast; }
231  void SetCast(const cast_list &cast) { m_cast = cast; }
232 
233  const QString &GetHost() const { return m_host; }
234  void SetHost(const QString &host) { m_host = host; }
235 
236  const QString &getFilename() const { return m_filename; }
237  const QString &getSortFilename() const { return m_sortFilename; }
238  void SetFilename(const QString &filename, const QString &sortFilename = "")
239  {
240  m_filename = filename;
241  m_sortFilename = sortFilename;
242  ensureSortFields();
243  }
244 
245  bool sortBefore(const VideoMetadataImp *rhs) const;
246 
247  const QString &GetHash() const { return m_hash; }
248  void SetHash(const QString &hash) { m_hash = hash; }
249 
250  const QString &GetTrailer() const { return m_trailer; }
251  void SetTrailer(const QString &trailer) { m_trailer = trailer; }
252 
253  const QString &GetCoverFile() const { return m_coverfile; }
254  void SetCoverFile(const QString &coverFile) { m_coverfile = coverFile; }
255 
256  const QString &GetScreenshot() const { return m_screenshot; }
257  void SetScreenshot(const QString &screenshot) { m_screenshot = screenshot; }
258 
259  const QString &GetBanner() const { return m_banner; }
260  void SetBanner(const QString &banner) { m_banner = banner; }
261 
262  const QString &GetFanart() const { return m_fanart; }
263  void SetFanart(const QString &fanart) { m_fanart = fanart; }
264 
265  int GetCategoryID() const
266  {
267  return m_categoryID;
268  }
269  void SetCategoryID(int id);
270 
271  int GetChildID() const { return m_childID; }
272  void SetChildID(int childID) { m_childID = childID; }
273 
274  int getYear() const { return m_year; }
275  void SetYear(int year) { m_year = year; }
276 
277  QDate getReleaseDate() const { return m_releasedate; }
278  void SetReleaseDate(QDate releasedate) { m_releasedate = releasedate; }
279 
280  int GetLength() const { return m_length; }
281  void SetLength(int length) { m_length = length; }
282 
283  unsigned int GetPlayCount() const { return m_playcount; }
284  void SetPlayCount(int playcount) { m_playcount = playcount; }
285 
286  int GetSeason() const { return m_season; }
287  void SetSeason(int season) { m_season = season; }
288 
289  int GetEpisode() const { return m_episode; }
290  void SetEpisode(int episode) { m_episode = episode; }
291 
292  QDate GetInsertdate() const { return m_insertdate;}
293  void SetInsertdate(QDate date) { m_insertdate = date;}
294 
295  ParentalLevel::Level GetShowLevel() const { return m_showlevel; }
297  {
298  m_showlevel = ParentalLevel(showLevel).GetLevel();
299  }
300 
301  bool GetBrowse() const { return m_browse; }
302  void SetBrowse(bool browse) { m_browse = browse; }
303 
304  bool GetWatched() const { return m_watched; }
305  void SetWatched(bool watched) { m_watched = watched; }
306 
307  unsigned int GetID() const { return m_id; }
308  void SetID(int id) { m_id = id; }
309 
310  float GetUserRating() const { return m_userrating; }
311  void SetUserRating(float userRating) { m_userrating = userRating; }
312 
313  bool GetProcessed() const { return m_processed; }
314  void SetProcessed(bool processed) { m_processed = processed; }
315 
316  VideoContentType GetContentType() const { return m_contenttype; }
317  void SetContentType(VideoContentType contenttype) { m_contenttype = contenttype; }
318 
320 
321  void SaveToDatabase();
322  void UpdateDatabase();
323  bool DeleteFromDatabase();
324 
325  bool DeleteFile();
326 
327  void Reset();
328 
329  bool IsHostSet() const;
330 
331  void GetImageMap(InfoMap &imageMap) const;
332 
333  private:
334  void fillCountries();
335  void updateCountries();
336  void fillGenres();
337  void fillCast();
338  void updateGenres();
339  void updateCast();
340  bool removeDir(const QString &dirName);
341  void fromDBRow(MSqlQuery &query);
342  void saveToDatabase();
343 
344  private:
345  QString m_title;
346  QString m_sortTitle;
347  QString m_subtitle;
348  QString m_sortSubtitle;
349  QString m_tagline;
350  QString m_inetref;
351  int m_collectionref {0};
352  QString m_homepage;
353  QString m_director;
354  QString m_studio;
355  QString m_plot;
356  QString m_rating;
357  QString m_playcommand;
358  QString m_category;
362  QString m_filename;
363  QString m_sortFilename;
364  QString m_hash;
365  QString m_trailer;
366  QString m_coverfile;
367  QString m_screenshot;
368  QString m_banner;
369  QString m_fanart;
370  QString m_host;
371 
372  int m_categoryID {0};
373  int m_childID {-1};
374  int m_year {VIDEO_YEAR_DEFAULT};
376  int m_length {0};
377  int m_playcount {0};
378  int m_season {0};
379  int m_episode {0};
382  bool m_browse {true};
383  bool m_watched {false};
384  unsigned int m_id {0}; // videometadata.intid
385  float m_userrating {0.0};
386  bool m_processed {false};
388 
389  // not in DB
390  QString m_prefix;
391 };
392 
396 
400 {
401  int ret = naturalCompare(m_sortTitle, rhs->m_sortTitle);
402  if (ret != 0)
403  return (ret == -1);
404  ret = naturalCompare(m_sortFilename, rhs->m_sortFilename);
405  if (ret != 0)
406  return (ret == -1);
407  return (m_id < rhs->m_id);
408 }
409 
410 bool VideoMetadataImp::removeDir(const QString &dirName)
411 {
412  QDir d(dirName);
413 
414  d.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
415  QFileInfoList contents = d.entryInfoList();
416  if (contents.empty())
417  {
418  return d.rmdir(dirName);
419  }
420 
421  for (const auto& entry : qAsConst(contents))
422  {
423  if (entry.isDir())
424  {
425  QString fileName = entry.fileName();
426  if (!removeDir(fileName))
427  return false;
428  }
429  else
430  {
431  if (!QFile(entry.fileName()).remove())
432  return false;
433  }
434  }
435  return d.rmdir(dirName);
436 }
437 
440 {
441  bool isremoved = false;
442 
443  if (!m_host.isEmpty())
444  {
445  QString url = generate_file_url("Videos", m_host, m_filename);
446  isremoved = RemoteFile::DeleteFile(url);
447  }
448  else
449  {
450  QFileInfo fi(m_filename);
451  if (fi.isDir())
452  {
453  isremoved = removeDir(m_filename);
454  }
455  else
456  {
457  isremoved = QFile::remove(m_filename);
458  }
459  }
460 
461  if (!isremoved)
462  {
463  LOG(VB_GENERAL, LOG_DEBUG, QString("Could not delete file: %1")
464  .arg(m_filename));
465  }
466 
467  return isremoved;
468 }
469 
471 {
472  VideoMetadataImp tmp(m_filename, QString(),
475  VIDEO_FANART_DEFAULT, QString(), QString(), QString(), QString(),
476  QString(), VIDEO_YEAR_DEFAULT,
477  QDate(), VIDEO_INETREF_DEFAULT, -1, QString(), VIDEO_DIRECTOR_DEFAULT,
478  QString(), VIDEO_PLOT_DEFAULT, 0.0,
479  VIDEO_RATING_DEFAULT, 0, 0,
480  0, 0, QDate(), m_id,
481  ParentalLevel::plLowest, 0, -1, true, false, "", "",
483  VideoMetadata::cast_list(), m_host, false);
484  tmp.m_prefix = m_prefix;
485 
486  *this = tmp;
487 }
488 
490 {
491  return !m_host.isEmpty();
492 }
493 
495 {
496  m_genres.clear();
499  if (vgm.get(m_id, genres))
500  {
502  for (long value : genres.values)
503  {
504  // Just add empty string for no-name genres
505  QString name;
506  vg.get(value, name);
507  m_genres.push_back(genre_list::value_type(value, name));
508  }
509  }
510 }
511 
513 {
514  m_countries.clear();
517  if (vcm.get(m_id, countries))
518  {
520  for (long value : countries.values)
521  {
522  // Just add empty string for no-name countries
523  QString name;
524  vc.get(value, name);
525  m_countries.push_back(country_list::value_type(value, name));
526  }
527  }
528 }
529 
531 {
532  m_cast.clear();
534  VideoCastMap::entry cast;
535  if (vcm.get(m_id, cast))
536  {
538  for (long value : cast.values)
539  {
540  // Just add empty string for no-name cast
541  QString name;
542  vc.get(value, name);
543  m_cast.push_back(cast_list::value_type(value, 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 
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 
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  auto 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  auto 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  auto 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 {
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 
1660 {
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 {
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 {
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:783
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:418
QString GetDisplayRating(const QString &rating)
Definition: videoutils.cpp:209
VideoContentType m_contenttype
void GetStateMap(InfoMap &stateMap) const
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle="")
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
float GetUserRating() const
void SetCollectionRef(int collectionref)
int GetLength() const
VideoContentType GetContentType() const
const QString & GetSortFilename() const
QString GetDisplayUserRating(float userrating)
Definition: videoutils.cpp:149
bool GetWatched() const
VideoMetadata & operator=(const VideoMetadata &rhs)
void SetID(int id)
const QString & getPlayCommand() const
static VideoCastMap & getCastMap()
Definition: dbaccess.cpp:573
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:219
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:223
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
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
std::vector< country_entry > country_list
Definition: videometadata.h:33
void SetTrailer(const QString &trailer)
class VideoMetadataImp * m_imp
int add(int id, int value)
Definition: dbaccess.cpp:445
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:30
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:216
void SetShowLevel(ParentalLevel::Level showLevel)
void Reset()
Resets to default metadata.
VideoMetadataImp(QString filename, QString sortFilename, QString hash, QString trailer, QString coverfile, QString screenshot, QString banner, QString fanart, const QString &title, QString sortTitle, const QString &subtitle, QString sortSubtitle, QString tagline, int year, const QDate &releasedate, QString inetref, int collectionref, QString homepage, QString director, QString studio, QString plot, float userrating, 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, QString playcommand, QString category, genre_list genres, country_list countries, cast_list cast, QString host="", bool processed=false, VideoContentType contenttype=kContentUnknown)
bool DeleteFromDatabase()
void GetImageMap(InfoMap &imageMap)
VideoMetadata::country_list country_list
MPUBLIC QString format_season_and_episode(int seasEp, int digits)
const QString & GetHash() const
bool IsHostSet() const
bool IsHostSet() const
std::vector< cast_entry > cast_list
Definition: videometadata.h:34
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:214
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:487
bool IsDefaultCoverFile(const QString &coverfile)
Definition: videoutils.cpp:125
ParentalLevel::Level GetShowLevel() const
bool operator!=(const VideoMetadata &a, const VideoMetadata &b)
VideoMetadataImp & operator=(const VideoMetadataImp &rhs)
static guint32 * tmp
Definition: goom_core.cpp:30
QStringList GetDisplayCast(const VideoMetadata &item)
Definition: videoutils.cpp:230
void SetGenres(const genre_list &genres)
unsigned int m_id
void SetInsertdate(QDate date)
void SetPlayCommand(const QString &playCommand)
void SetStudio(const QString &studio)
void SetFilename(const QString &filename, const QString &sortFilename="")
unsigned int GetID() const
void SetYear(int year)
static VideoCountryMap & getCountryMap()
Definition: dbaccess.cpp:558
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
bool GetWatched() const
const QString & GetFanart() const
const QString & GetHomepage() const
void SetStudio(const QString &studio)
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:501
const QString & GetTagline() const
void SetScreenshot(const QString &screenshot)
QDate GetInsertdate() const
QString TrailerToState(const QString &trailerFile)
Definition: videoutils.cpp:261
const QString VIDEO_PLOT_DEFAULT
Definition: globals.cpp:32
def rating(profile, smoonURL, gate)
Definition: scan.py:39
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:44
float GetUserRating() const
void SetCountries(const country_list &countries)
const QString & GetPlot() const
MSqlQuery query(MSqlQuery::InitCon())
QDate getReleaseDate() const
VideoMetadataImp(const VideoMetadataImp &other)
void SetSeason(int season)
const QString & getSubtitle() const
QString GetDisplayWatched(bool watched)
Definition: videoutils.cpp:174
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
Default local time.
Definition: mythdate.h:16
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
void toMap(InfoMap &metadataMap)
bool GetProcessed() const
bool operator==(const VideoMetadata &a, const VideoMetadata &b)
const QString & GetRating() const
Add year to string if not included.
Definition: mythdate.h:22
std::vector< genre_entry > genre_list
Definition: videometadata.h:32
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=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
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:529
int GetCollectionRef() const
const QString & GetHost() const
QString GetDisplayYear(int year)
Definition: videoutils.cpp:204
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:455
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:281
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:808
const country_list & GetCountries() const
bool removeDir(const QString &dirName)
const QString & GetFilename() const
void SetScreenshot(const QString &screenshot)
QString WatchedToState(bool watched)
Definition: videoutils.cpp:271
const QString VIDEO_DIRECTOR_UNKNOWN
Definition: globals.cpp:9
void SetWatched(bool watched)
static VideoGenreMap & getGenreMap()
Definition: dbaccess.cpp:543
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:154
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:515
const cast_list & GetCast() const
void SetShowLevel(ParentalLevel::Level showLevel)
int GetSeason() const
VideoMetadata::cast_list cast_list
void SetYear(int year)
const QString & GetBanner() const
QString ContentTypeToString(VideoContentType type)
Definition: videoutils.cpp:299
void SetCoverFile(const QString &coverFile)
const QString VIDEO_COVERFILE_DEFAULT
Definition: globals.cpp:25
VideoMetadataPtr byID(unsigned int db_id) const
bool GetBrowse() const
VideoMetadata::genre_list genre_list
void SetLength(int length)
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:73
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
QString GetDisplayProcessed(bool processed)
Definition: videoutils.cpp:186
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:162
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:450
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)
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:237
void SetCast(const cast_list &cast)
std::shared_ptr< MythSortHelper > getMythSortHelper(void)
Get a pointer to the MythSortHelper singleton.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23