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