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.size())
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().length())
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().length())
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().length())
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  else if (position == 2)
1135  return season.trimmed();
1136  else if (position == 3)
1137  return episode.trimmed();
1138  else 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["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["genres"] = "";
1302  metadataMap["countries"] = "";
1303  metadataMap["cast"] = "";
1304  metadataMap["rating"] = "";
1305  metadataMap["length"] = "";
1306  metadataMap["playcount"] = "";
1307  metadataMap["year"] = "";
1308  metadataMap["releasedate"] = "";
1309  metadataMap["userrating"] = "";
1310  metadataMap["season"] = "";
1311  metadataMap["episode"] = "";
1312  metadataMap["s##e##"] = "";
1313  metadataMap["##x##"] = "";
1314  metadataMap["trailerstate"] = "";
1315  metadataMap["userratingstate"] = "";
1316  metadataMap["watchedstate"] = "";
1317  metadataMap["videolevel"] = "";
1318  metadataMap["insertdate"] = "";
1319  metadataMap["inetref"] = "";
1320  metadataMap["homepage"] = "";
1321  metadataMap["child_id"] = "";
1322  metadataMap["browseable"] = "";
1323  metadataMap["watched"] = "";
1324  metadataMap["category"] = "";
1325  metadataMap["processed"] = "";
1326 }
1327 
1328 const QString &VideoMetadata::GetPrefix() const
1329 {
1330  return m_imp->GetPrefix();
1331 }
1332 
1333 void VideoMetadata::SetPrefix(const QString &prefix)
1334 {
1336 }
1337 
1338 const QString &VideoMetadata::GetTitle() const
1339 {
1340  return m_imp->getTitle();
1341 }
1342 
1343 const QString &VideoMetadata::GetSortTitle() const
1344 {
1345  return m_imp->getSortTitle();
1346 }
1347 
1348 void VideoMetadata::SetTitle(const QString &title, const QString &sortTitle)
1349 {
1350  m_imp->SetTitle(title, sortTitle);
1351 }
1352 
1353 const QString &VideoMetadata::GetSubtitle() const
1354 {
1355  return m_imp->getSubtitle();
1356 }
1357 
1358 const QString &VideoMetadata::GetSortSubtitle() const
1359 {
1360  return m_imp->getSortSubtitle();
1361 }
1362 
1363 void VideoMetadata::SetSubtitle(const QString &subtitle, const QString &sortSubtitle)
1364 {
1365  m_imp->SetSubtitle(subtitle, sortSubtitle);
1366 }
1367 
1368 const QString &VideoMetadata::GetTagline() const
1369 {
1370  return m_imp->GetTagline();
1371 }
1372 
1373 void VideoMetadata::SetTagline(const QString &tagline)
1374 {
1375  m_imp->SetTagline(tagline);
1376 }
1377 
1379 {
1380  return m_imp->getYear();
1381 }
1382 
1384 {
1385  m_imp->SetYear(year);
1386 }
1387 
1389 {
1390  return m_imp->getReleaseDate();
1391 }
1392 
1393 void VideoMetadata::SetReleaseDate(QDate releasedate)
1394 {
1395  m_imp->SetReleaseDate(releasedate);
1396 }
1397 
1398 const QString &VideoMetadata::GetInetRef() const
1399 {
1400  return m_imp->GetInetRef();
1401 }
1402 
1403 void VideoMetadata::SetInetRef(const QString &inetRef)
1404 {
1405  m_imp->SetInetRef(inetRef);
1406 }
1407 
1409 {
1410  return m_imp->GetCollectionRef();
1411 }
1412 
1413 void VideoMetadata::SetCollectionRef(int collectionref)
1414 {
1415  m_imp->SetCollectionRef(collectionref);
1416 }
1417 
1418 const QString &VideoMetadata::GetHomepage() const
1419 {
1420  return m_imp->GetHomepage();
1421 }
1422 
1423 void VideoMetadata::SetHomepage(const QString &homepage)
1424 {
1425  m_imp->SetHomepage(homepage);
1426 }
1427 
1428 const QString &VideoMetadata::GetDirector() const
1429 {
1430  return m_imp->getDirector();
1431 }
1432 
1433 void VideoMetadata::SetDirector(const QString &director)
1434 {
1435  m_imp->SetDirector(director);
1436 }
1437 
1438 const QString &VideoMetadata::GetStudio() const
1439 {
1440  return m_imp->getStudio();
1441 }
1442 
1443 void VideoMetadata::SetStudio(const QString &studio)
1444 {
1445  m_imp->SetStudio(studio);
1446 }
1447 
1448 const QString &VideoMetadata::GetPlot() const
1449 {
1450  return m_imp->getPlot();
1451 }
1452 
1453 void VideoMetadata::SetPlot(const QString &plot)
1454 {
1455  m_imp->SetPlot(plot);
1456 }
1457 
1459 {
1460  return m_imp->GetUserRating();
1461 }
1462 
1463 void VideoMetadata::SetUserRating(float userRating)
1464 {
1465  m_imp->SetUserRating(userRating);
1466 }
1467 
1468 const QString &VideoMetadata::GetRating() const
1469 {
1470  return m_imp->GetRating();
1471 }
1472 
1473 void VideoMetadata::SetRating(const QString &rating)
1474 {
1476 }
1477 
1479 {
1480  return m_imp->GetLength();
1481 }
1482 
1484 {
1485  m_imp->SetLength(length);
1486 }
1487 
1488 unsigned int VideoMetadata::GetPlayCount() const
1489 {
1490  return m_imp->GetPlayCount();
1491 }
1492 
1494 {
1495  m_imp->SetPlayCount(count);
1496 }
1497 
1499 {
1500  return m_imp->GetSeason();
1501 }
1502 
1504 {
1505  m_imp->SetSeason(season);
1506 }
1507 
1509 {
1510  return m_imp->GetEpisode();
1511 }
1512 
1513 void VideoMetadata::SetEpisode(int episode)
1514 {
1515  m_imp->SetEpisode(episode);
1516 }
1517 
1519 {
1520  return m_imp->GetInsertdate();
1521 }
1522 
1524 {
1525  m_imp->SetInsertdate(date);
1526 }
1527 
1528 unsigned int VideoMetadata::GetID() const
1529 {
1530  return m_imp->GetID();
1531 }
1532 
1534 {
1535  m_imp->SetID(id);
1536 }
1537 
1539 {
1540  return m_imp->GetChildID();
1541 }
1542 
1543 void VideoMetadata::SetChildID(int childID)
1544 {
1545  m_imp->SetChildID(childID);
1546 }
1547 
1549 {
1550  return m_imp->GetBrowse();
1551 }
1552 
1553 void VideoMetadata::SetBrowse(bool browse)
1554 {
1555  m_imp->SetBrowse(browse);
1556 }
1557 
1559 {
1560  return m_imp->GetWatched();
1561 }
1562 
1563 void VideoMetadata::SetWatched(bool watched)
1564 {
1565  m_imp->SetWatched(watched);
1566 }
1567 
1569 {
1570  return m_imp->GetProcessed();
1571 }
1572 
1573 void VideoMetadata::SetProcessed(bool processed)
1574 {
1575  m_imp->SetProcessed(processed);
1576 }
1577 
1579 {
1580  return m_imp->GetContentType();
1581 }
1582 
1584 {
1585  m_imp->SetContentType(contenttype);
1586 }
1587 
1588 const QString &VideoMetadata::GetPlayCommand() const
1589 {
1590  return m_imp->getPlayCommand();
1591 }
1592 
1593 void VideoMetadata::SetPlayCommand(const QString &playCommand)
1594 {
1595  m_imp->SetPlayCommand(playCommand);
1596 }
1597 
1599 {
1600  return m_imp->GetShowLevel();
1601 }
1602 
1604 {
1605  m_imp->SetShowLevel(showLevel);
1606 }
1607 
1608 const QString &VideoMetadata::GetFilename() const
1609 {
1610  return m_imp->getFilename();
1611 }
1612 
1613 const QString &VideoMetadata::GetSortFilename() const
1614 {
1615  return m_imp->getSortFilename();
1616 }
1617 
1618 const QString &VideoMetadata::GetHash() const
1619 {
1620  return m_imp->GetHash();
1621 }
1622 
1623 void VideoMetadata::SetHash(const QString &hash)
1624 {
1625  return m_imp->SetHash(hash);
1626 }
1627 
1628 const QString &VideoMetadata::GetHost() const
1629 {
1630  return m_imp->GetHost();
1631 }
1632 
1633 void VideoMetadata::SetHost(const QString &host)
1634 {
1635  m_imp->SetHost(host);
1636 }
1637 
1638 void VideoMetadata::SetFilename(const QString &filename, const QString &sortFilename)
1639 {
1640  m_imp->SetFilename(filename, sortFilename);
1641 }
1642 
1643 const QString &VideoMetadata::GetTrailer() const
1644 {
1645  return m_imp->GetTrailer();
1646 }
1647 
1648 void VideoMetadata::SetTrailer(const QString &trailer)
1649 {
1650  m_imp->SetTrailer(trailer);
1651 }
1652 
1653 const QString &VideoMetadata::GetCoverFile() const
1654 {
1655  return m_imp->GetCoverFile();
1656 }
1657 
1658 void VideoMetadata::SetCoverFile(const QString &coverFile)
1659 {
1660  m_imp->SetCoverFile(coverFile);
1661 }
1662 
1663 const QString &VideoMetadata::GetScreenshot() const
1664 {
1665  return m_imp->GetScreenshot();
1666 }
1667 
1668 void VideoMetadata::SetScreenshot(const QString &screenshot)
1669 {
1670  m_imp->SetScreenshot(screenshot);
1671 }
1672 
1673 const QString &VideoMetadata::GetBanner() const
1674 {
1675  return m_imp->GetBanner();
1676 }
1677 
1678 void VideoMetadata::SetBanner(const QString &banner)
1679 {
1680  m_imp->SetBanner(banner);
1681 }
1682 
1683 const QString &VideoMetadata::GetFanart() const
1684 {
1685  return m_imp->GetFanart();
1686 }
1687 
1688 void VideoMetadata::SetFanart(const QString &fanart)
1689 {
1690  m_imp->SetFanart(fanart);
1691 }
1692 
1693 const QString &VideoMetadata::GetCategory() const
1694 {
1695  return m_imp->GetCategory();
1696 }
1697 
1698 //void VideoMetadata::SetCategory(const QString &category)
1699 //{
1700 // m_imp->SetCategory(category);
1701 //}
1702 
1704 {
1705  return m_imp->getGenres();
1706 }
1707 
1709 {
1710  m_imp->SetGenres(genres);
1711 }
1712 
1714 {
1715  return m_imp->GetCast();
1716 }
1717 
1719 {
1720  m_imp->SetCast(cast);
1721 }
1722 
1724 {
1725  return m_imp->GetCountries();
1726 }
1727 
1729 {
1730  m_imp->SetCountries(countries);
1731 }
1732 
1734 {
1735  return m_imp->GetCategoryID();
1736 }
1737 
1739 {
1740  m_imp->SetCategoryID(id);
1741 }
1742 
1744 {
1745  m_imp->SaveToDatabase();
1746 }
1747 
1749 {
1750  m_imp->UpdateDatabase();
1751 }
1752 
1754 {
1755  return m_imp->DeleteFromDatabase();
1756 }
1757 
1758 #if 0
1759 bool VideoMetadata::fillDataFromID(const VideoMetadataListManager &cache)
1760 {
1761  if (m_imp->getID() == 0)
1762  return false;
1763 
1765  if (mp.get())
1766  {
1767  *this = *mp;
1768  return true;
1769  }
1770 
1771  return false;
1772 }
1773 #endif
1774 
1776 {
1777  if (m_imp->getFilename().isEmpty())
1778  return false;
1779 
1781  cache.byFilename(m_imp->getFilename());
1782  if (mp)
1783  {
1784  *this = *mp;
1785  return true;
1786  }
1787 
1788  return false;
1789 }
1790 
1792 {
1793  return m_imp->DeleteFile();
1794 }
1795 
1797 {
1798  m_imp->Reset();
1799 }
1800 
1802 {
1803  return m_imp->IsHostSet();
1804 }
1805 
1807 {
1808  return m_imp->sortBefore(rhs.m_imp);
1809 }
1810 
1811 bool operator==(const VideoMetadata& a, const VideoMetadata& b)
1812 {
1813  if (a.GetFilename() == b.GetFilename())
1814  return true;
1815  return false;
1816 }
1817 
1818 bool operator!=(const VideoMetadata& a, const VideoMetadata& b)
1819 {
1820  if (a.GetFilename() != b.GetFilename())
1821  return true;
1822  return false;
1823 }
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:794
std::vector< cast_entry > cast_list
Definition: videometadata.h:34
static bool DeleteFile(const QString &url)
Definition: remotefile.cpp:425
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)
Definition: mythdbcon.cpp:875
float GetUserRating() const
void SetCollectionRef(int collectionref)
QString FileHash(QString filename)
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:586
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)
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:458
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:221
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:500
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:571
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:340
const QString & GetHomepage() const
void SetStudio(const QString &studio)
VideoMetadata::genre_list genre_list
QVariant value(int i) const
Definition: mythdbcon.h:182
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:514
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)
bool get(int id, QString &value)
Definition: dbaccess.cpp:226
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:188
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:547
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:339
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:542
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:468
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:468
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:819
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:556
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:528
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:615
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:463
const QString VIDEO_DIRECTOR_DEFAULT
Definition: globals.cpp:23
void SetContentType(VideoContentType contenttype)
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:560
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.