MythTV  master
videodlg.cpp
Go to the documentation of this file.
1 #include <set>
2 #include <map>
3 #include <functional> //not2
4 #include <memory>
5 
6 #include <QApplication>
7 #include <QTimer>
8 #include <QList>
9 #include <QFile>
10 #include <QFileInfo>
11 #include <QDir>
12 #include <QUrl>
13 
14 #include "mythcontext.h"
15 #include "compat.h"
16 #include "mythdirs.h"
17 
18 #include "mythuihelper.h"
19 #include "mythprogressdialog.h"
20 #include "mythuitext.h"
21 #include "mythuibutton.h"
22 #include "mythuibuttonlist.h"
23 #include "mythuibuttontree.h"
24 #include "mythuiimage.h"
25 #include "mythuistatetype.h"
26 #include "mythuimetadataresults.h"
27 #include "mythdialogbox.h"
28 #include "mythgenerictree.h"
29 #include "mythsystemlegacy.h"
30 #include "remotefile.h"
31 #include "remoteutil.h"
32 #include "storagegroup.h"
33 
34 #include "videoscan.h"
35 #include "globals.h"
37 #include "parentalcontrols.h"
38 #include "videoutils.h"
39 #include "dbaccess.h"
40 #include "dirscan.h"
41 #include "metadatafactory.h"
42 #include "videofilter.h"
43 #include "editvideometadata.h"
44 #include "videopopups.h"
45 #include "videolist.h"
46 #include "videoplayercommand.h"
47 #include "videodlg.h"
48 #include "videofileassoc.h"
49 #include "videoplayersettings.h"
50 #include "videometadatasettings.h"
51 // for ImageDLFailureEvent
52 #include "metadataimagedownload.h"
53 
54 static const QString _Location = "MythVideo";
55 
56 namespace
57 {
58  bool IsValidDialogType(int num)
59  {
60  for (int i = 1; i <= VideoDialog::dtLast - 1; i <<= 1)
61  if (num == i) return true;
62  return false;
63  }
64 
65  class ParentalLevelNotifyContainer : public QObject
66  {
67  Q_OBJECT
68 
69  signals:
70  void SigLevelChanged();
71 
72  public:
73  explicit ParentalLevelNotifyContainer(QObject *lparent = nullptr) :
74  QObject(lparent)
75  {
76  connect(&m_levelCheck,
77  SIGNAL(SigResultReady(bool, ParentalLevel::Level)),
78  SLOT(OnResultReady(bool, ParentalLevel::Level)));
79  }
80 
81  const ParentalLevel &GetLevel() const { return m_level; }
82 
83  void SetLevel(const ParentalLevel& level)
84  {
85  m_levelCheck.Check(m_level.GetLevel(), level.GetLevel());
86  }
87 
88  private slots:
89  void OnResultReady(bool passwordValid, ParentalLevel::Level newLevel)
90  {
91  ParentalLevel lastLevel = m_level;
92  if (passwordValid)
93  {
94  m_level = newLevel;
95  }
96 
97  if (m_level.GetLevel() == ParentalLevel::plNone)
98  {
100  }
101 
102  if (lastLevel != m_level)
103  {
104  emit SigLevelChanged();
105  }
106  }
107 
108  private:
110  ParentalLevelChangeChecker m_levelCheck;
111  };
112 
113  MythGenericTree *GetNodePtrFromButton(MythUIButtonListItem *item)
114  {
115  if (item)
116  return item->GetData().value<MythGenericTree *>();
117 
118  return nullptr;
119  }
120 
121  VideoMetadata *GetMetadataPtrFromNode(MythGenericTree *node)
122  {
123  if (node)
124  return node->GetData().value<TreeNodeData>().GetMetadata();
125 
126  return nullptr;
127  }
128 
129  bool GetLocalVideoImage(const QString &video_uid, const QString &filename,
130  const QStringList &in_dirs, QString &image,
131  QString title, int season,
132  const QString &host, const QString& sgroup,
133  int episode = 0, bool isScreenshot = false)
134  {
135  QStringList search_dirs(in_dirs);
136  QFileInfo qfi(filename);
137  search_dirs += qfi.absolutePath();
138  if (title.contains("/"))
139  title.replace("/", "-");
140 
141  const QString base_name = qfi.completeBaseName();
142  QList<QByteArray> image_types = QImageReader::supportedImageFormats();
143 
144  typedef std::set<QString> image_type_list;
145  image_type_list image_exts;
146 
147  QString suffix;
148 
149  if (sgroup == "Coverart")
150  suffix = "coverart";
151  if (sgroup == "Fanart")
152  suffix = "fanart";
153  if (sgroup == "Screenshots")
154  suffix = "screenshot";
155  if (sgroup == "Banners")
156  suffix = "banner";
157 
158  for (QList<QByteArray>::const_iterator it = image_types.begin();
159  it != image_types.end(); ++it)
160  {
161  image_exts.insert(QString(*it).toLower());
162  }
163 
164  if (!host.isEmpty())
165  {
166  QStringList hostFiles;
167 
168  RemoteGetFileList(host, "", &hostFiles, sgroup, true);
169  const QString hntm("%2.%3");
170 
171  for (image_type_list::const_iterator ext = image_exts.begin();
172  ext != image_exts.end(); ++ext)
173  {
174  QStringList sfn;
175  if (episode > 0 || season > 0)
176  {
177  if (isScreenshot)
178  sfn += hntm.arg(QString("%1 Season %2x%3_%4")
179  .arg(title).arg(QString::number(season))
180  .arg(QString::number(episode))
181  .arg(suffix))
182  .arg(*ext);
183  else
184  sfn += hntm.arg(QString("%1 Season %2_%3")
185  .arg(title).arg(QString::number(season))
186  .arg(suffix))
187  .arg(*ext);
188 
189  }
190  else
191  {
192  sfn += hntm.arg(base_name + "_%1").arg(suffix).arg(*ext);
193  sfn += hntm.arg(video_uid + "_%1").arg(suffix).arg(*ext);
194  }
195 
196  for (QStringList::const_iterator i = sfn.begin();
197  i != sfn.end(); ++i)
198  {
199  if (hostFiles.contains(*i))
200  {
201  image = *i;
202  return true;
203  }
204  }
205  }
206  }
207 
208  const QString fntm("%1/%2.%3");
209 
210  for (QStringList::const_iterator dir = search_dirs.begin();
211  dir != search_dirs.end(); ++dir)
212  {
213  if (!(*dir).length()) continue;
214 
215  for (image_type_list::const_iterator ext = image_exts.begin();
216  ext != image_exts.end(); ++ext)
217  {
218  QStringList sfn;
219  if (season > 0 || episode > 0)
220  {
221  if (isScreenshot)
222  sfn += fntm.arg(*dir).arg(QString("%1 Season %2x%3_%4")
223  .arg(title).arg(QString::number(season))
224  .arg(QString::number(episode))
225  .arg(suffix))
226  .arg(*ext);
227  else if (!isScreenshot)
228  sfn += fntm.arg(*dir).arg(QString("%1 Season %2_%3")
229  .arg(title).arg(QString::number(season))
230  .arg(suffix))
231  .arg(*ext);
232 
233  }
234  if (!isScreenshot)
235  {
236  sfn += fntm.arg(*dir)
237  .arg(base_name + QString("_%1").arg(suffix))
238  .arg(*ext);
239  sfn += fntm.arg(*dir)
240  .arg(video_uid + QString("_%1").arg(suffix))
241  .arg(*ext);
242  }
243 
244  for (QStringList::const_iterator i = sfn.begin();
245  i != sfn.end(); ++i)
246  {
247  if (QFile::exists(*i))
248  {
249  image = *i;
250  return true;
251  }
252  }
253  }
254  }
255 
256  return false;
257  }
258 
259  void PlayVideo(const QString &filename,
260  const VideoMetadataListManager &video_list, bool useAltPlayer = false)
261  {
262  const int WATCHED_WATERMARK = 10000; // Less than this and the chain of
263  // videos will not be followed when
264  // playing.
265 
266  VideoMetadataListManager::VideoMetadataPtr item = video_list.byFilename(filename);
267 
268  if (!item) return;
269 
270  QTime playing_time;
271 
272  do
273  {
274  playing_time.start();
275 
276  if (useAltPlayer)
277  VideoPlayerCommand::AltPlayerFor(item.get()).Play();
278  else
279  VideoPlayerCommand::PlayerFor(item.get()).Play();
280 
281  if (item->GetChildID() > 0 && video_list.byID(item->GetChildID()))
282  item = video_list.byID(item->GetChildID());
283  else
284  break;
285  }
286  while (item && playing_time.elapsed() > WATCHED_WATERMARK);
287  }
288 
289  class FanartLoader: public QObject
290  {
291  Q_OBJECT
292 
293  public:
294  FanartLoader() = default;
295  ~FanartLoader() override
296  {
297  m_fanartTimer.stop();
298  m_fanartTimer.disconnect(this);
299  }
300 
301  void LoadImage(const QString &filename, MythUIImage *image)
302  {
303  if (!m_bConnected)
304  {
305  connect(&m_fanartTimer, SIGNAL(timeout()), SLOT(fanartLoad()));
306  m_bConnected = true;
307  }
308 
309  bool wasActive = m_fanartTimer.isActive();
310  if (filename.isEmpty())
311  {
312  if (wasActive)
313  m_fanartTimer.stop();
314 
315  image->Reset();
316  itemsPast++;
317  }
318  else
319  {
320  QMutexLocker locker(&m_fanartLock);
321  m_fanart = image;
322  if (filename != m_fanart->GetFilename())
323  {
324  if (wasActive)
325  m_fanartTimer.stop();
326 
327  if (itemsPast > 2)
328  m_fanart->Reset();
329 
330  m_fanart->SetFilename(filename);
331  m_fanartTimer.setSingleShot(true);
332  m_fanartTimer.start(300);
333 
334  if (wasActive)
335  itemsPast++;
336  else
337  itemsPast = 0;
338  }
339  else
340  itemsPast = 0;
341  }
342  }
343 
344  protected slots:
345  void fanartLoad(void)
346  {
347  QMutexLocker locker(&m_fanartLock);
348  m_fanart->Load();
349  }
350 
351  private:
352  int itemsPast {0};
353  QMutex m_fanartLock;
354  MythUIImage *m_fanart {nullptr};
355  QTimer m_fanartTimer;
356  bool m_bConnected {false};
357  };
358 
359  std::unique_ptr<FanartLoader> fanartLoader;
360 
361  struct CopyMetadataDestination
362  {
363  virtual void handleText(const QString &name, const QString &value) = 0;
364  virtual void handleState(const QString &name, const QString &value) = 0;
365  virtual void handleImage(const QString &name,
366  const QString &filename) = 0;
367  };
368 
369  class ScreenCopyDest : public CopyMetadataDestination
370  {
371  public:
372  explicit ScreenCopyDest(MythScreenType *screen) : m_screen(screen) {}
373 
374  void handleText(const QString &name, const QString &value) override // CopyMetadataDestination
375  {
376  CheckedSet(m_screen, name, value);
377  }
378 
379  void handleState(const QString &name, const QString &value) override // CopyMetadataDestination
380  {
381  handleText(name, value);
382  }
383 
384  void handleImage(const QString &name, const QString &filename) override // CopyMetadataDestination
385  {
386  MythUIImage *image = nullptr;
387  UIUtilW::Assign(m_screen, image, name);
388  if (image)
389  {
390  if (name != "fanart")
391  {
392  if (!filename.isEmpty())
393  {
394  image->SetFilename(filename);
395  image->Load();
396  }
397  else
398  image->Reset();
399  }
400  else
401  {
402  if (fanartLoader == nullptr)
403  fanartLoader.reset(new FanartLoader);
404  fanartLoader->LoadImage(filename, image);
405  }
406  }
407  }
408 
409  private:
410  MythScreenType *m_screen {nullptr};
411  };
412 
413  class MythUIButtonListItemCopyDest : public CopyMetadataDestination
414  {
415  public:
416  explicit MythUIButtonListItemCopyDest(MythUIButtonListItem *item) :
417  m_item(item) {}
418 
419  void handleText(const QString &name, const QString &value) override // CopyMetadataDestination
420  {
421  m_item->SetText(value, name);
422  }
423 
424  void handleState(const QString &name, const QString &value) override // CopyMetadataDestination
425  {
426  m_item->DisplayState(value, name);
427  }
428 
429  void handleImage(const QString &name, const QString &filename) override // CopyMetadataDestination
430  {
431  (void) name;
432  (void) filename;
433  }
434 
435  private:
436  MythUIButtonListItem *m_item {nullptr};
437  };
438 
439  void CopyMetadataToUI(const VideoMetadata *metadata,
440  CopyMetadataDestination &dest)
441  {
442  typedef std::map<QString, QString> valuelist;
443  valuelist tmp;
444 
445  if (metadata)
446  {
447  QString coverfile;
448  if ((metadata->IsHostSet()
449  && !metadata->GetCoverFile().startsWith("/"))
450  && !metadata->GetCoverFile().isEmpty()
451  && !IsDefaultCoverFile(metadata->GetCoverFile()))
452  {
453  coverfile = generate_file_url("Coverart", metadata->GetHost(),
454  metadata->GetCoverFile());
455  }
456  else
457  {
458  coverfile = metadata->GetCoverFile();
459  }
460 
461  if (!IsDefaultCoverFile(coverfile))
462  tmp["coverart"] = coverfile;
463 
464  tmp["coverfile"] = coverfile;
465 
466  QString screenshotfile;
467  if (metadata->IsHostSet() && !metadata->GetScreenshot().startsWith("/")
468  && !metadata->GetScreenshot().isEmpty())
469  {
470  screenshotfile = generate_file_url("Screenshots",
471  metadata->GetHost(), metadata->GetScreenshot());
472  }
473  else
474  {
475  screenshotfile = metadata->GetScreenshot();
476  }
477 
478  if (!IsDefaultScreenshot(screenshotfile))
479  tmp["screenshot"] = screenshotfile;
480 
481  tmp["screenshotfile"] = screenshotfile;
482 
483  QString bannerfile;
484  if (metadata->IsHostSet() && !metadata->GetBanner().startsWith("/")
485  && !metadata->GetBanner().isEmpty())
486  {
487  bannerfile = generate_file_url("Banners", metadata->GetHost(),
488  metadata->GetBanner());
489  }
490  else
491  {
492  bannerfile = metadata->GetBanner();
493  }
494 
495  if (!IsDefaultBanner(bannerfile))
496  tmp["banner"] = bannerfile;
497 
498  tmp["bannerfile"] = bannerfile;
499 
500  QString fanartfile;
501  if (metadata->IsHostSet() && !metadata->GetFanart().startsWith("/")
502  && !metadata->GetFanart().isEmpty())
503  {
504  fanartfile = generate_file_url("Fanart", metadata->GetHost(),
505  metadata->GetFanart());
506  }
507  else
508  {
509  fanartfile = metadata->GetFanart();
510  }
511 
512  if (!IsDefaultFanart(fanartfile))
513  tmp["fanart"] = fanartfile;
514 
515  tmp["fanartfile"] = fanartfile;
516 
517  tmp["trailerstate"] = TrailerToState(metadata->GetTrailer());
518  tmp["studiostate"] = metadata->GetStudio();
519  tmp["userratingstate"] =
520  QString::number((int)(metadata->GetUserRating()));
521  tmp["watchedstate"] = WatchedToState(metadata->GetWatched());
522 
523  tmp["videolevel"] = ParentalLevelToState(metadata->GetShowLevel());
524  }
525 
526  struct helper
527  {
528  helper(valuelist &values, CopyMetadataDestination &d) :
529  m_vallist(values), m_dest(d) {}
530 
531  void handleImage(const QString &name)
532  {
533  m_dest.handleImage(name, m_vallist[name]);
534  }
535 
536  void handleState(const QString &name)
537  {
538  m_dest.handleState(name, m_vallist[name]);
539  }
540  private:
541  valuelist &m_vallist;
542  CopyMetadataDestination &m_dest;
543  };
544 
545  helper h(tmp, dest);
546 
547  h.handleImage("coverart");
548  h.handleImage("screenshot");
549  h.handleImage("banner");
550  h.handleImage("fanart");
551 
552  h.handleState("trailerstate");
553  h.handleState("userratingstate");
554  h.handleState("watchedstate");
555  h.handleState("videolevel");
556  }
557 }
558 
560 {
561  Q_OBJECT
562 
563  public:
564  static bool Exists()
565  {
566  // TODO: Add ability to theme loader to do this a better way.
567  return LoadWindowFromXML("video-ui.xml", WINDOW_NAME, nullptr);
568  }
569 
570  public:
572  const VideoMetadataListManager &listManager) :
573  MythScreenType(lparent, WINDOW_NAME), m_metadata(metadata),
574  m_listManager(listManager)
575  {
576  }
577 
578  bool Create() override // MythScreenType
579  {
580  if (!LoadWindowFromXML("video-ui.xml", WINDOW_NAME, this))
581  return false;
582 
583  UIUtilW::Assign(this, m_playButton, "play_button");
584  UIUtilW::Assign(this, m_doneButton, "done_button");
585 
586  if (m_playButton)
587  connect(m_playButton, SIGNAL(Clicked()), SLOT(OnPlay()));
588 
589  if (m_doneButton)
590  connect(m_doneButton, SIGNAL(Clicked()), SLOT(OnDone()));
591 
592  BuildFocusList();
593 
594  if (m_playButton || m_doneButton)
596 
597  InfoMap metadataMap;
598  m_metadata->toMap(metadataMap);
599  SetTextFromMap(metadataMap);
600 
601  ScreenCopyDest dest(this);
602  CopyMetadataToUI(m_metadata, dest);
603 
604  return true;
605  }
606 
607  private slots:
608  void OnPlay()
609  {
610  PlayVideo(m_metadata->GetFilename(), m_listManager);
611  }
612 
613  void OnDone()
614  {
615  // TODO: Close() can do horrible things, this will pop
616  // our screen, delete us, and return here.
617  Close();
618  }
619 
620  private:
621  bool OnKeyAction(const QStringList &actions)
622  {
623  bool handled = false;
624  for (QStringList::const_iterator key = actions.begin();
625  key != actions.end(); ++key)
626  {
627  handled = true;
628  if (*key == "SELECT" || *key == "PLAYBACK")
629  OnPlay();
630  else
631  handled = false;
632  }
633 
634  return handled;
635  }
636 
637  protected:
638  bool keyPressEvent(QKeyEvent *levent) override // MythScreenType
639  {
640  if (MythScreenType::keyPressEvent(levent))
641  return true;
642 
643  QStringList actions;
644  bool handled = GetMythMainWindow()->TranslateKeyPress("Video",
645  levent, actions);
646  if (!handled && !OnKeyAction(actions))
647  {
648  handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend",
649  levent, actions);
650  OnKeyAction(actions);
651  }
652  return handled;
653  }
654 
655  private:
656  static const char * const WINDOW_NAME;
659 
662 };
663 
664 const char * const ItemDetailPopup::WINDOW_NAME = "itemdetailpopup";
665 
667 {
668  private:
669  typedef std::list<std::pair<QString, ParentalLevel::Level> >
671 
673  public std::binary_function<parental_level_map::value_type,
674  parental_level_map::value_type, bool>
675  {
676  bool operator()(const parental_level_map::value_type &lhs,
677  const parental_level_map::value_type &rhs) const
678  {
679  return lhs.first.length() < rhs.first.length();
680  }
681  };
682 
684 
685  public:
687  VideoDialog::BrowseType browse) :
688  m_videoList(videoList), m_type(type), m_browse(browse)
689  {
690  if (gCoreContext->GetBoolSetting("mythvideo.ParentalLevelFromRating", false))
691  {
693  sl.GetLevel() <= ParentalLevel::plHigh && sl.good(); ++sl)
694  {
695  QString ratingstring =
696  gCoreContext->GetSetting(QString("mythvideo.AutoR2PL%1")
697  .arg(sl.GetLevel()));
698  QStringList ratings =
699  ratingstring.split(':', QString::SkipEmptyParts);
700 
701  for (QStringList::const_iterator p = ratings.begin();
702  p != ratings.end(); ++p)
703  {
704  m_rating_to_pl.push_back(
705  parental_level_map::value_type(*p, sl.GetLevel()));
706  }
707  }
708  m_rating_to_pl.sort(std::not2(rating_to_pl_less()));
709  }
710 
712  gCoreContext->GetBoolSetting("mythvideo.VideoTreeRemember", false);
713 
714  m_isFileBrowser = gCoreContext->GetBoolSetting("VideoDialogNoDB", false);
715  m_groupType = gCoreContext->GetNumSetting("mythvideo.db_group_type", 0);
716 
718  gCoreContext->GetBoolSetting("mythvideo.EnableAlternatePlayer");
719 
720  m_autoMeta = gCoreContext->GetBoolSetting("mythvideo.AutoMetaDataScan", true);
721 
722  m_artDir = gCoreContext->GetSetting("VideoArtworkDir");
723  m_sshotDir = gCoreContext->GetSetting("mythvideo.screenshotDir");
724  m_fanDir = gCoreContext->GetSetting("mythvideo.fanartDir");
725  m_banDir = gCoreContext->GetSetting("mythvideo.bannerDir");
726  }
727 
729  {
730  delete m_scanner;
731 
732  if (m_rememberPosition && m_lastTreeNodePath.length())
733  {
734  gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive",
736  }
737  }
738 
740  {
741  if (metadata && !m_rating_to_pl.empty())
742  {
743  QString rating = metadata->GetRating();
744  for (parental_level_map::const_iterator p = m_rating_to_pl.begin();
745  !rating.isEmpty() && p != m_rating_to_pl.end(); ++p)
746  {
747  if (rating.indexOf(p->first) != -1)
748  {
749  metadata->SetShowLevel(p->second);
750  break;
751  }
752  }
753  }
754  }
755 
757  {
758  m_savedPtr = new VideoListDeathDelay(videoList);
759  }
760 
761  public:
762  ParentalLevelNotifyContainer m_parentalLevel;
763  bool m_switchingLayout {false};
764 
766 
767  bool m_firstLoadPass {true};
768 
769  bool m_rememberPosition {false};
770 
772 
775 
776  bool m_treeLoaded {false};
777 
778  bool m_isFileBrowser {false};
779  int m_groupType {0};
780  bool m_isFlatList {false};
781  bool m_altPlayerEnabled {false};
784 
785  bool m_autoMeta {true};
786 
787  QString m_artDir;
788  QString m_sshotDir;
789  QString m_fanDir;
790  QString m_banDir;
792 
794  QMap<QString, int> m_notifications;
795 
796  private:
798 };
799 
801 
803 {
804  public:
806  m_savedList(toSave)
807  {
808  }
809 
811  {
812  return m_savedList;
813  }
814 
815  private:
817 };
818 
820  QObject(qApp)
821 {
822  m_d = new VideoListDeathDelayPrivate(toSave);
823  QTimer::singleShot(kDelayTimeMS, this, SLOT(OnTimeUp()));
824 }
825 
827 {
828  delete m_d;
829 }
830 
832 {
833  return m_d->GetSaved();
834 }
835 
837 {
838  deleteLater();
839 }
840 
842 {
844 }
845 
846 VideoDialog::VideoDialog(MythScreenStack *lparent, const QString& lname,
847  const VideoListPtr& video_list, DialogType type, BrowseType browse)
848  : MythScreenType(lparent, lname),
849  m_popupStack(GetMythMainWindow()->GetStack("popup stack")),
850  m_mainStack(GetMythMainWindow()->GetMainStack()),
851  m_metadataFactory(new MetadataFactory(this)),
852  m_d(new VideoDialogPrivate(video_list, type, browse))
853 {
855  lname));
856 
858  GetNumSetting("VideoDefaultParentalLevel",
860 
862 }
863 
865 {
866  if (!m_d->m_switchingLayout)
868 
869  SavePosition();
870 
871  delete m_d;
872 }
873 
875 {
876  m_d->m_lastTreeNodePath = "";
877 
878  if (m_d->m_type == DLG_TREE)
879  {
881  if (node)
882  m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
883  }
884  else if (m_d->m_type == DLG_BROWSER || m_d->m_type == DLG_GALLERY)
885  {
887  if (item)
888  {
889  MythGenericTree *node = GetNodePtrFromButton(item);
890  if (node)
891  m_d->m_lastTreeNodePath = node->getRouteByString().join("\n");
892  }
893  }
894 
895  gCoreContext->SaveSetting("mythvideo.VideoTreeLastActive", m_d->m_lastTreeNodePath);
896 }
897 
899 {
900  if (m_d->m_type == DLG_DEFAULT)
901  {
902  m_d->m_type = static_cast<DialogType>(
903  gCoreContext->GetNumSetting("Default MythVideo View", DLG_GALLERY));
904  m_d->m_browse = static_cast<BrowseType>(
905  gCoreContext->GetNumSetting("mythvideo.db_group_type", BRS_FOLDER));
906  }
907 
908  if (!IsValidDialogType(m_d->m_type))
909  {
911  }
912 
913  QString windowName = "videogallery";
914  bool flatlistDefault = false;
915 
916  switch (m_d->m_type)
917  {
918  case DLG_BROWSER:
919  windowName = "browser";
920  flatlistDefault = true;
921  break;
922  case DLG_GALLERY:
923  windowName = "gallery";
924  break;
925  case DLG_TREE:
926  windowName = "tree";
927  break;
928  case DLG_MANAGER:
929  m_d->m_isFlatList =
930  gCoreContext->GetBoolSetting("mythvideo.db_folder_view", true);
931  windowName = "manager";
932  flatlistDefault = true;
933  break;
934  case DLG_DEFAULT:
935  default:
936  break;
937  }
938 
939  switch (m_d->m_browse)
940  {
941  case BRS_GENRE:
943  break;
944  case BRS_CATEGORY:
946  break;
947  case BRS_YEAR:
949  break;
950  case BRS_DIRECTOR:
952  break;
953  case BRS_STUDIO:
955  break;
956  case BRS_CAST:
958  break;
959  case BRS_USERRATING:
961  break;
962  case BRS_INSERTDATE:
964  break;
965  case BRS_TVMOVIE:
967  break;
968  case BRS_FOLDER:
969  default:
971  break;
972  }
973 
974  m_d->m_isFlatList =
975  gCoreContext->GetBoolSetting(QString("mythvideo.folder_view_%1")
976  .arg(m_d->m_type), flatlistDefault);
977 
978  if (!LoadWindowFromXML("video-ui.xml", windowName, this))
979  return false;
980 
981  bool err = false;
982  if (m_d->m_type == DLG_TREE)
983  UIUtilE::Assign(this, m_videoButtonTree, "videos", &err);
984  else
985  UIUtilE::Assign(this, m_videoButtonList, "videos", &err);
986 
987  UIUtilW::Assign(this, m_titleText, "title");
988  UIUtilW::Assign(this, m_novideoText, "novideos");
989  UIUtilW::Assign(this, m_positionText, "position");
990  UIUtilW::Assign(this, m_crumbText, "breadcrumbs");
991 
992  UIUtilW::Assign(this, m_coverImage, "coverart");
993  UIUtilW::Assign(this, m_screenshot, "screenshot");
994  UIUtilW::Assign(this, m_banner, "banner");
995  UIUtilW::Assign(this, m_fanart, "fanart");
996 
997  UIUtilW::Assign(this, m_trailerState, "trailerstate");
998  UIUtilW::Assign(this, m_parentalLevelState, "parentallevel");
999  UIUtilW::Assign(this, m_watchedState, "watchedstate");
1000  UIUtilW::Assign(this, m_studioState, "studiostate");
1001 
1002  if (err)
1003  {
1004  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen '" + windowName + "'");
1005  return false;
1006  }
1007 
1008  CheckedSet(m_trailerState, "None");
1010  CheckedSet(m_watchedState, "None");
1011  CheckedSet(m_studioState, "None");
1012 
1013  BuildFocusList();
1014 
1015  if (m_d->m_type == DLG_TREE)
1016  {
1018 
1019  connect(m_videoButtonTree, SIGNAL(itemClicked(MythUIButtonListItem *)),
1021  connect(m_videoButtonTree, SIGNAL(itemSelected(MythUIButtonListItem *)),
1022  SLOT(UpdateText(MythUIButtonListItem *)));
1023  connect(m_videoButtonTree, SIGNAL(nodeChanged(MythGenericTree *)),
1024  SLOT(SetCurrentNode(MythGenericTree *)));
1025  }
1026  else
1027  {
1029 
1030  connect(m_videoButtonList, SIGNAL(itemClicked(MythUIButtonListItem *)),
1032  connect(m_videoButtonList, SIGNAL(itemSelected(MythUIButtonListItem *)),
1033  SLOT(UpdateText(MythUIButtonListItem *)));
1034  }
1035 
1036  return true;
1037 }
1038 
1040 {
1041  connect(&m_d->m_parentalLevel, SIGNAL(SigLevelChanged()),
1042  SLOT(reloadData()));
1043 }
1044 
1046 {
1047  reloadData();
1048  // We only want to prompt once, on startup, hence this is done in Load()
1049  if (m_d->m_rootNode->childCount() == 1 &&
1051  PromptToScan();
1052 }
1053 
1059 {
1060  fetchVideos();
1061  loadData();
1062 
1065 
1066  bool noFiles = (m_d->m_rootNode->childCount() == 1 &&
1068 
1069  if (m_novideoText)
1070  m_novideoText->SetVisible(noFiles);
1071 }
1072 
1073 void VideoDialog::scanFinished(bool dbChanged)
1074 {
1075  delete m_d->m_scanner;
1076  m_d->m_scanner = nullptr;
1077 
1078  if (dbChanged)
1080 
1081  m_d->m_currentNode = nullptr;
1082  reloadData();
1083 
1084  if (m_d->m_autoMeta)
1085  VideoAutoSearch();
1086 
1087  if (m_d->m_rootNode->childCount() == 1 &&
1089  {
1090  QString message = tr("The video scan found no files, have you "
1091  "configured a video storage group?");
1092  ShowOkPopup(message);
1093  }
1094 }
1095 
1101 {
1102  m_d->m_treeLoaded = false;
1103  refreshData();
1104 }
1105 
1111 {
1112  if (m_d->m_type == DLG_TREE)
1113  {
1115 
1116  if (m_d->m_firstLoadPass)
1117  {
1118  m_d->m_firstLoadPass = false;
1119 
1120  if (m_d->m_rememberPosition)
1121  {
1122  QStringList route =
1123  gCoreContext->GetSetting("mythvideo.VideoTreeLastActive",
1124  "").split("\n");
1126  }
1127  }
1128  }
1129  else
1130  {
1132 
1133  if (!m_d->m_treeLoaded)
1134  return;
1135 
1136  if (!m_d->m_currentNode)
1138 
1139  if (!m_d->m_currentNode)
1140  return;
1141 
1142  MythGenericTree *selectedNode = m_d->m_currentNode->getSelectedChild();
1143 
1144  // restore the last saved position in the video tree if this is the first
1145  // time this method is called and the option is set in the database
1146  if (m_d->m_firstLoadPass)
1147  {
1148  if (m_d->m_rememberPosition)
1149  {
1150  QStringList lastTreeNodePath = gCoreContext->GetSetting("mythvideo.VideoTreeLastActive", "").split("\n");
1151 
1152  if (m_d->m_type == DLG_GALLERY || m_d->m_type == DLG_BROWSER)
1153  {
1154  if (!lastTreeNodePath.isEmpty())
1155  {
1156  MythGenericTree *node;
1157 
1158  // go through the path list and set the current node
1159  for (int i = 0; i < lastTreeNodePath.size(); i++)
1160  {
1161  node = m_d->m_currentNode->getChildByName(lastTreeNodePath.at(i));
1162  if (node != nullptr)
1163  {
1164  // check if the node name is the same as the currently selected
1165  // one in the saved tree list. if yes then we are on the right
1166  // way down the video tree to find the last saved position
1167  if (node->GetText().compare(lastTreeNodePath.at(i)) == 0)
1168  {
1169  // set the folder as the new node so we can travel further down
1170  // dont do this if its the last part of the saved video path tree
1171  if (node->getInt() == kSubFolder &&
1172  node->childCount() > 1 &&
1173  i < lastTreeNodePath.size()-1)
1174  {
1175  SetCurrentNode(node);
1176  }
1177  // in the last run the selectedNode will be the last
1178  // entry of the saved tree node.
1179  if (lastTreeNodePath.at(i) == lastTreeNodePath.last())
1180  selectedNode = node;
1181  }
1182  }
1183  }
1184  m_d->m_firstLoadPass = false;
1185  }
1186  }
1187  }
1188  }
1189 
1190  typedef QList<MythGenericTree *> MGTreeChildList;
1191  MGTreeChildList *lchildren = m_d->m_currentNode->getAllChildren();
1192 
1193  for (MGTreeChildList::const_iterator p = lchildren->begin();
1194  p != lchildren->end(); ++p)
1195  {
1196  if (*p != nullptr)
1197  {
1198  MythUIButtonListItem *item =
1199  new MythUIButtonListItem(m_videoButtonList, QString(), nullptr,
1201 
1202  item->SetData(qVariantFromValue(*p));
1203 
1204  UpdateItem(item);
1205 
1206  if (*p == selectedNode)
1208  }
1209  }
1210  }
1211 
1212  UpdatePosition();
1213 }
1214 
1220 {
1221  if (!item)
1222  return;
1223 
1224  MythGenericTree *node = GetNodePtrFromButton(item);
1225 
1226  VideoMetadata *metadata = GetMetadata(item);
1227 
1228  if (metadata)
1229  {
1230  InfoMap metadataMap;
1231  metadata->toMap(metadataMap);
1232  item->SetTextFromMap(metadataMap);
1233  }
1234 
1235  MythUIButtonListItemCopyDest dest(item);
1236  CopyMetadataToUI(metadata, dest);
1237 
1238  MythGenericTree *parent = node->getParent();
1239 
1240  if (parent && metadata && ((QString::compare(parent->GetText(),
1241  metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
1242  parent->GetText().startsWith(tr("Season"), Qt::CaseInsensitive)))
1243  item->SetText(metadata->GetSubtitle());
1244  else if (metadata && !metadata->GetSubtitle().isEmpty())
1245  item->SetText(QString("%1: %2").arg(metadata->GetTitle()).arg(metadata->GetSubtitle()));
1246  else
1247  item->SetText(metadata ? metadata->GetTitle() : node->GetText());
1248 
1249  QString coverimage = GetCoverImage(node);
1250  QString screenshot = GetScreenshot(node);
1251  QString banner = GetBanner(node);
1252  QString fanart = GetFanart(node);
1253 
1254  if (!screenshot.isEmpty() && parent && metadata &&
1255  ((QString::compare(parent->GetText(),
1256  metadata->GetTitle(), Qt::CaseInsensitive) == 0) ||
1257  parent->GetText().startsWith(tr("Season"), Qt::CaseInsensitive)))
1258  {
1259  item->SetImage(screenshot);
1260  }
1261  else
1262  {
1263  if (coverimage.isEmpty())
1264  coverimage = GetFirstImage(node, "Coverart");
1265  item->SetImage(coverimage);
1266  }
1267 
1268  int nodeInt = node->getInt();
1269 
1270  if (coverimage.isEmpty() && nodeInt == kSubFolder)
1271  coverimage = GetFirstImage(node, "Coverart");
1272 
1273  item->SetImage(coverimage, "coverart");
1274 
1275  if (screenshot.isEmpty() && nodeInt == kSubFolder)
1276  screenshot = GetFirstImage(node, "Screenshots");
1277 
1278  item->SetImage(screenshot, "screenshot");
1279 
1280  if (banner.isEmpty() && nodeInt == kSubFolder)
1281  banner = GetFirstImage(node, "Banners");
1282 
1283  item->SetImage(banner, "banner");
1284 
1285  if (fanart.isEmpty() && nodeInt == kSubFolder)
1286  fanart = GetFirstImage(node, "Fanart");
1287 
1288  item->SetImage(fanart, "fanart");
1289 
1290  if (nodeInt == kSubFolder)
1291  {
1292  item->SetText(QString("%1").arg(node->visibleChildCount()), "childcount");
1293  item->DisplayState("subfolder", "nodetype");
1294  item->SetText(node->GetText(), "title");
1295  item->SetText(node->GetText());
1296  }
1297  else if (nodeInt == kUpFolder)
1298  {
1299  item->DisplayState("upfolder", "nodetype");
1300  item->SetText(node->GetText(), "title");
1301  item->SetText(node->GetText());
1302  }
1303 
1304  if (item == GetItemCurrent())
1305  UpdateText(item);
1306 }
1307 
1313 {
1314  MythGenericTree *oldroot = m_d->m_rootNode;
1315  if (!m_d->m_treeLoaded)
1316  {
1319  m_d->m_parentalLevel.GetLevel(), true);
1320  }
1321  else
1322  {
1324  m_d->m_parentalLevel.GetLevel(),
1327  }
1328 
1329  m_d->m_treeLoaded = true;
1330 
1331  // Move a node down if there is a single directory item here...
1332  if (m_d->m_rootNode->childCount() == 1)
1333  {
1335  if (node->getInt() == kSubFolder && node->childCount() > 1)
1336  m_d->m_rootNode = node;
1337  else if (node->getInt() == kUpFolder)
1338  m_d->m_treeLoaded = false;
1339  }
1340  else if (m_d->m_rootNode->childCount() == 0)
1341  m_d->m_treeLoaded = false;
1342 
1343  if (!m_d->m_currentNode || m_d->m_rootNode != oldroot)
1345 }
1346 
1351 QString VideoDialog::RemoteImageCheck(const QString& host, const QString& filename)
1352 {
1353  QString result = "";
1354 #if 0
1355  LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteImageCheck(%1)").arg(filename));
1356 #endif
1357 
1358  QStringList dirs = GetVideoDirsByHost(host);
1359 
1360  if (!dirs.isEmpty())
1361  {
1362  for (QStringList::const_iterator iter = dirs.begin();
1363  iter != dirs.end(); ++iter)
1364  {
1365  QUrl sgurl = *iter;
1366  QString path = sgurl.path();
1367 
1368  QString fname = QString("%1/%2").arg(path).arg(filename);
1369 
1370  QStringList list( QString("QUERY_SG_FILEQUERY") );
1371  list << host;
1372  list << "Videos";
1373  list << fname;
1374 
1375  bool ok = gCoreContext->SendReceiveStringList(list);
1376 
1377  if (!ok || list.at(0).startsWith("SLAVE UNREACHABLE"))
1378  {
1379  LOG(VB_GENERAL, LOG_WARNING,
1380  QString("Backend : %1 currently Unreachable. Skipping "
1381  "this one.") .arg(host));
1382  break;
1383  }
1384 
1385  if ((!list.isEmpty()) && (list.at(0) == fname))
1386  result = generate_file_url("Videos", host, filename);
1387 
1388  if (!result.isEmpty())
1389  {
1390 #if 0
1391  LOG(VB_GENERAL, LOG_DEBUG,
1392  QString("RemoteImageCheck(%1) res :%2: :%3:")
1393  .arg(fname).arg(result).arg(*iter));
1394 #endif
1395  break;
1396  }
1397 
1398  }
1399  }
1400 
1401  return result;
1402 }
1403 
1409 {
1410  QString icon_file;
1411  const QString& host = metadata->GetHost();
1412  QFileInfo fullpath(metadata->GetFilename());
1413  QDir dir = fullpath.dir();
1414  QString prefix = QDir::cleanPath(dir.path());
1415 
1416  QString filename = QString("%1/folder").arg(prefix);
1417 
1418  QStringList test_files;
1419  test_files.append(filename + ".png");
1420  test_files.append(filename + ".jpg");
1421  test_files.append(filename + ".jpeg");
1422  test_files.append(filename + ".gif");
1423 
1424  for (QStringList::const_iterator tfp = test_files.begin();
1425  tfp != test_files.end(); ++tfp)
1426  {
1427  QString imagePath = *tfp;
1428  bool foundCover = false;
1429  if (!host.isEmpty())
1430  {
1431  // Strip out any extra /'s
1432  imagePath.replace("//", "/");
1433  prefix.replace("//","/");
1434  imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
1435  QString tmpCover = RemoteImageCheck(host, imagePath);
1436 
1437  if (!tmpCover.isEmpty())
1438  {
1439  foundCover = true;
1440  imagePath = tmpCover;
1441  }
1442  }
1443  else
1444  foundCover = QFile::exists(imagePath);
1445 
1446  if (foundCover)
1447  {
1448  icon_file = imagePath;
1449  return icon_file;
1450  }
1451  }
1452 
1453  // If we found nothing, load something that matches the title.
1454  // If that fails, load anything we find.
1455  if (icon_file.isEmpty())
1456  {
1457  QStringList imageTypes;
1458  imageTypes.append(metadata->GetTitle() + ".png");
1459  imageTypes.append(metadata->GetTitle() + ".jpg");
1460  imageTypes.append(metadata->GetTitle() + ".jpeg");
1461  imageTypes.append(metadata->GetTitle() + ".gif");
1462  imageTypes.append("*.png");
1463  imageTypes.append("*.jpg");
1464  imageTypes.append("*.jpeg");
1465  imageTypes.append("*.gif");
1466 
1467  QStringList fList;
1468 
1469  if (!host.isEmpty())
1470  {
1471  // TODO: This can likely get a little cleaner
1472 
1473  QStringList dirs = GetVideoDirsByHost(host);
1474 
1475  if (!dirs.isEmpty())
1476  {
1477  for (QStringList::const_iterator iter = dirs.begin();
1478  iter != dirs.end(); ++iter)
1479  {
1480  QUrl sgurl = *iter;
1481  QString path = sgurl.path();
1482 
1483  const QString& subdir = prefix;
1484 
1485  path = path + "/" + subdir;
1486  QStringList tmpList;
1487  bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
1488 
1489  if (ok)
1490  {
1491  for (QStringList::const_iterator pattern = imageTypes.begin();
1492  pattern != imageTypes.end(); ++pattern)
1493  {
1494  QRegExp rx(*pattern);
1495  rx.setPatternSyntax(QRegExp::Wildcard);
1496  rx.setCaseSensitivity(Qt::CaseInsensitive);
1497  QStringList matches = tmpList.filter(rx);
1498  if (!matches.isEmpty())
1499  {
1500  fList.clear();
1501  fList.append(subdir + "/" + matches.at(0).split("::").at(1));
1502  break;
1503  }
1504  }
1505 
1506  break;
1507  }
1508  }
1509  }
1510  }
1511  else
1512  {
1513  QDir vidDir(prefix);
1514  vidDir.setNameFilters(imageTypes);
1515  fList = vidDir.entryList();
1516  }
1517 
1518  if (!fList.isEmpty())
1519  {
1520  if (host.isEmpty())
1521  icon_file = QString("%1/%2")
1522  .arg(prefix)
1523  .arg(fList.at(0));
1524  else
1525  icon_file = generate_file_url("Videos", host, fList.at(0));
1526  }
1527  }
1528 
1529  if (!icon_file.isEmpty())
1530  LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
1531  .arg(icon_file));
1532  else
1533  LOG(VB_GENERAL, LOG_DEBUG, QString("Could not find cover Image : %1 ")
1534  .arg(prefix));
1535 
1536  if (IsDefaultCoverFile(icon_file))
1537  icon_file.clear();
1538 
1539  return icon_file;
1540 }
1541 
1547 {
1548  int nodeInt = node->getInt();
1549 
1550  QString icon_file;
1551 
1552  if (nodeInt == kSubFolder) // subdirectory
1553  {
1554  // load folder icon
1555  QString folder_path = node->GetData().value<TreeNodeData>().GetPath();
1556  QString host = node->GetData().value<TreeNodeData>().GetHost();
1557  QString prefix = node->GetData().value<TreeNodeData>().GetPrefix();
1558 
1559  if (folder_path.startsWith("myth://"))
1560  folder_path = folder_path.right(folder_path.length()
1561  - folder_path.lastIndexOf("//") - 1);
1562 
1563  QString filename = QString("%1/folder").arg(folder_path);
1564 
1565 #if 0
1566  LOG(VB_GENERAL, LOG_DEBUG,
1567  QString("GetCoverImage host : %1 prefix : %2 file : %3")
1568  .arg(host).arg(prefix).arg(filename));
1569 #endif
1570 
1571  QStringList test_files;
1572  test_files.append(filename + ".png");
1573  test_files.append(filename + ".jpg");
1574  test_files.append(filename + ".jpeg");
1575  test_files.append(filename + ".gif");
1576 
1577  for (QStringList::const_iterator tfp = test_files.begin();
1578  tfp != test_files.end(); ++tfp)
1579  {
1580  QString imagePath = *tfp;
1581 #if 0
1582  LOG(VB_GENERAL, LOG_DEBUG, QString("Cover check :%1 : ").arg(*tfp));
1583 #endif
1584 
1585  bool foundCover = false;
1586  if (!host.isEmpty())
1587  {
1588  // Strip out any extra /'s
1589  imagePath.replace("//", "/");
1590  prefix.replace("//","/");
1591  imagePath = imagePath.right(imagePath.length() - (prefix.length() + 1));
1592  QString tmpCover = RemoteImageCheck(host, imagePath);
1593 
1594  if (!tmpCover.isEmpty())
1595  {
1596  foundCover = true;
1597  imagePath = tmpCover;
1598  }
1599  }
1600  else
1601  foundCover = QFile::exists(imagePath);
1602 
1603  if (foundCover)
1604  {
1605  icon_file = imagePath;
1606  break;
1607  }
1608  }
1609 
1610  // If we found nothing, load the first image we find
1611  if (icon_file.isEmpty())
1612  {
1613  QStringList imageTypes;
1614  imageTypes.append("*.png");
1615  imageTypes.append("*.jpg");
1616  imageTypes.append("*.jpeg");
1617  imageTypes.append("*.gif");
1618 
1619  QStringList fList;
1620 
1621  if (!host.isEmpty())
1622  {
1623  // TODO: This can likely get a little cleaner
1624 
1625  QStringList dirs = GetVideoDirsByHost(host);
1626 
1627  if (!dirs.isEmpty())
1628  {
1629  for (QStringList::const_iterator iter = dirs.begin();
1630  iter != dirs.end(); ++iter)
1631  {
1632  QUrl sgurl = *iter;
1633  QString path = sgurl.path();
1634 
1635  QString subdir = folder_path.right(folder_path.length() - (prefix.length() + 1));
1636 
1637  path = path + "/" + subdir;
1638 
1639  QStringList tmpList;
1640  bool ok = RemoteGetFileList(host, path, &tmpList, "Videos");
1641 
1642  if (ok)
1643  {
1644  for (QStringList::const_iterator pattern = imageTypes.begin();
1645  pattern != imageTypes.end(); ++pattern)
1646  {
1647  QRegExp rx(*pattern);
1648  rx.setPatternSyntax(QRegExp::Wildcard);
1649  rx.setCaseSensitivity(Qt::CaseInsensitive);
1650  QStringList matches = tmpList.filter(rx);
1651  if (!matches.isEmpty())
1652  {
1653  fList.clear();
1654  fList.append(subdir + "/" + matches.at(0).split("::").at(1));
1655  break;
1656  }
1657  }
1658 
1659  break;
1660  }
1661  }
1662  }
1663 
1664  }
1665  else
1666  {
1667  QDir vidDir(folder_path);
1668  vidDir.setNameFilters(imageTypes);
1669  fList = vidDir.entryList();
1670  }
1671 
1672  // Take the Coverfile for the first valid node in the dir, if it exists.
1673  if (icon_file.isEmpty())
1674  {
1675  int list_count = node->visibleChildCount();
1676  if (list_count > 0)
1677  {
1678  for (int i = 0; i < list_count; i++)
1679  {
1680  MythGenericTree *subnode = node->getVisibleChildAt(i);
1681  if (subnode)
1682  {
1683  VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
1684  if (metadata)
1685  {
1686  if (!metadata->GetHost().isEmpty() &&
1687  !metadata->GetCoverFile().startsWith("/"))
1688  {
1689  QString test_file = generate_file_url("Coverart",
1690  metadata->GetHost(), metadata->GetCoverFile());
1691  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1692  !IsDefaultCoverFile(test_file))
1693  {
1694  icon_file = test_file;
1695  break;
1696  }
1697  }
1698  else
1699  {
1700  const QString& test_file = metadata->GetCoverFile();
1701  if (!test_file.isEmpty() &&
1702  !IsDefaultCoverFile(test_file))
1703  {
1704  icon_file = test_file;
1705  break;
1706  }
1707  }
1708  }
1709  }
1710  }
1711  }
1712  }
1713 
1714  if (!fList.isEmpty())
1715  {
1716  if (host.isEmpty())
1717  icon_file = QString("%1/%2")
1718  .arg(folder_path)
1719  .arg(fList.at(0));
1720  else
1721  icon_file = generate_file_url("Videos", host, fList.at(0));
1722  }
1723  }
1724 
1725  if (!icon_file.isEmpty())
1726  LOG(VB_GENERAL, LOG_DEBUG, QString("Found Image : %1 :")
1727  .arg(icon_file));
1728  else
1729  LOG(VB_GENERAL, LOG_DEBUG,
1730  QString("Could not find folder cover Image : %1 ")
1731  .arg(folder_path));
1732  }
1733  else
1734  {
1735  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1736 
1737  if (metadata)
1738  {
1739  if (metadata->IsHostSet() &&
1740  !metadata->GetCoverFile().startsWith("/") &&
1741  !IsDefaultCoverFile(metadata->GetCoverFile()))
1742  {
1743  icon_file = generate_file_url("Coverart", metadata->GetHost(),
1744  metadata->GetCoverFile());
1745  }
1746  else
1747  {
1748  icon_file = metadata->GetCoverFile();
1749  }
1750  }
1751  }
1752 
1753  if (IsDefaultCoverFile(icon_file))
1754  icon_file.clear();
1755 
1756  return icon_file;
1757 }
1758 
1770 QString VideoDialog::GetFirstImage(MythGenericTree *node, const QString& type,
1771  const QString& gpnode, int levels)
1772 {
1773  if (!node || type.isEmpty())
1774  return QString();
1775 
1776  QString icon_file;
1777 
1778  int list_count = node->visibleChildCount();
1779  if (list_count > 0)
1780  {
1781  QList<MythGenericTree *> subDirs;
1782  // cppcheck-suppress variableScope
1783  int maxRecurse = 1;
1784 
1785  for (int i = 0; i < list_count; i++)
1786  {
1787  MythGenericTree *subnode = node->getVisibleChildAt(i);
1788  if (subnode)
1789  {
1790  if (subnode->childCount() > 0)
1791  subDirs << subnode;
1792 
1793  VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
1794  if (metadata)
1795  {
1796  QString test_file;
1797  const QString& host = metadata->GetHost();
1798  const QString& title = metadata->GetTitle();
1799 
1800  if (type == "Coverart" && !host.isEmpty() &&
1801  !metadata->GetCoverFile().startsWith("/"))
1802  {
1803  test_file = generate_file_url("Coverart",
1804  host, metadata->GetCoverFile());
1805  }
1806  else if (type == "Coverart")
1807  test_file = metadata->GetCoverFile();
1808 
1809  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1810  !IsDefaultCoverFile(test_file) && (gpnode.isEmpty() ||
1811  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1812  {
1813  icon_file = test_file;
1814  break;
1815  }
1816 
1817  if (type == "Fanart" && !host.isEmpty() &&
1818  !metadata->GetFanart().startsWith("/"))
1819  {
1820  test_file = generate_file_url("Fanart",
1821  host, metadata->GetFanart());
1822  }
1823  else if (type == "Fanart")
1824  test_file = metadata->GetFanart();
1825 
1826  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1827  test_file != VIDEO_FANART_DEFAULT && (gpnode.isEmpty() ||
1828  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1829  {
1830  icon_file = test_file;
1831  break;
1832  }
1833 
1834  if (type == "Banners" && !host.isEmpty() &&
1835  !metadata->GetBanner().startsWith("/"))
1836  {
1837  test_file = generate_file_url("Banners",
1838  host, metadata->GetBanner());
1839  }
1840  else if (type == "Banners")
1841  test_file = metadata->GetBanner();
1842 
1843  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1844  test_file != VIDEO_BANNER_DEFAULT && (gpnode.isEmpty() ||
1845  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1846  {
1847  icon_file = test_file;
1848  break;
1849  }
1850 
1851  if (type == "Screenshots" && !host.isEmpty() &&
1852  !metadata->GetScreenshot().startsWith("/"))
1853  {
1854  test_file = generate_file_url("Screenshots",
1855  host, metadata->GetScreenshot());
1856  }
1857  else if (type == "Screenshots")
1858  test_file = metadata->GetScreenshot();
1859 
1860  if (!test_file.endsWith("/") && !test_file.isEmpty() &&
1861  test_file != VIDEO_SCREENSHOT_DEFAULT && (gpnode.isEmpty() ||
1862  (QString::compare(gpnode, title, Qt::CaseInsensitive) == 0)))
1863  {
1864  icon_file = test_file;
1865  break;
1866  }
1867  }
1868  }
1869  }
1870  if (icon_file.isEmpty() && !subDirs.isEmpty())
1871  {
1872  QString test_file;
1873  int subDirCount = subDirs.count();
1874  for (int i = 0; i < subDirCount; i ++)
1875  {
1876  if (levels < maxRecurse)
1877  {
1878  test_file = GetFirstImage(subDirs[i], type,
1879  node->GetText(), levels + 1);
1880  if (!test_file.isEmpty())
1881  {
1882  icon_file = test_file;
1883  break;
1884  }
1885  }
1886  }
1887  }
1888  }
1889  return icon_file;
1890 }
1891 
1897 {
1898  const int nodeInt = node->getInt();
1899 
1900  QString icon_file;
1901 
1902  if (nodeInt == kSubFolder || nodeInt == kUpFolder) // subdirectory
1903  {
1904  icon_file = VIDEO_SCREENSHOT_DEFAULT;
1905  }
1906  else
1907  {
1908  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1909 
1910  if (metadata)
1911  {
1912  if (metadata->IsHostSet() &&
1913  !metadata->GetScreenshot().startsWith("/") &&
1914  !metadata->GetScreenshot().isEmpty())
1915  {
1916  icon_file = generate_file_url("Screenshots", metadata->GetHost(),
1917  metadata->GetScreenshot());
1918  }
1919  else
1920  {
1921  icon_file = metadata->GetScreenshot();
1922  }
1923  }
1924  }
1925 
1926  if (IsDefaultScreenshot(icon_file))
1927  icon_file.clear();
1928 
1929  return icon_file;
1930 }
1931 
1937 {
1938  const int nodeInt = node->getInt();
1939 
1940  if (nodeInt == kSubFolder || nodeInt == kUpFolder)
1941  return QString();
1942 
1943  QString icon_file;
1944  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1945 
1946  if (metadata)
1947  {
1948  if (metadata->IsHostSet() &&
1949  !metadata->GetBanner().startsWith("/") &&
1950  !metadata->GetBanner().isEmpty())
1951  {
1952  icon_file = generate_file_url("Banners", metadata->GetHost(),
1953  metadata->GetBanner());
1954  }
1955  else
1956  {
1957  icon_file = metadata->GetBanner();
1958  }
1959 
1960  if (IsDefaultBanner(icon_file))
1961  icon_file.clear();
1962  }
1963 
1964  return icon_file;
1965 }
1966 
1972 {
1973  const int nodeInt = node->getInt();
1974 
1975  if (nodeInt == kSubFolder || nodeInt == kUpFolder) // subdirectory
1976  return QString();
1977 
1978  QString icon_file;
1979  const VideoMetadata *metadata = GetMetadataPtrFromNode(node);
1980 
1981  if (metadata)
1982  {
1983  if (metadata->IsHostSet() &&
1984  !metadata->GetFanart().startsWith("/") &&
1985  !metadata->GetFanart().isEmpty())
1986  {
1987  icon_file = generate_file_url("Fanart", metadata->GetHost(),
1988  metadata->GetFanart());
1989  }
1990  else
1991  {
1992  icon_file = metadata->GetFanart();
1993  }
1994 
1995  if (IsDefaultFanart(icon_file))
1996  icon_file.clear();
1997  }
1998 
1999  return icon_file;
2000 }
2001 
2006 bool VideoDialog::keyPressEvent(QKeyEvent *levent)
2007 {
2008  if (GetFocusWidget()->keyPressEvent(levent))
2009  return true;
2010 
2011  QStringList actions;
2012  bool handled = GetMythMainWindow()->TranslateKeyPress("Video", levent, actions);
2013 
2014  for (int i = 0; i < actions.size() && !handled; i++)
2015  {
2016  QString action = actions[i];
2017  handled = true;
2018 
2019  if (action == "INFO")
2020  {
2022  MythGenericTree *node = GetNodePtrFromButton(item);
2023  if (!m_menuPopup && node->getInt() != kUpFolder)
2024  VideoMenu();
2025  }
2026  else if (action == "INCPARENT")
2027  shiftParental(1);
2028  else if (action == "DECPARENT")
2029  shiftParental(-1);
2030  else if (action == "1" || action == "2" ||
2031  action == "3" || action == "4")
2033  else if (action == "FILTER")
2034  ChangeFilter();
2035  else if (action == "MENU")
2036  {
2037  if (!m_menuPopup)
2038  DisplayMenu();
2039  }
2040  else if (action == "PLAYALT")
2041  {
2042  if (!m_menuPopup && GetMetadata(GetItemCurrent()) &&
2044  playVideoAlt();
2045  }
2046  else if (action == "DOWNLOADDATA")
2047  {
2049  VideoSearch();
2050  }
2051  else if (action == "INCSEARCH")
2052  searchStart();
2053  else if (action == "ITEMDETAIL")
2054  DoItemDetailShow();
2055  else if (action == "DELETE")
2056  {
2058  RemoveVideo();
2059  }
2060  else if (action == "EDIT" && !m_menuPopup)
2061  EditMetadata();
2062  else if (action == "ESCAPE")
2063  {
2064  if (m_d->m_type != DLG_TREE
2065  && !GetMythMainWindow()->IsExitingToMain()
2066  && m_d->m_currentNode != m_d->m_rootNode)
2067  handled = goBack();
2068  else
2069  handled = false;
2070  }
2071  else
2072  handled = false;
2073  }
2074 
2075  if (!handled)
2076  {
2077  handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", levent,
2078  actions);
2079 
2080  for (int i = 0; i < actions.size() && !handled; i++)
2081  {
2082  QString action = actions[i];
2083  if (action == "PLAYBACK")
2084  {
2085  handled = true;
2086  playVideo();
2087  }
2088  }
2089  }
2090 
2091  if (!handled && MythScreenType::keyPressEvent(levent))
2092  handled = true;
2093 
2094  return handled;
2095 }
2096 
2101 void VideoDialog::createBusyDialog(const QString &title)
2102 {
2103  if (m_busyPopup)
2104  return;
2105 
2106  const QString& message = title;
2107 
2108  m_busyPopup = new MythUIBusyDialog(message, m_popupStack,
2109  "mythvideobusydialog");
2110 
2111  if (m_busyPopup->Create())
2113 }
2114 
2120 {
2121  if (m_d->m_notifications.contains(metadata->GetHash()))
2122  return;
2123 
2124  int id = GetNotificationCenter()->Register(this);
2125  m_d->m_notifications[metadata->GetHash()] = id;
2126 
2127  QString msg = tr("Fetching details for %1")
2128  .arg(metadata->GetTitle());
2129  QString desc;
2130  if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
2131  {
2132  desc = tr("Season %1, Episode %2")
2133  .arg(metadata->GetSeason()).arg(metadata->GetEpisode());
2134  }
2135  MythBusyNotification n(msg, _Location, desc);
2136  n.SetId(id);
2137  n.SetParent(this);
2139 }
2140 
2142 {
2143  if (!metadata || !m_d->m_notifications.contains(metadata->GetHash()))
2144  return;
2145 
2146  int id = m_d->m_notifications[metadata->GetHash()];
2147  m_d->m_notifications.remove(metadata->GetHash());
2148 
2149  QString msg;
2150  if (ok)
2151  {
2152  msg = tr("Retrieved details for %1").arg(metadata->GetTitle());
2153  }
2154  else
2155  {
2156  msg = tr("Failed to retrieve details for %1").arg(metadata->GetTitle());
2157  }
2158  QString desc;
2159  if (metadata->GetSeason() > 0 || metadata->GetEpisode() > 0)
2160  {
2161  desc = tr("Season %1, Episode %2")
2162  .arg(metadata->GetSeason()).arg(metadata->GetEpisode());
2163  }
2164  if (ok)
2165  {
2166  MythCheckNotification n(msg, _Location, desc);
2167  n.SetId(id);
2168  n.SetParent(this);
2170  }
2171  else
2172  {
2173  MythErrorNotification n(msg, _Location, desc);
2174  n.SetId(id);
2175  n.SetParent(this);
2177  }
2178  GetNotificationCenter()->UnRegister(this, id);
2179 }
2180 
2185 void VideoDialog::createOkDialog(const QString& title)
2186 {
2187  const QString& message = title;
2188 
2189  MythConfirmationDialog *okPopup =
2190  new MythConfirmationDialog(m_popupStack, message, false);
2191 
2192  if (okPopup->Create())
2193  m_popupStack->AddScreen(okPopup);
2194 }
2195 
2200 void VideoDialog::searchComplete(const QString& string)
2201 {
2202  LOG(VB_GENERAL, LOG_DEBUG, QString("Jumping to: %1").arg(string));
2203 
2205  QStringList childList;
2206  QList<MythGenericTree*>::iterator it;
2207  QList<MythGenericTree*> *children;
2208  QMap<int, QString> idTitle;
2209 
2210  if (parent && m_d->m_type == DLG_TREE)
2211  children = parent->getAllChildren();
2212  else
2213  children = m_d->m_currentNode->getAllChildren();
2214 
2215  for (it = children->begin(); it != children->end(); ++it)
2216  {
2217  MythGenericTree *child = *it;
2218  QString title = child->GetText();
2219  int id = child->getPosition();
2220  idTitle.insert(id, title);
2221  }
2222 
2223  if (m_d->m_type == DLG_TREE)
2224  {
2226  MythGenericTree *new_node = dlgParent->getChildAt(idTitle.key(string));
2227  if (new_node)
2228  {
2229  m_videoButtonTree->SetCurrentNode(new_node);
2231  }
2232  }
2233  else
2234  m_videoButtonList->SetItemCurrent(idTitle.key(string));
2235 }
2236 
2242 {
2244 
2245  QStringList childList;
2246  QList<MythGenericTree*>::iterator it;
2247  QList<MythGenericTree*> *children;
2248  if (parent && m_d->m_type == DLG_TREE)
2249  children = parent->getAllChildren();
2250  else
2251  children = m_d->m_currentNode->getAllChildren();
2252 
2253  for (it = children->begin(); it != children->end(); ++it)
2254  {
2255  MythGenericTree *child = *it;
2256  childList << child->GetText();
2257  }
2258 
2259  MythScreenStack *popupStack =
2260  GetMythMainWindow()->GetStack("popup stack");
2261  MythUISearchDialog *searchDialog = new MythUISearchDialog(popupStack,
2262  tr("Video Search"), childList, false, "");
2263 
2264  if (searchDialog->Create())
2265  {
2266  connect(searchDialog, SIGNAL(haveResult(QString)),
2267  SLOT(searchComplete(QString)));
2268 
2269  popupStack->AddScreen(searchDialog);
2270  }
2271  else
2272  delete searchDialog;
2273 }
2274 
2280 {
2281  bool handled = false;
2282 
2283  if (m_d->m_currentNode != m_d->m_rootNode)
2284  {
2285  MythGenericTree *lparent = m_d->m_currentNode->getParent();
2286  if (lparent)
2287  {
2288  SetCurrentNode(lparent);
2289 
2290  handled = true;
2291  }
2292  }
2293 
2294  loadData();
2295 
2296  return handled;
2297 }
2298 
2304 {
2305  if (!node)
2306  return;
2307 
2308  m_d->m_currentNode = node;
2309 }
2310 
2316 {
2318  MythUIButtonList *currentList = ci ? ci->parent() : nullptr;
2319 
2320  if (!currentList)
2321  return;
2322 
2323  CheckedSet(m_positionText, tr("%1 of %2")
2324  .arg(currentList->IsEmpty() ? 0 : currentList->GetCurrentPos() + 1)
2325  .arg(currentList->GetCount()));
2326 }
2327 
2333 {
2334  if (!item)
2335  return;
2336 
2337  MythUIButtonList *currentList = item->parent();
2338 
2339  if (!currentList)
2340  return;
2341 
2342  VideoMetadata *metadata = GetMetadata(item);
2343 
2344  MythGenericTree *node = GetNodePtrFromButton(item);
2345 
2346  if (!node)
2347  return;
2348 
2349  if (metadata)
2350  {
2351  InfoMap metadataMap;
2352  metadata->toMap(metadataMap);
2353  SetTextFromMap(metadataMap);
2354  }
2355  else
2356  {
2357  InfoMap metadataMap;
2358  ClearMap(metadataMap);
2359  SetTextFromMap(metadataMap);
2360  }
2361 
2362  ScreenCopyDest dest(this);
2363  CopyMetadataToUI(metadata, dest);
2364 
2365  if (node->getInt() == kSubFolder && !metadata)
2366  {
2367  QString cover = GetFirstImage(node, "Coverart");
2368  QString fanart = GetFirstImage(node, "Fanart");
2369  QString banner = GetFirstImage(node, "Banners");
2370  QString screenshot = GetFirstImage(node, "Screenshots");
2371  CheckedSet(m_coverImage, cover);
2372  CheckedSet(m_fanart, fanart);
2373  CheckedSet(m_banner, banner);
2374  CheckedSet(m_screenshot, screenshot);
2375  }
2376 
2377  if (!metadata)
2378  CheckedSet(m_titleText, item->GetText());
2379  UpdatePosition();
2380 
2381  if (m_d->m_currentNode)
2382  {
2384  CheckedSet(this, "foldername", m_d->m_currentNode->GetText());
2385  }
2386 
2387  if (node && node->getInt() == kSubFolder)
2388  CheckedSet(this, "childcount",
2389  QString("%1").arg(node->visibleChildCount()));
2390 
2391  if (node)
2392  node->becomeSelectedChild();
2393 }
2394 
2400 {
2401  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2402  QString label;
2403 
2404  if (metadata)
2405  {
2406  if (!metadata->GetSubtitle().isEmpty())
2407  label = tr("Video Options\n%1\n%2").arg(metadata->GetTitle())
2408  .arg(metadata->GetSubtitle());
2409  else
2410  label = tr("Video Options\n%1").arg(metadata->GetTitle());
2411  }
2412  else
2413  label = tr("Video Options");
2414 
2415  MythMenu *menu = new MythMenu(label, this, "actions");
2416 
2418  MythGenericTree *node = GetNodePtrFromButton(item);
2419  if (metadata)
2420  {
2421  if (!metadata->GetTrailer().isEmpty() ||
2422  gCoreContext->GetBoolSetting("mythvideo.TrailersRandomEnabled", false) ||
2424  menu->AddItem(tr("Play..."), nullptr, CreatePlayMenu());
2425  else
2426  menu->AddItem(tr("Play"), SLOT(playVideo()));
2427  if (metadata->GetWatched())
2428  menu->AddItem(tr("Mark as Unwatched"), SLOT(ToggleWatched()));
2429  else
2430  menu->AddItem(tr("Mark as Watched"), SLOT(ToggleWatched()));
2431  menu->AddItem(tr("Video Info"), nullptr, CreateInfoMenu());
2432  if (!m_d->m_notifications.contains(metadata->GetHash()))
2433  {
2434  menu->AddItem(tr("Change Video Details"), nullptr, CreateManageMenu());
2435  }
2436  menu->AddItem(tr("Delete"), SLOT(RemoveVideo()));
2437  }
2438  else if (node && node->getInt() != kUpFolder)
2439  {
2440  menu->AddItem(tr("Play Folder"), SLOT(playFolder()));
2441  }
2442 
2443 
2444  m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
2445 
2446  if (m_menuPopup->Create())
2447  {
2449  connect(m_menuPopup, SIGNAL(Closed(QString,int)), SLOT(popupClosed(QString,int)));
2450  }
2451  else
2452  delete m_menuPopup;
2453 }
2454 
2461 {
2462  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2463  QString label;
2464 
2465  if (metadata)
2466  label = tr("Playback Options\n%1").arg(metadata->GetTitle());
2467  else
2468  return nullptr;
2469 
2470  MythMenu *menu = new MythMenu(label, this, "actions");
2471 
2472  menu->AddItem(tr("Play"), SLOT(playVideo()));
2473 
2474  if (m_d->m_altPlayerEnabled)
2475  {
2476  menu->AddItem(tr("Play in Alternate Player"), SLOT(playVideoAlt()));
2477  }
2478 
2479  if (gCoreContext->GetBoolSetting("mythvideo.TrailersRandomEnabled", false))
2480  {
2481  menu->AddItem(tr("Play With Trailers"), SLOT(playVideoWithTrailers()));
2482  }
2483 
2484  QString trailerFile = metadata->GetTrailer();
2485  if (QFile::exists(trailerFile) ||
2486  (!metadata->GetHost().isEmpty() && !trailerFile.isEmpty()))
2487  {
2488  menu->AddItem(tr("Play Trailer"), SLOT(playTrailer()));
2489  }
2490 
2491  return menu;
2492 }
2493 
2499 {
2500  QString label = tr("Video Display Menu");
2501 
2502  MythMenu *menu = new MythMenu(label, this, "display");
2503 
2504  menu->AddItem(tr("Scan For Changes"), SLOT(doVideoScan()));
2505  menu->AddItem(tr("Retrieve All Details"), SLOT(VideoAutoSearch()));
2506  menu->AddItem(tr("Filter Display"), SLOT(ChangeFilter()));
2507  menu->AddItem(tr("Browse By..."), nullptr, CreateMetadataBrowseMenu());
2508  menu->AddItem(tr("Change View"), nullptr, CreateViewMenu());
2509  menu->AddItem(tr("Settings"), nullptr, CreateSettingsMenu());
2510 
2511  m_menuPopup = new MythDialogBox(menu, m_popupStack, "videomenupopup");
2512 
2513  if (m_menuPopup->Create())
2514  {
2516  connect(m_menuPopup, SIGNAL(Closed(QString,int)), SLOT(popupClosed(QString,int)));
2517  }
2518  else
2519  delete m_menuPopup;
2520 }
2521 
2522 // Switch from the display menu to the actions menu on second
2523 // menu press
2524 
2525 void VideoDialog::popupClosed(const QString& which, int result)
2526 {
2527  m_menuPopup = nullptr;
2528 
2529  if (result == -2)
2530  {
2531  if (which == "display")
2532  VideoMenu();
2533  }
2534 }
2535 
2541 {
2542  QString label = tr("Change View");
2543 
2544  MythMenu *menu = new MythMenu(label, this, "view");
2545 
2546  if (!(m_d->m_type & DLG_BROWSER))
2547  menu->AddItem(tr("Switch to Browse View"), SLOT(SwitchBrowse()));
2548 
2549  if (!(m_d->m_type & DLG_GALLERY))
2550  menu->AddItem(tr("Switch to Gallery View"), SLOT(SwitchGallery()));
2551 
2552  if (!(m_d->m_type & DLG_TREE))
2553  menu->AddItem(tr("Switch to List View"), SLOT(SwitchTree()));
2554 
2555  if (!(m_d->m_type & DLG_MANAGER))
2556  menu->AddItem(tr("Switch to Manage View"), SLOT(SwitchManager()));
2557 
2558  if (m_d->m_isFlatList)
2559  menu->AddItem(tr("Show Directory Structure"), SLOT(ToggleFlatView()));
2560  else
2561  menu->AddItem(tr("Hide Directory Structure"), SLOT(ToggleFlatView()));
2562 
2563  if (m_d->m_isFileBrowser)
2564  menu->AddItem(tr("Browse Library (recommended)"), SLOT(ToggleBrowseMode()));
2565  else
2566  menu->AddItem(tr("Browse Filesystem (slow)"), SLOT(ToggleBrowseMode()));
2567 
2568 
2569  return menu;
2570 }
2571 
2577 {
2578  QString label = tr("Video Settings");
2579 
2580  MythMenu *menu = new MythMenu(label, this, "settings");
2581 
2582  menu->AddItem(tr("Player Settings"), SLOT(ShowPlayerSettings()));
2583  menu->AddItem(tr("Metadata Settings"), SLOT(ShowMetadataSettings()));
2584  menu->AddItem(tr("File Type Settings"), SLOT(ShowExtensionSettings()));
2585 
2586  return menu;
2587 }
2588 
2594 {
2595  PlayerSettings *ps = new PlayerSettings(m_mainStack, "player settings");
2596 
2597  if (ps->Create())
2598  m_mainStack->AddScreen(ps);
2599  else
2600  delete ps;
2601 }
2602 
2608 {
2609  MetadataSettings *ms = new MetadataSettings(m_mainStack, "metadata settings");
2610 
2611  if (ms->Create())
2612  m_mainStack->AddScreen(ms);
2613  else
2614  delete ms;
2615 }
2616 
2622 {
2623  FileAssocDialog *fa = new FileAssocDialog(m_mainStack, "fa dialog");
2624 
2625  if (fa->Create())
2626  m_mainStack->AddScreen(fa);
2627  else
2628  delete fa;
2629 }
2630 
2636 {
2637  QString label = tr("Browse By");
2638 
2639  MythMenu *menu = new MythMenu(label, this, "metadata");
2640 
2641  if (m_d->m_groupType != BRS_CAST)
2642  menu->AddItem(tr("Cast"), SLOT(SwitchVideoCastGroup()));
2643 
2644  if (m_d->m_groupType != BRS_CATEGORY)
2645  menu->AddItem(tr("Category"), SLOT(SwitchVideoCategoryGroup()));
2646 
2647  if (m_d->m_groupType != BRS_INSERTDATE)
2648  menu->AddItem(tr("Date Added"), SLOT(SwitchVideoInsertDateGroup()));
2649 
2650  if (m_d->m_groupType != BRS_DIRECTOR)
2651  menu->AddItem(tr("Director"), SLOT(SwitchVideoDirectorGroup()));
2652 
2653  if (m_d->m_groupType != BRS_STUDIO)
2654  menu->AddItem(tr("Studio"), SLOT(SwitchVideoStudioGroup()));
2655 
2656  if (m_d->m_groupType != BRS_FOLDER)
2657  menu->AddItem(tr("Folder"), SLOT(SwitchVideoFolderGroup()));
2658 
2659  if (m_d->m_groupType != BRS_GENRE)
2660  menu->AddItem(tr("Genre"), SLOT(SwitchVideoGenreGroup()));
2661 
2662  if (m_d->m_groupType != BRS_TVMOVIE)
2663  menu->AddItem(tr("TV/Movies"),SLOT(SwitchVideoTVMovieGroup()));
2664 
2665  if (m_d->m_groupType != BRS_USERRATING)
2666  menu->AddItem(tr("User Rating"), SLOT(SwitchVideoUserRatingGroup()));
2667 
2668  if (m_d->m_groupType != BRS_YEAR)
2669  menu->AddItem(tr("Year"), SLOT(SwitchVideoYearGroup()));
2670 
2671  return menu;
2672 }
2673 
2679 {
2680  QString label = tr("Video Info");
2681 
2682  MythMenu *menu = new MythMenu(label, this, "info");
2683 
2685  menu->AddItem(tr("View Details"), SLOT(DoItemDetailShow()));
2686 
2687  menu->AddItem(tr("View Full Plot"), SLOT(ViewPlot()));
2688 
2689  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2690  if (metadata)
2691  {
2692  if (!metadata->GetCast().empty())
2693  menu->AddItem(tr("View Cast"), SLOT(ShowCastDialog()));
2694  if (!metadata->GetHomepage().isEmpty())
2695  menu->AddItem(tr("View Homepage"), SLOT(ShowHomepage()));
2696  }
2697 
2698  return menu;
2699 }
2700 
2706 {
2707  QString label = tr("Manage Video Details");
2708 
2709  MythMenu *menu = new MythMenu(label, this, "manage");
2710 
2711  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2712 
2713  menu->AddItem(tr("Edit Details"), SLOT(EditMetadata()));
2714  menu->AddItem(tr("Retrieve Details"), SLOT(VideoSearch()));
2715  if (metadata->GetProcessed())
2716  menu->AddItem(tr("Allow Updates"), SLOT(ToggleProcess()));
2717  else
2718  menu->AddItem(tr("Disable Updates"), SLOT(ToggleProcess()));
2719  menu->AddItem(tr("Reset Details"), SLOT(ResetMetadata()));
2720 
2721  return menu;
2722 }
2723 
2725 {
2726  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2727  if (metadata)
2728  {
2729  metadata->SetProcessed(!metadata->GetProcessed());
2730  metadata->UpdateDatabase();
2731 
2732  refreshData();
2733  }
2734 }
2735 
2741 {
2743  gCoreContext->SaveSetting("VideoDialogNoDB",
2744  QString("%1").arg((int)m_d->m_isFileBrowser));
2745  reloadData();
2746 }
2747 
2753 {
2755  gCoreContext->SaveSetting(QString("mythvideo.folder_view_%1").arg(m_d->m_type),
2756  QString("%1").arg((int)m_d->m_isFlatList));
2757  // TODO: This forces a complete tree rebuild, this is SLOW and shouldn't
2758  // be necessary since MythGenericTree can do a flat view without a rebuild,
2759  // I just don't want to re-write VideoList just now
2760  reloadData();
2761 }
2762 
2768 {
2769  SetCurrentNode(node);
2770  loadData();
2771 }
2772 
2778 {
2779  QStringList route = node->getRouteByString();
2780  if (m_d->m_videoList && m_d->m_videoList->refreshNode(node))
2781  reloadData();
2783 }
2784 
2790 {
2791  MythGenericTree *node = GetNodePtrFromButton(item);
2792  int nodeInt = node->getInt();
2793 
2794  switch (nodeInt)
2795  {
2796  case kDynamicSubFolder:
2797  handleDynamicDirSelect(node);
2798  break;
2799  case kSubFolder:
2800  handleDirSelect(node);
2801  break;
2802  case kUpFolder:
2803  goBack();
2804  break;
2805  default:
2806  {
2807  bool doPlay = true;
2808  if (m_d->m_type == DLG_GALLERY)
2809  {
2810  doPlay = !DoItemDetailShow();
2811  }
2812 
2813  if (doPlay)
2814  playVideo();
2815  }
2816  };
2817 }
2818 
2824 {
2826 }
2827 
2833 {
2835 }
2836 
2842 {
2844 }
2845 
2851 {
2853 }
2854 
2860 {
2862 }
2863 
2869 {
2871 }
2872 
2878 {
2880 }
2881 
2887 {
2889 }
2890 
2896 {
2898 }
2899 
2905 {
2907 }
2908 
2914 {
2916 }
2917 
2923 {
2925 }
2926 
2932 {
2934 }
2935 
2941 {
2943 }
2944 
2950 {
2951  m_d->m_switchingLayout = true;
2952 
2953  // save current position so it can be restored after the switch
2954  SavePosition();
2955 
2956  VideoDialog *mythvideo =
2957  new VideoDialog(GetMythMainWindow()->GetMainStack(), "mythvideo",
2958  m_d->m_videoList, type, browse);
2959 
2960  if (mythvideo->Create())
2961  {
2962  gCoreContext->SaveSetting("Default MythVideo View", type);
2963  gCoreContext->SaveSetting("mythvideo.db_group_type", browse);
2964  MythScreenStack *screenStack = GetScreenStack();
2965  screenStack->AddScreen(mythvideo);
2966  screenStack->PopScreen(this, false, false);
2967  deleteLater();
2968  }
2969  else
2970  {
2971  ShowOkPopup(tr("An error occurred when switching views."));
2972  }
2973 }
2974 
2980 {
2981  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2982 
2983  PlotDialog *plotdialog = new PlotDialog(m_popupStack, metadata);
2984 
2985  if (plotdialog->Create())
2986  m_popupStack->AddScreen(plotdialog);
2987 }
2988 
2994 {
2995  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
2996 
2997  if (metadata)
2998  {
3000  ItemDetailPopup *idp = new ItemDetailPopup(mainStack, metadata,
3002 
3003  if (idp->Create())
3004  {
3005  mainStack->AddScreen(idp);
3006  return true;
3007  }
3008  }
3009 
3010  return false;
3011 }
3012 
3018 {
3019  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3020 
3021  CastDialog *castdialog = new CastDialog(m_popupStack, metadata);
3022 
3023  if (castdialog->Create())
3024  m_popupStack->AddScreen(castdialog);
3025 }
3026 
3028 {
3029  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3030 
3031  if (!metadata)
3032  return;
3033 
3034  QString url = metadata->GetHomepage();
3035 
3036  if (url.isEmpty())
3037  return;
3038 
3039  QString browser = gCoreContext->GetSetting("WebBrowserCommand", "");
3040  QString zoom = gCoreContext->GetSetting("WebBrowserZoomLevel", "1.0");
3041 
3042  if (browser.isEmpty())
3043  {
3044  ShowOkPopup(tr("No browser command set! MythVideo needs MythBrowser "
3045  "installed to display the homepage."));
3046  return;
3047  }
3048 
3049  if (browser.toLower() == "internal")
3050  {
3051  GetMythMainWindow()->HandleMedia("WebBrowser", url);
3052  return;
3053  }
3054 
3055  QString cmd = browser;
3056  cmd.replace("%ZOOM%", zoom);
3057  cmd.replace("%URL%", url);
3058  cmd.replace('\'', "%27");
3059  cmd.replace("&","\\&");
3060  cmd.replace(";","\\;");
3061 
3062  GetMythMainWindow()->AllowInput(false);
3064  GetMythMainWindow()->AllowInput(true);
3065 }
3066 
3072 {
3073  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3074  if (metadata)
3075  PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
3076 }
3077 
3083 {
3084  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3085  if (metadata)
3086  PlayVideo(metadata->GetFilename(),
3087  m_d->m_videoList->getListCache(), true);
3088 }
3089 
3095 {
3096  const int WATCHED_WATERMARK = 10000; // Play less then this milisec and the chain of
3097  // videos will not be followed when
3098  // playing.
3099  QTime playing_time;
3100 
3102  MythGenericTree *node = GetNodePtrFromButton(item);
3103  int list_count;
3104 
3105  if (node && !(node->getInt() >= 0))
3106  list_count = node->childCount();
3107  else
3108  return;
3109 
3110  if (list_count > 0)
3111  {
3112  bool video_started = false;
3113  int i = 0;
3114  while (i < list_count &&
3115  (!video_started || playing_time.elapsed() > WATCHED_WATERMARK))
3116  {
3117  MythGenericTree *subnode = node->getChildAt(i);
3118  if (subnode)
3119  {
3120  VideoMetadata *metadata = GetMetadataPtrFromNode(subnode);
3121  if (metadata)
3122  {
3123  playing_time.start();
3124  video_started = true;
3125  PlayVideo(metadata->GetFilename(),
3127  }
3128  }
3129  i++;
3130  }
3131  }
3132 }
3133 
3134 namespace
3135 {
3136  struct SimpleCollect : public DirectoryHandler
3137  {
3138  explicit SimpleCollect(QStringList &fileList) : m_fileList(fileList) {}
3139 
3140  DirectoryHandler *newDir(const QString &dirName,
3141  const QString &fqDirName) override // DirectoryHandler
3142  {
3143  (void) dirName;
3144  (void) fqDirName;
3145  return this;
3146  }
3147 
3148  void handleFile(const QString &fileName, const QString &fqFileName,
3149  const QString &extension, const QString &host) override // DirectoryHandler
3150  {
3151  (void) fileName;
3152  (void) extension;
3153  (void) host;
3154  m_fileList.push_back(fqFileName);
3155  }
3156 
3157  private:
3158  QStringList &m_fileList;
3159  };
3160 
3161  QStringList GetTrailersInDirectory(const QString &startDir)
3162  {
3165  .getExtensionIgnoreList(extensions);
3166  QStringList ret;
3167  SimpleCollect sc(ret);
3168 
3169  (void) ScanVideoDirectory(startDir, &sc, extensions, false);
3170  return ret;
3171  }
3172 }
3173 
3179 {
3180  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3181  if (!metadata) return;
3182 
3183  QStringList trailers = GetTrailersInDirectory(gCoreContext->
3184  GetSetting("mythvideo.TrailersDir"));
3185 
3186  if (trailers.isEmpty())
3187  return;
3188 
3189  const int trailersToPlay =
3190  gCoreContext->GetNumSetting("mythvideo.TrailersRandomCount");
3191 
3192  int i = 0;
3193  while (!trailers.isEmpty() && i < trailersToPlay)
3194  {
3195  ++i;
3196  QString trailer = trailers.takeAt(random() % trailers.size());
3197 
3198  LOG(VB_GENERAL, LOG_DEBUG,
3199  QString("Random trailer to play will be: %1").arg(trailer));
3200 
3202  }
3203 
3204  PlayVideo(metadata->GetFilename(), m_d->m_videoList->getListCache());
3205 }
3206 
3212 {
3213  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3214  if (!metadata) return;
3215  QString url;
3216 
3217  if (metadata->IsHostSet() && !metadata->GetTrailer().startsWith("/"))
3218  url = generate_file_url("Trailers", metadata->GetHost(),
3219  metadata->GetTrailer());
3220  else
3221  url = metadata->GetTrailer();
3222 
3224 }
3225 
3231 {
3232  m_d->m_parentalLevel.SetLevel(level);
3233 }
3234 
3240 {
3242  .GetLevel() + amount).GetLevel());
3243 }
3244 
3250 {
3251  MythScreenStack *mainStack = GetScreenStack();
3252 
3253  VideoFilterDialog *filterdialog = new VideoFilterDialog(mainStack,
3254  "videodialogfilters", m_d->m_videoList.get());
3255 
3256  if (filterdialog->Create())
3257  mainStack->AddScreen(filterdialog);
3258 
3259  connect(filterdialog, SIGNAL(filterChanged()), SLOT(reloadData()));
3260 }
3261 
3267 {
3268  VideoMetadata *metadata = nullptr;
3269 
3270  if (item)
3271  {
3272  MythGenericTree *node = GetNodePtrFromButton(item);
3273  if (node)
3274  {
3275  int nodeInt = node->getInt();
3276 
3277  if (nodeInt >= 0)
3278  metadata = GetMetadataPtrFromNode(node);
3279  }
3280  }
3281 
3282  return metadata;
3283 }
3284 
3285 void VideoDialog::customEvent(QEvent *levent)
3286 {
3287  if (levent->type() == MetadataFactoryMultiResult::kEventType)
3288  {
3289  MetadataFactoryMultiResult *mfmr = dynamic_cast<MetadataFactoryMultiResult*>(levent);
3290 
3291  if (!mfmr)
3292  return;
3293 
3294  MetadataLookupList list = mfmr->m_results;
3295 
3296  if (list.count() > 1)
3297  {
3298  VideoMetadata *metadata =
3299  list[0]->GetData().value<VideoMetadata *>();
3300  dismissFetchDialog(metadata, true);
3301  MetadataResultsDialog *resultsdialog =
3303 
3304  connect(resultsdialog, SIGNAL(haveResult(RefCountHandler<MetadataLookup>)),
3306  Qt::QueuedConnection);
3307 
3308  if (resultsdialog->Create())
3309  m_popupStack->AddScreen(resultsdialog);
3310  }
3311  }
3312  else if (levent->type() == MetadataFactorySingleResult::kEventType)
3313  {
3314  MetadataFactorySingleResult *mfsr = dynamic_cast<MetadataFactorySingleResult*>(levent);
3315 
3316  if (!mfsr)
3317  return;
3318 
3319  MetadataLookup *lookup = mfsr->m_result;
3320 
3321  if (!lookup)
3322  return;
3323 
3324  OnVideoSearchDone(lookup);
3325  }
3326  else if (levent->type() == MetadataFactoryNoResult::kEventType)
3327  {
3328  MetadataFactoryNoResult *mfnr = dynamic_cast<MetadataFactoryNoResult*>(levent);
3329 
3330  if (!mfnr)
3331  return;
3332 
3333  MetadataLookup *lookup = mfnr->m_result;
3334 
3335  if (!lookup)
3336  return;
3337 
3338  VideoMetadata *metadata =
3339  lookup->GetData().value<VideoMetadata *>();
3340  if (metadata)
3341  {
3342  dismissFetchDialog(metadata, false);
3343  metadata->SetProcessed(true);
3344  metadata->UpdateDatabase();
3345  }
3346  LOG(VB_GENERAL, LOG_INFO,
3347  QString("No results found for %1 %2 %3").arg(lookup->GetTitle())
3348  .arg(lookup->GetSeason()).arg(lookup->GetEpisode()));
3349  }
3350  else if (levent->type() == DialogCompletionEvent::kEventType)
3351  {
3352  DialogCompletionEvent *dce = static_cast<DialogCompletionEvent *>(levent);
3353  QString id = dce->GetId();
3354 
3355  if (id == "scanprompt")
3356  {
3357  int result = dce->GetResult();
3358  if (result == 1)
3359  doVideoScan();
3360  }
3361  else
3362  m_menuPopup = nullptr;
3363  }
3364  else if (levent->type() == ImageDLFailureEvent::kEventType)
3365  {
3366  MythErrorNotification n(tr("Failed to retrieve image(s)"),
3367  _Location,
3368  tr("Check logs"));
3370  }
3371 }
3372 
3374 {
3375  // The metadata has some cover file set
3376  dismissFetchDialog(metadata, true);
3377 
3378  metadata->SetProcessed(true);
3379  metadata->UpdateDatabase();
3380 
3381  MythUIButtonListItem *item = GetItemByMetadata(metadata);
3382  if (item != nullptr)
3383  UpdateItem(item);
3384 }
3385 
3387 {
3388  if (m_videoButtonTree)
3389  {
3391  }
3392 
3394 }
3395 
3397 {
3398  if (m_videoButtonTree)
3399  {
3401  }
3402 
3403  QList<MythGenericTree*>::iterator it;
3404  QList<MythGenericTree*> *children;
3405  QMap<int, int> idPosition;
3406 
3407  children = m_d->m_currentNode->getAllChildren();
3408 
3409  for (it = children->begin(); it != children->end(); ++it)
3410  {
3411  MythGenericTree *child = *it;
3412  int nodeInt = child->getInt();
3413  if (nodeInt != kSubFolder && nodeInt != kUpFolder)
3414  {
3415  VideoMetadata *listmeta =
3416  GetMetadataPtrFromNode(child);
3417  if (listmeta)
3418  {
3419  int position = child->getPosition();
3420  int id = listmeta->GetID();
3421  idPosition.insert(id, position);
3422  }
3423  }
3424  }
3425 
3426  return m_videoButtonList->GetItemAt(idPosition.value(metadata->GetID()));
3427 }
3428 
3430  bool automode)
3431 {
3432  if (!node)
3433  node = GetNodePtrFromButton(GetItemCurrent());
3434 
3435  if (!node)
3436  return;
3437 
3438  VideoMetadata *metadata = GetMetadataPtrFromNode(node);
3439 
3440  if (!metadata)
3441  return;
3442 
3443  m_metadataFactory->Lookup(metadata, automode, true);
3444 
3445  if (!automode)
3446  {
3447  createFetchDialog(metadata);
3448  }
3449 }
3450 
3452 {
3453  if (!node)
3454  node = m_d->m_rootNode;
3455  typedef QList<MythGenericTree *> MGTreeChildList;
3456  MGTreeChildList *lchildren = node->getAllChildren();
3457 
3458  LOG(VB_GENERAL, LOG_DEBUG,
3459  QString("Fetching details in %1").arg(node->GetText()));
3460 
3461  for (MGTreeChildList::const_iterator p = lchildren->begin();
3462  p != lchildren->end(); ++p)
3463  {
3464  if (((*p)->getInt() == kSubFolder) ||
3465  ((*p)->getInt() == kUpFolder))
3466  VideoAutoSearch((*p));
3467  else
3468  {
3469  VideoMetadata *metadata = GetMetadataPtrFromNode((*p));
3470 
3471  if (!metadata)
3472  continue;
3473 
3474  if (!metadata->GetProcessed())
3475  VideoSearch((*p), true);
3476  }
3477  }
3478 }
3479 
3481 {
3483  if (!item)
3484  return;
3485 
3486  VideoMetadata *metadata = GetMetadata(item);
3487  if (metadata)
3488  {
3489  metadata->SetWatched(!metadata->GetWatched());
3490  metadata->UpdateDatabase();
3491  item->DisplayState(WatchedToState(metadata->GetWatched()),
3492  "watchedstate");
3493  }
3494 }
3495 
3497 {
3498  if (!lookup)
3499  return;
3500 
3501  OnVideoSearchDone(lookup);
3502 }
3503 
3505 {
3506  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3507  if (metadata)
3508  {
3509  ParentalLevel curshowlevel = metadata->GetShowLevel();
3510 
3511  curshowlevel += amount;
3512 
3513  if (curshowlevel.GetLevel() != metadata->GetShowLevel())
3514  {
3515  metadata->SetShowLevel(curshowlevel.GetLevel());
3516  metadata->UpdateDatabase();
3517  refreshData();
3518  }
3519  }
3520 }
3521 
3523 {
3524  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3525  if (!metadata)
3526  return;
3527 
3528  MythScreenStack *screenStack = GetScreenStack();
3529 
3530  EditMetadataDialog *md_editor = new EditMetadataDialog(screenStack,
3531  "mythvideoeditmetadata", metadata,
3533 
3534  connect(md_editor, SIGNAL(Finished()), SLOT(refreshData()));
3535 
3536  if (md_editor->Create())
3537  screenStack->AddScreen(md_editor);
3538 }
3539 
3541 {
3542  VideoMetadata *metadata = GetMetadata(GetItemCurrent());
3543 
3544  if (!metadata)
3545  return;
3546 
3547  QString message = tr("Are you sure you want to permanently delete:\n%1")
3548  .arg(metadata->GetTitle());
3549 
3550  MythConfirmationDialog *confirmdialog =
3551  new MythConfirmationDialog(m_popupStack,message);
3552 
3553  if (confirmdialog->Create())
3554  m_popupStack->AddScreen(confirmdialog);
3555 
3556  connect(confirmdialog, SIGNAL(haveResult(bool)),
3557  SLOT(OnRemoveVideo(bool)));
3558 }
3559 
3560 void VideoDialog::OnRemoveVideo(bool dodelete)
3561 {
3562  if (!dodelete)
3563  return;
3564 
3566  MythGenericTree *gtItem = GetNodePtrFromButton(item);
3567 
3568  VideoMetadata *metadata = GetMetadata(item);
3569 
3570  if (!metadata)
3571  return;
3572 
3573  if (m_d->m_videoList->Delete(metadata->GetID()))
3574  {
3575  if (m_videoButtonTree)
3576  m_videoButtonTree->RemoveItem(item, false); // FIXME Segfault when true
3577  else
3579 
3580  MythGenericTree *parent = gtItem->getParent();
3581  parent->deleteNode(gtItem);
3582  }
3583  else
3584  {
3585  QString message = tr("Failed to delete file");
3586 
3587  MythConfirmationDialog *confirmdialog =
3588  new MythConfirmationDialog(m_popupStack,message,false);
3589 
3590  if (confirmdialog->Create())
3591  m_popupStack->AddScreen(confirmdialog);
3592  }
3593 }
3594 
3596 {
3598  VideoMetadata *metadata = GetMetadata(item);
3599 
3600  if (metadata)
3601  {
3602  metadata->Reset();
3603  metadata->UpdateDatabase();
3604  UpdateItem(item);
3605  }
3606 }
3607 
3609 {
3610  if (!metadata)
3611  return;
3612 
3613  QStringList cover_dirs;
3614  cover_dirs += m_d->m_artDir;
3615 
3616  QString cover_file;
3617  QString inetref = metadata->GetInetRef();
3618  QString filename = metadata->GetFilename();
3619  QString title = metadata->GetTitle();
3620  int season = metadata->GetSeason();
3621  QString host = metadata->GetHost();
3622  int episode = metadata->GetEpisode();
3623 
3624  if (metadata->GetCoverFile().isEmpty() ||
3625  IsDefaultCoverFile(metadata->GetCoverFile()))
3626  {
3627  if (GetLocalVideoImage(inetref, filename,
3628  cover_dirs, cover_file, title,
3629  season, host, "Coverart", episode))
3630  {
3631  metadata->SetCoverFile(cover_file);
3632  OnVideoImageSetDone(metadata);
3633  }
3634  }
3635 
3636  QStringList fanart_dirs;
3637  fanart_dirs += m_d->m_fanDir;
3638 
3639  QString fanart_file;
3640 
3641  if (metadata->GetFanart().isEmpty())
3642  {
3643  if (GetLocalVideoImage(inetref, filename,
3644  fanart_dirs, fanart_file, title,
3645  season, host, "Fanart", episode))
3646  {
3647  metadata->SetFanart(fanart_file);
3648  OnVideoImageSetDone(metadata);
3649  }
3650  }
3651 
3652  QStringList banner_dirs;
3653  banner_dirs += m_d->m_banDir;
3654 
3655  QString banner_file;
3656 
3657  if (metadata->GetBanner().isEmpty())
3658  {
3659  if (GetLocalVideoImage(inetref, filename,
3660  banner_dirs, banner_file, title,
3661  season, host, "Banners", episode))
3662  {
3663  metadata->SetBanner(banner_file);
3664  OnVideoImageSetDone(metadata);
3665  }
3666  }
3667 
3668  QStringList screenshot_dirs;
3669  screenshot_dirs += m_d->m_sshotDir;
3670 
3671  QString screenshot_file;
3672 
3673  if (metadata->GetScreenshot().isEmpty())
3674  {
3675  if (GetLocalVideoImage(inetref, filename,
3676  screenshot_dirs, screenshot_file, title,
3677  season, host, "Screenshots", episode,
3678  true))
3679  {
3680  metadata->SetScreenshot(screenshot_file);
3681  OnVideoImageSetDone(metadata);
3682  }
3683  }
3684 }
3685 
3687 {
3688  if (!lookup)
3689  return;
3690 
3691  VideoMetadata *metadata = lookup->GetData().value<VideoMetadata *>();
3692 
3693  if (!metadata)
3694  return;
3695 
3696  dismissFetchDialog(metadata, true);
3697  metadata->SetTitle(lookup->GetTitle());
3698  metadata->SetSubtitle(lookup->GetSubtitle());
3699 
3700  if (metadata->GetTagline().isEmpty())
3701  metadata->SetTagline(lookup->GetTagline());
3702  if (metadata->GetYear() == 1895 || metadata->GetYear() == 0)
3703  metadata->SetYear(lookup->GetYear());
3704  if (metadata->GetReleaseDate() == QDate())
3705  metadata->SetReleaseDate(lookup->GetReleaseDate());
3706  if (metadata->GetDirector() == VIDEO_DIRECTOR_UNKNOWN ||
3707  metadata->GetDirector().isEmpty())
3708  {
3709  QList<PersonInfo> director = lookup->GetPeople(kPersonDirector);
3710  if (director.count() > 0)
3711  metadata->SetDirector(director.takeFirst().name);
3712  }
3713  if (metadata->GetStudio().isEmpty())
3714  {
3715  QStringList studios = lookup->GetStudios();
3716  if (studios.count() > 0)
3717  metadata->SetStudio(studios.takeFirst());
3718  }
3719  if (metadata->GetPlot() == VIDEO_PLOT_DEFAULT ||
3720  metadata->GetPlot().isEmpty())
3721  metadata->SetPlot(lookup->GetDescription());
3722  if (metadata->GetUserRating() == 0)
3723  metadata->SetUserRating(lookup->GetUserRating());
3724  if (metadata->GetRating() == VIDEO_RATING_DEFAULT)
3725  metadata->SetRating(lookup->GetCertification());
3726  if (metadata->GetLength() == 0)
3727  metadata->SetLength(lookup->GetRuntime());
3728  if (metadata->GetSeason() == 0)
3729  metadata->SetSeason(lookup->GetSeason());
3730  if (metadata->GetEpisode() == 0)
3731  metadata->SetEpisode(lookup->GetEpisode());
3732  if (metadata->GetHomepage().isEmpty())
3733  metadata->SetHomepage(lookup->GetHomepage());
3734 
3735  metadata->SetInetRef(lookup->GetInetref());
3736 
3737  m_d->AutomaticParentalAdjustment(metadata);
3738 
3739  // Cast
3740  QList<PersonInfo> actors = lookup->GetPeople(kPersonActor);
3741  QList<PersonInfo> gueststars = lookup->GetPeople(kPersonGuestStar);
3742 
3743  for (QList<PersonInfo>::const_iterator p = gueststars.begin();
3744  p != gueststars.end(); ++p)
3745  {
3746  actors.append(*p);
3747  }
3748 
3750  QStringList cl;
3751 
3752  for (QList<PersonInfo>::const_iterator p = actors.begin();
3753  p != actors.end(); ++p)
3754  {
3755  cl.append((*p).name);
3756  }
3757 
3758  for (QStringList::const_iterator p = cl.begin();
3759  p != cl.end(); ++p)
3760  {
3761  QString cn = (*p).trimmed();
3762  if (cn.length())
3763  {
3764  cast.push_back(VideoMetadata::cast_list::
3765  value_type(-1, cn));
3766  }
3767  }
3768 
3769  metadata->SetCast(cast);
3770 
3771  // Genres
3772  VideoMetadata::genre_list video_genres;
3773  QStringList genres = lookup->GetCategories();
3774 
3775  for (QStringList::const_iterator p = genres.begin();
3776  p != genres.end(); ++p)
3777  {
3778  QString genre_name = (*p).trimmed();
3779  if (genre_name.length())
3780  {
3781  video_genres.push_back(
3782  VideoMetadata::genre_list::value_type(-1, genre_name));
3783  }
3784  }
3785 
3786  metadata->SetGenres(video_genres);
3787 
3788  // Countries
3789  VideoMetadata::country_list video_countries;
3790  QStringList countries = lookup->GetCountries();
3791 
3792  for (QStringList::const_iterator p = countries.begin();
3793  p != countries.end(); ++p)
3794  {
3795  QString country_name = (*p).trimmed();
3796  if (country_name.length())
3797  {
3798  video_countries.push_back(
3799  VideoMetadata::country_list::value_type(-1,
3800  country_name));
3801  }
3802  }
3803 
3804  metadata->SetCountries(video_countries);
3805  metadata->SetProcessed(true);
3806 
3807  metadata->UpdateDatabase();
3808 
3809  MythUIButtonListItem *item = GetItemByMetadata(metadata);
3810  if (item != nullptr)
3811  UpdateItem(item);
3812 
3813  StartVideoImageSet(metadata);
3814 }
3815 
3817 {
3818  if (!m_d->m_scanner)
3819  m_d->m_scanner = new VideoScanner();
3820  connect(m_d->m_scanner, SIGNAL(finished(bool)), SLOT(scanFinished(bool)));
3822 }
3823 
3825 {
3826  QString message = tr("There are no videos in the database, would you like "
3827  "to scan your video directories now?");
3829  message,
3830  true);
3831  dialog->SetReturnEvent(this, "scanprompt");
3832  if (dialog->Create())
3833  m_popupStack->AddScreen(dialog);
3834  else
3835  delete dialog;
3836 }
3837 
3838 #include "videodlg.moc"
Level GetLevel() const
void playVideoAlt()
Play the selected item in an alternate player.
Definition: videodlg.cpp:3082
void SetHomepage(const QString &homepage)
ItemDetailPopup(MythScreenStack *lparent, VideoMetadata *metadata, const VideoMetadataListManager &listManager)
Definition: videodlg.cpp:571
QStringList GetCategories() const
parental_level_map m_rating_to_pl
Definition: videodlg.cpp:797
MythGenericTree * buildVideoList(bool filebrowser, bool flatlist, int group_type, const ParentalLevel &parental_level, bool include_updirs)
Definition: videolist.cpp:467
void StartVideoImageSet(VideoMetadata *metadata)
Definition: videodlg.cpp:3608
bool keyPressEvent(QKeyEvent *levent) override
Handle keypresses and keybindings.
Definition: videodlg.cpp:2006
std::vector< cast_entry > cast_list
Definition: videometadata.h:34
bool DoItemDetailShow()
Display the Item Detail Popup.
Definition: videodlg.cpp:2993
void SetParent(void *parent)
contains the parent address.
MythGenericTree * GetCurrentNode(void) const
void ShowMetadataSettings()
Pop up a MythUI Menu for MythVideo Metadata Settings.
Definition: videodlg.cpp:2607
avoid disabling UI drawing
Definition: mythsystem.h:35
MythScreenStack * GetScreenStack() const
void ToggleFlatView()
Toggle Flat View.
Definition: videodlg.cpp:2752
void UpdateItem(MythUIButtonListItem *item)
Update the visible representation of a MythUIButtonListItem.
Definition: videodlg.cpp:1219
void SetSubtitle(const QString &subtitle, const QString &sortSubtitle="")
MythUIText * m_novideoText
Definition: videodlg.h:196
int GetLength() const
MythGenericTree * getSelectedChild(bool onlyVisible=false) const
unsigned int slots[4]
Definition: element.c:38
void SetCurrentNode(MythGenericTree *)
Switch to a given MythGenericTree node.
Definition: videodlg.cpp:2303
bool GetWatched() const
QStringList GetVideoDirs()
Definition: videoutils.cpp:122
MythUIButtonList * m_videoButtonList
Definition: videodlg.h:192
VideoDialogPrivate(const VideoListPtr &videoList, VideoDialog::DialogType type, VideoDialog::BrowseType browse)
Definition: videodlg.cpp:686
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:154
void SetUserRating(float userRating)
void setCurrentVideoFilter(const VideoFilterSettings &filter)
Definition: videolist.cpp:498
bool IsDefaultScreenshot(const QString &screenshot)
Definition: videoutils.cpp:136
Dialog asking for user confirmation.
uint visibleChildCount() const
const QString VIDEO_SCREENSHOT_DEFAULT
Definition: globals.cpp:27
VideoDialog::VideoListPtr GetSaved()
Definition: videodlg.cpp:831
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
static bool Exists()
Definition: videodlg.cpp:564
void OnVideoImageSetDone(VideoMetadata *metadata)
Definition: videodlg.cpp:3373
int GetSeason() const
QList< MythGenericTree * > * getAllChildren() const
const QString & GetHash() const
static VideoListDeathDelayPtr & GetSavedVideoList()
Definition: videodlg.cpp:841
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
const QString & GetFanart() const
const VideoMetadataListManager & getListCache() const
Definition: videolist.cpp:508
const VideoMetadataListManager & m_listManager
Definition: videodlg.cpp:658
uint GetYear() const
bool keyPressEvent(QKeyEvent *levent) override
Key event handler.
Definition: videodlg.cpp:638
void SetId(int id)
Optional MythNotification elements.
VideoDialog::VideoListPtr m_savedList
Definition: videodlg.cpp:816
void SwitchVideoGenreGroup()
Switch to Genre browse mode.
Definition: videodlg.cpp:2868
void SetData(QVariant data)
void SaveSetting(const QString &key, int newValue)
bool IsDefaultFanart(const QString &fanart)
Definition: videoutils.cpp:146
bool Create() override
void SetFanart(const QString &fanart)
MythUIStateType * m_studioState
Definition: videodlg.h:211
void SetRating(const QString &rating)
bool SetNodeByString(QStringList route)
Using a path based on the node string, set the currently selected node.
bool Create() override
Definition: videodlg.cpp:578
Image widget, displays a single image or multiple images in sequence.
Definition: mythuiimage.h:97
MythUIText * m_positionText
Definition: videodlg.h:198
MythUIBusyDialog * m_busyPopup
Definition: videodlg.h:188
QString GetDescription() const
void SwitchManager()
Switch to Video Manager View.
Definition: videodlg.cpp:2850
QMap< QString, int > m_notifications
Definition: videodlg.cpp:794
std::list< std::pair< QString, ParentalLevel::Level > > parental_level_map
Definition: videodlg.cpp:670
static VideoPlayerCommand AltPlayerFor(const VideoMetadata *item)
Basic menu dialog, message and a list of options.
QDate GetReleaseDate() const
int childCount(void) const
bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler, const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown_extensions)
Definition: dirscan.cpp:226
MythMenu * CreateMetadataBrowseMenu()
Create a MythMenu for MythVideo Metadata Browse modes.
Definition: videodlg.cpp:2635
void Reset()
Resets to default metadata.
MythUIImage * m_banner
Definition: videodlg.h:203
void deleteNode(MythGenericTree *child)
bool IsHostSet() const
void refreshData()
Reloads the tree without invalidating the data.
Definition: videodlg.cpp:1058
const QVariant GetData(void) const
MythGenericTree * GetTreeRoot()
Definition: videolist.cpp:523
MythGenericTree * getVisibleChildAt(uint reference) const
void UnRegister(void *from, int id, bool closeimemdiately=false)
Unregister the client.
QString GetFanart(MythGenericTree *node)
Find the Fanart for a given node.
Definition: videodlg.cpp:1971
const QString & GetDirector() const
void AllowInput(bool allow)
MythMenu * CreateViewMenu()
Create a MythMenu for MythVideo Views.
Definition: videodlg.cpp:2540
const QString & GetBanner() const
MythScreenStack * GetStack(const QString &stackname)
VideoDialog::VideoListPtr VideoListPtr
Definition: videodlg.cpp:683
void SetDirector(const QString &director)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void dismissFetchDialog(VideoMetadata *metadata, bool ok)
Definition: videodlg.cpp:2141
void shiftParental(int amount)
Shift the parental level for the library by an integer amount.
Definition: videodlg.cpp:3239
void SwitchVideoInsertDateGroup()
Switch to Insert Date browse mode.
Definition: videodlg.cpp:2931
MythScreenStack * GetMainStack()
std::vector< country_entry > country_list
Definition: videometadata.h:33
bool IsDefaultCoverFile(const QString &coverfile)
Definition: videoutils.cpp:127
MythUIButtonListItem * GetItemAt(int pos) const
void UpdateText(MythUIButtonListItem *)
Update the visible text values for a given ButtonListItem.
Definition: videodlg.cpp:2332
QList< PersonInfo > GetPeople(PeopleType type) const
MythGenericTree * m_rootNode
Definition: videodlg.cpp:773
QStringList GetVideoDirsByHost(const QString &host)
Definition: videoutils.cpp:80
bool Create() override
Definition: videopopups.cpp:49
void PromptToScan()
Definition: videodlg.cpp:3824
static MythThemedMenu * menu
void SetGenres(const genre_list &genres)
void SwitchTree()
Switch to Tree (List) View.
Definition: videodlg.cpp:2823
QString GetFirstImage(MythGenericTree *node, const QString &type, const QString &gpnode=QString(), int levels=0)
Find the first image of "type" within a folder structure.
Definition: videodlg.cpp:1770
void SetStudio(const QString &studio)
static guint32 * tmp
Definition: goom_core.c:35
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
virtual MythUIButtonListItem * GetItemCurrent()
Definition: videodlg.cpp:3386
void RemoveItem(MythUIButtonListItem *item)
void BuildFocusList(void)
unsigned int GetID() const
void SetYear(int year)
virtual void handleFile(const QString &file_name, const QString &fq_file_name, const QString &extension, const QString &host)=0
static Type kEventType
Definition: mythdialogbox.h:50
void SetTagline(const QString &tagline)
void SetImage(MythImage *image, const QString &name="")
Sets an image directly, should only be used in special circumstances since it bypasses the cache.
bool Create() override
Definition: videopopups.cpp:13
MythScreenStack * m_mainStack
Definition: videodlg.h:190
const QString & GetTrailer() const
QString GetSubtitle() const
void CheckedSet(MythUIStateType *uiItem, const QString &state)
Definition: videoutils.cpp:44
QStringList GetStudios() const
QString m_lastTreeNodePath
Definition: videodlg.cpp:793
VideoListDeathDelayPrivate(const VideoDialog::VideoListPtr &toSave)
Definition: videodlg.cpp:805
float GetUserRating() const
uint GetSeason() const
MetadataLookupList m_results
VideoListDeathDelay(const VideoDialog::VideoListPtr &toSave)
Definition: videodlg.cpp:819
QString GetTitle() const
const QString & GetHomepage() const
MetadataFactory * m_metadataFactory
Definition: videodlg.h:213
bool goBack()
Move one level up in the tree.
Definition: videodlg.cpp:2279
MythScreenStack * m_popupStack
Definition: videodlg.h:189
void ShowHomepage()
Definition: videodlg.cpp:3027
virtual void Close()
ParentalLevel::Level GetShowLevel() const
int GetYear() const
QString GetText(const QString &name="") const
uint GetEpisode() const
void SwitchLayout(DialogType type, BrowseType browse)
Handle a layout or browse mode switch.
Definition: videodlg.cpp:2949
bool Create() override
MythMenu * CreateManageMenu()
Create a MythMenu for metadata management.
Definition: videodlg.cpp:2705
MythUIStateType * m_trailerState
Definition: videodlg.h:206
void ToggleProcess()
Definition: videodlg.cpp:2724
bool OnKeyAction(const QStringList &actions)
Definition: videodlg.cpp:621
virtual MythUIButtonListItem * GetItemByMetadata(VideoMetadata *metadata)
Definition: videodlg.cpp:3396
void SetCoverFile(const QString &coverFile)
void ClearMap(InfoMap &metadataMap)
void VideoAutoSearch(MythGenericTree *node=nullptr)
Definition: videodlg.cpp:3451
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
virtual void SetVisible(bool visible)
QString GetTagline() const
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void Load() override
Called after the screen is created by MythScreenStack.
Definition: videodlg.cpp:1045
MythUIStateType * m_parentalLevelState
Definition: videodlg.h:207
void setParentalLevel(const ParentalLevel::Level &level)
Set the parental level for the library.
Definition: videodlg.cpp:3230
const QString & GetTagline() const
virtual DirectoryHandler * newDir(const QString &dir_name, const QString &fq_dir_name)=0
void SwitchVideoTVMovieGroup()
Switch to Television/Movie browse mode.
Definition: videodlg.cpp:2940
ParentalLevelNotifyContainer m_parentalLevel
Definition: videodlg.cpp:762
QString GetScreenshot(MythGenericTree *node)
Find the Screenshot for a given node.
Definition: videodlg.cpp:1896
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
void ShowExtensionSettings()
Pop up a MythUI Menu for MythVideo filte Type Settings.
Definition: videodlg.cpp:2621
VideoMetadataPtr byFilename(const QString &file_name) const
float GetUserRating() const
void EditMetadata()
Definition: videodlg.cpp:3522
bool Create(void) override
void SetCountries(const country_list &countries)
const QString & GetPlot() const
void SwitchVideoUserRatingGroup()
Switch to User Rating browse mode.
Definition: videodlg.cpp:2922
MythUIText * m_titleText
Definition: videodlg.h:195
MythUIImage * m_fanart
Definition: videodlg.h:204
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
int GetEpisode() const
QString RemoteImageCheck(const QString &host, const QString &filename)
Search for a given (image) filename in the Video SG.
Definition: videodlg.cpp:1351
class VideoListDeathDelayPrivate * m_d
Definition: videodlg.h:236
static const uint16_t * d
bool GetProcessed() const
MythUIButtonTree * m_videoButtonTree
Definition: videodlg.h:193
QString GetSetting(const QString &key, const QString &defaultval="")
QStringList GetCountries() const
void SetEpisode(int episode)
void customEvent(QEvent *levent) override
Definition: videodlg.cpp:3285
QPointer< class VideoListDeathDelay > VideoListDeathDelayPtr
Definition: videodlg.h:46
void SwitchVideoYearGroup()
Switch to Year browse mode.
Definition: videodlg.cpp:2886
void AutomaticParentalAdjustment(VideoMetadata *metadata)
Definition: videodlg.cpp:739
void handleDynamicDirSelect(MythGenericTree *node)
Request the latest metadata for a folder.
Definition: videodlg.cpp:2777
void searchComplete(const QString &string)
After using incremental search, move to the selected item.
Definition: videodlg.cpp:2200
void ShowCastDialog()
Display the Cast if the selected item.
Definition: videodlg.cpp:3017
void SetReturnEvent(QObject *retobject, const QString &resultid)
void toMap(InfoMap &metadataMap)
void playVideoWithTrailers()
Play the selected item w/ a User selectable # of trailers.
Definition: videodlg.cpp:3178
void Reset(void) override
Reset the image back to the default defined in the theme.
static const int kDelayTimeMS
Definition: videodlg.h:230
virtual void SetTextFromMap(const InfoMap &infoMap)
void SwitchBrowse()
Switch to Browser View.
Definition: videodlg.cpp:2841
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
const QString & GetRating() const
void searchStart()
Create an incremental search dialog for the current tree level.
Definition: videodlg.cpp:2241
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
bool RemoteGetFileList(const QString &host, const QString &path, QStringList *list, QString sgroup, bool fileNamesOnly)
Definition: remoteutil.cpp:433
MythUIText * m_crumbText
Definition: videodlg.h:199
void SetText(const QString &text, const QString &name="", const QString &state="")
void SwitchVideoCategoryGroup()
Switch to Category browse mode.
Definition: videodlg.cpp:2877
VideoDialog::VideoListPtr GetSaved()
Definition: videodlg.cpp:810
void SwitchVideoDirectorGroup()
Switch to Director browse mode.
Definition: videodlg.cpp:2895
void SetInetRef(const QString &inetRef)
std::vector< genre_entry > genre_list
Definition: videometadata.h:32
QString GetInetref() const
void ShowPlayerSettings()
Pop up a MythUI Menu for MythVideo Player Settings.
Definition: videodlg.cpp:2593
static VideoPlayerCommand PlayerFor(const VideoMetadata *item)
const char * name
Definition: ParseText.cpp:328
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
void SwitchVideoFolderGroup()
Switch to Folder (filesystem) browse mode.
Definition: videodlg.cpp:2859
uint myth_system(const QString &command, uint flags, uint timeout)
void popupClosed(const QString &which, int result)
Definition: videodlg.cpp:2525
void OnVideoSearchDone(MetadataLookup *lookup)
Definition: videodlg.cpp:3686
void RemoveVideo()
Definition: videodlg.cpp:3540
void ToggleWatched()
Definition: videodlg.cpp:3480
MythMenu * CreateInfoMenu()
Create a MythMenu for Info pertaining to the selected item.
Definition: videodlg.cpp:2678
MythUIButton * m_playButton
Definition: videodlg.cpp:660
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
VideoMetadata * GetMetadata(MythUIButtonListItem *item)
Retrieve the Database Metadata for a given MythUIButtonListItem.
Definition: videodlg.cpp:3266
void InvalidateCache()
Definition: videolist.cpp:528
const QString & GetHost() const
void SetProcessed(bool processed)
void doVideoScan()
Definition: videodlg.cpp:3816
QVariant GetData() const
MythUIType * GetFocusWidget(void) const
void handleDirSelect(MythGenericTree *node)
Descend into a selected folder.
Definition: videodlg.cpp:2767
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:836
A single button widget.
Definition: mythuibutton.h:21
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
void Init() override
Definition: videodlg.cpp:1039
MythMainWindow * GetMythMainWindow(void)
void SetReleaseDate(QDate releasedate)
QString GetText(const QString &name="") const
const cast_list & GetCast() const
bool Create() override
Definition: videodlg.cpp:898
void OnRemoveVideo(bool)
Definition: videodlg.cpp:3560
void refreshList(bool filebrowser, const ParentalLevel &parental_level, bool flat_list, int group_type)
Definition: videolist.cpp:476
static const QString _Location
Definition: videodlg.cpp:54
void handleSelect(MythUIButtonListItem *)
Handle SELECT action for a given MythUIButtonListItem.
Definition: videodlg.cpp:2789
void SetTitle(const QString &title, const QString &sortTitle="")
MythMenu * CreatePlayMenu()
Create a "Play Menu" for MythVideo.
Definition: videodlg.cpp:2460
bool Create(void) override
int Register(void *from)
An application can register in which case it will be assigned a reusable screen, which can be modifie...
virtual void loadData()
load the data used to build the ButtonTree/List for MythVideo.
Definition: videodlg.cpp:1110
MythUIStateType * m_watchedState
Definition: videodlg.h:210
bool SetCurrentNode(MythGenericTree *node)
Set the currently selected node.
int getInt() const
QDate GetReleaseDate() const
int GetNumSetting(const QString &key, int defaultval=0)
bool Create() override
bool refreshNode(MythGenericTree *node)
Definition: videolist.cpp:483
void playFolder()
Play all the items in the selected folder.
Definition: videodlg.cpp:3094
void RemoveItem(MythUIButtonListItem *item, bool deleteNode=false)
Remove the item from the tree.
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
const QString & GetFilename() const
void ChangeFilter()
Change the filtering of the library.
Definition: videodlg.cpp:3249
void SetScreenshot(const QString &screenshot)
void SwitchVideoCastGroup()
Switch to Cast browse mode.
Definition: videodlg.cpp:2913
QString WatchedToState(bool watched)
Definition: videoutils.cpp:273
const QString VIDEO_DIRECTOR_UNKNOWN
Definition: globals.cpp:9
void SetWatched(bool watched)
MythUIButtonList * parent() const
void createBusyDialog(const QString &title)
Create a busy dialog, used during metadata search, etc.
Definition: videodlg.cpp:2101
bool GetBoolSetting(const QString &key, bool defaultval=false)
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
void createOkDialog(const QString &title)
Create a MythUI "OK" Dialog.
Definition: videodlg.cpp:2185
VideoDialog(MythScreenStack *lparent, const QString &lname, const VideoListPtr &video_list, DialogType type, BrowseType browse)
Definition: videodlg.cpp:846
void ResetMetadata()
Definition: videodlg.cpp:3595
bool Create(void) override
bool Create(void) override
void OnVideoSearchListSelection(const RefCountHandler< MetadataLookup > &lookup)
Definition: videodlg.cpp:3496
MythGenericTree * getChildByName(const QString &a_name) const
MythUIButtonListItem * GetItemCurrent(void) const
Return the currently selected list item.
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
VideoDialog::DialogType m_type
Definition: videodlg.cpp:782
bool AssignTree(MythGenericTree *tree)
Assign the root node of the tree to be displayed.
void Lookup(ProgramInfo *pginfo, bool automatic=true, bool getimages=true, bool allowgeneric=false)
QString GetHomepage() const
void reloadData()
Reloads the tree after having invalidated the data.
Definition: videodlg.cpp:1100
void VideoMenu()
Pop up a MythUI "Playback Menu" for MythVideo.
Definition: videodlg.cpp:2399
void SavePosition(void)
Definition: videodlg.cpp:874
void SwitchGallery()
Switch to Gallery View.
Definition: videodlg.cpp:2832
void SetShowLevel(ParentalLevel::Level showLevel)
VideoMetadataPtr byID(unsigned int db_id) const
void SetLength(int length)
uint GetRuntime() const
void SetSeason(int season)
QString generate_file_url(const QString &storage_group, const QString &host, const QString &path)
Definition: videoutils.h:65
void UpdatePosition()
Called after the screen is created by MythScreenStack.
Definition: videodlg.cpp:2315
MythGenericTree * getParent(void) const
static const char *const WINDOW_NAME
Definition: videodlg.cpp:656
const QString & GetScreenshot() const
T * get() const
Definition: quicksp.h:65
static void ClearGroupToUseCache(void)
void SetItemCurrent(MythUIButtonListItem *item)
void SwitchVideoStudioGroup()
Switch to Studio browse mode.
Definition: videodlg.cpp:2904
const QString VIDEO_RATING_DEFAULT
Definition: globals.cpp:30
const QString & GetSubtitle() const
void OnParentalChange(int amount)
Definition: videodlg.cpp:3504
bool SetFocusWidget(MythUIType *widget=nullptr)
void createFetchDialog(VideoMetadata *metadata)
Create a fetch notification, used during metadata search.
Definition: videodlg.cpp:2119
const QString & GetCoverFile() const
MythGenericTree * getChildAt(uint reference) const
static long int random(void)
Definition: compat.h:149
void becomeSelectedChild(void)
bool Create(void) override
void fetchVideos()
Build the buttonlist/tree.
Definition: videodlg.cpp:1312
void ToggleBrowseMode()
Toggle the browseable status for the selected item.
Definition: videodlg.cpp:2740
bool HandleMedia(const QString &handler, const QString &mrl, const QString &plot="", const QString &title="", const QString &subtitle="", const QString &director="", int season=0, int episode=0, const QString &inetref="", int lenMins=120, const QString &year="1895", const QString &id="", bool useBookmarks=false)
void VideoSearch(MythGenericTree *node=nullptr, bool automode=false)
Definition: videodlg.cpp:3429
Screen in which all other widgets are contained and rendered.
const QString VIDEO_FANART_DEFAULT
Definition: globals.cpp:29
bool Delete(int video_id)
Definition: videolist.cpp:518
int GetCurrentPos() const
const QString & GetInetRef() const
void playVideo()
Play the selected item.
Definition: videodlg.cpp:3071
const QString & GetStudio() const
void ViewPlot()
Display a MythUI Popup with the selected item's plot.
Definition: videodlg.cpp:2979
class VideoDialogPrivate * m_d
Definition: videodlg.h:215
const QString & GetTitle() const
void SetBanner(const QString &banner)
VideoScanner * m_scanner
Definition: videodlg.cpp:791
QString GetImageFromFolder(VideoMetadata *metadata)
Attempt to find/fallback a cover image for a given metadata item.
Definition: videodlg.cpp:1408
MetadataLookup * m_result
MythGenericTree * m_currentNode
Definition: videodlg.cpp:774
MythUIImage * m_screenshot
Definition: videodlg.h:202
void SetPlot(const QString &plot)
MythMenu * CreateSettingsMenu()
Create a MythMenu for MythVideo Settings.
Definition: videodlg.cpp:2576
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:37
VideoListPtr m_videoList
Definition: videodlg.cpp:771
void DisplayState(const QString &state, const QString &name)
void playTrailer()
Play the trailer associated with the selected item.
Definition: videodlg.cpp:3211
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
MythUIButton * m_doneButton
Definition: videodlg.cpp:661
VideoMetadata * m_metadata
Definition: videodlg.cpp:657
static VideoDialog::VideoListDeathDelayPtr m_savedPtr
Definition: videodlg.cpp:765
QStringList getRouteByString(void)
void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
Definition: dbaccess.cpp:816
MythUIImage * m_coverImage
Definition: videodlg.h:201
MythDialogBox * m_menuPopup
Definition: videodlg.h:187
void scanFinished(bool)
Definition: videodlg.cpp:1073
void DelayVideoListDestruction(const VideoListPtr &videoList)
Definition: videodlg.cpp:756
void DisplayMenu()
Pop up a MythUI Menu for MythVideo Global Functions.
Definition: videodlg.cpp:2498
QString GetBanner(MythGenericTree *node)
Find the Banner for a given node.
Definition: videodlg.cpp:1936
bool operator()(const parental_level_map::value_type &lhs, const parental_level_map::value_type &rhs) const
Definition: videodlg.cpp:676
VideoDialog::BrowseType m_browse
Definition: videodlg.cpp:783
void doScan(const QStringList &dirs)
Definition: videoscan.cpp:430
QString GetCertification() const
Provide a dialog to quickly find an entry in a list.
const QString VIDEO_BANNER_DEFAULT
Definition: globals.cpp:28
MythNotificationCenter * GetNotificationCenter(void)
MythUIButtonListItem * GetItemCurrent() const
bool IsDefaultBanner(const QString &banner)
Definition: videoutils.cpp:141
bool Create(void) override
QString ParentalLevelToState(const ParentalLevel &level)
Definition: videoutils.cpp:239
void SetCast(const cast_list &cast)
QString GetCoverImage(MythGenericTree *node)
A "hunt" for cover art to apply for a folder item.
Definition: videodlg.cpp:1546
void SetActive(bool active)
Set the widget active/inactive.