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