MythTV  master
videolist.cpp
Go to the documentation of this file.
1 #include <algorithm>
2 #include <iterator>
3 #include <map>
4 using namespace std;
5 
6 #include <QFileInfo>
7 #include <QList>
8 #include <QScopedPointer>
9 #include <utility>
10 
11 #include "mythcontext.h"
12 #include "mythdate.h"
13 #include "mythmiscutil.h"
14 
15 #include "mythgenerictree.h"
17 #include "dbaccess.h"
18 #include "quicksp.h"
19 #include "dirscan.h"
20 #include "videoutils.h"
21 #include "parentalcontrols.h"
22 
23 #include "videofilter.h"
24 #include "videolist.h"
25 #include "videodlg.h"
26 
27 #include "upnpscanner.h"
28 
30 {
31  public:
32  explicit TreeNodeDataPrivate(VideoMetadata *metadata) :
33  m_metadata(metadata)
34  {
35  if (m_metadata)
36  m_host = m_metadata->GetHost();
37  else
38  m_host = "";
39  }
40 
41  TreeNodeDataPrivate(QString path, QString host, QString prefix) :
42  m_metadata(nullptr), m_host(std::move(host)), m_path(std::move(path)), m_prefix(std::move(prefix))
43  {
44  }
45 
47  {
48  return m_metadata;
49  }
50 
51  const VideoMetadata *GetMetadata(void) const
52  {
53  return m_metadata;
54  }
55 
56  QString GetPath(void) const
57  {
58  return m_path;
59  }
60 
61  QString GetHost(void) const
62  {
63  return m_host;
64  }
65 
66  QString GetPrefix(void) const
67  {
68  return m_prefix;
69  }
70 
71  private:
72  VideoMetadata *m_metadata {nullptr};
73  QString m_host;
74  QString m_path;
75  QString m_prefix;
76 };
77 
79 {
80  m_d = new TreeNodeDataPrivate(metadata);
81 }
82 
83 TreeNodeData::TreeNodeData(QString path, QString host, QString prefix)
84 {
85  m_d = new TreeNodeDataPrivate(std::move(path), std::move(host), std::move(prefix));
86 }
87 
88 TreeNodeData::TreeNodeData(const TreeNodeData &other) : m_d(nullptr)
89 {
90  *this = other;
91 }
92 
94 {
95  if (this != &rhs)
96  {
97  delete m_d;
98  m_d = new TreeNodeDataPrivate(*rhs.m_d);
99  }
100 
101  return *this;
102 }
103 
105 {
106  delete m_d;
107 }
108 
110 {
111  if (m_d)
112  return m_d->GetMetadata();
113 
114  return nullptr;
115 }
116 
118 {
119  if (m_d)
120  return m_d->GetMetadata();
121 
122  return nullptr;
123 }
124 
125 QString TreeNodeData::GetPath(void) const
126 {
127  if (m_d)
128  return m_d->GetPath();
129  return QString();
130 }
131 
132 QString TreeNodeData::GetHost(void) const
133 {
134  if (m_d)
135  return m_d->GetHost();
136  return QString();
137 }
138 
139 QString TreeNodeData::GetPrefix(void) const
140 {
141  if (m_d)
142  return m_d->GetPrefix();
143  return QString();
144 }
145 
148 {
149  explicit metadata_sort(const VideoFilterSettings &vfs) : m_vfs(vfs) {}
150 
151  bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
152  {
153  return m_vfs.meta_less_than(*lhs, *rhs);
154  }
155 
156  bool operator()(const smart_meta_node &lhs, const smart_meta_node &rhs)
157  {
158  return m_vfs.meta_less_than(*(lhs->getData()), *(rhs->getData()));
159  }
160 
161  private:
163 };
164 
166 {
167  explicit metadata_path_sort(void) = default;
168 
169  bool operator()(const VideoMetadata &lhs, const VideoMetadata &rhs)
170  {
171  return sort(&lhs, &rhs);
172  }
173 
174  bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
175  {
176  return sort(lhs, rhs);
177  }
178 
179  bool operator()(const smart_dir_node &lhs, const smart_dir_node &rhs)
180  {
181  return sort(lhs->getSortPath(), rhs->getSortPath());
182  }
183 
184  private:
185  static bool sort(const VideoMetadata *lhs, const VideoMetadata *rhs)
186  {
187  return sort(lhs->GetSortFilename(), rhs->GetSortFilename());
188  }
189 
190  static bool sort(const QString &lhs, const QString &rhs)
191  {
192  return naturalCompare(lhs, rhs) < 0;
193  }
194 };
195 
196 static QString path_to_node_name(const QString &path)
197 {
198  QString ret;
199  int slashLoc = path.lastIndexOf('/', -2) + 1;
200  if (path.endsWith("/"))
201  ret = path.mid(slashLoc, path.length() - slashLoc - 1);
202  else
203  ret = path.mid(slashLoc);
204 
205  return ret;
206 }
207 
209  meta_dir_node *dir,
210  meta_dir_node *hint = nullptr)
211 {
212  meta_dir_node *start = dir;
213  QString insert_chunk = metadata->GetFilename();
214  QString host = metadata->GetHost();
215  QString prefix = metadata->GetPrefix();
216 
217  if (hint)
218  {
219  if (metadata->GetFilename().startsWith(hint->getFQPath() + "/"))
220  {
221  start = hint;
222  insert_chunk =
223  metadata->GetFilename().mid(hint->getFQPath().length());
224  }
225  }
226 
227  if (insert_chunk.startsWith(dir->getFQPath() + "/"))
228  {
229  insert_chunk = metadata->GetFilename().mid(dir->getFQPath().length());
230  }
231 
232  QStringList path = insert_chunk.split("/", QString::SkipEmptyParts);
233  if (path.size() > 1)
234  {
235  path.pop_back();
236  }
237  else
238  {
239  path.clear();
240  }
241 
242  for (QStringList::const_iterator p = path.begin(); p != path.end(); ++p)
243  {
244  smart_dir_node sdn = start->addSubDir(*p, "" , host, prefix);
245  start = sdn.get();
246  }
247 
248  start->addEntry(smart_meta_node(new meta_data_node(metadata)));
249 
250  return start;
251 }
252 
254 {
256  {
257  return smn->getData();
258  }
259 
261  {
262  return &data;
263  }
264 
267  {
268  return data.get();
269  }
270 };
271 
273  MythGenericTree *where_to_add,
274  const QString& name, QString fqPath, bool add_up_dirs,
275  QString host = "", QString prefix = "")
276 {
277  // Add the subdir node...
278  MythGenericTree *sub_node =
279  where_to_add->addNode(name, kSubFolder, false);
280  sub_node->SetData(QVariant::fromValue(TreeNodeData(std::move(fqPath), std::move(host), std::move(prefix))));
281  sub_node->SetText(name, "title");
282  sub_node->DisplayState("subfolder", "nodetype");
283 
284  // ...and the updir node.
285  if (add_up_dirs)
286  {
287  MythGenericTree *up_node =
288  sub_node->addNode(where_to_add->GetText(), kUpFolder,
289  true, false);
290  up_node->DisplayState("subfolder", "nodetype");
291  }
292 
293  return sub_node;
294 }
295 
296 static int AddFileNode(MythGenericTree *where_to_add, const QString& name,
297  VideoMetadata *metadata)
298 {
299  MythGenericTree *sub_node = where_to_add->addNode(name, 0, true);
300  sub_node->SetData(QVariant::fromValue(TreeNodeData(metadata)));
301 
302  // Text
303  InfoMap textMap;
304  metadata->toMap(textMap);
305  sub_node->SetTextFromMap(textMap);
306 
307  // Images
308  InfoMap imageMap;
309  metadata->GetImageMap(imageMap);
310  sub_node->SetImageFromMap(imageMap);
311  sub_node->SetImage("buttonimage", imageMap["smartimage"]);
312 
313  // Assign images to parent node if this is the first child
314  if (where_to_add->visibleChildCount() == 1 &&
315  where_to_add->getInt() == kSubFolder)
316  {
317  where_to_add->SetImageFromMap(imageMap);
318  where_to_add->SetImage("buttonimage", imageMap["smartimage"]);
319  }
320 
321  // Statetypes
322  InfoMap stateMap;
323  metadata->GetStateMap(stateMap);
324  sub_node->DisplayStateFromMap(stateMap);
325 
326  return 1;
327 }
328 
330 {
331  public:
332  using metadata_view_list = vector<VideoMetadata *>;
333 
334  private:
343 
344  public:
345  VideoListImp();
346 
348  bool include_updirs);
350  bool filebrowser, bool flatlist,
351  int group_type, const ParentalLevel &parental_level,
352  bool include_updirs);
353 
354  void refreshList(bool filebrowser, const ParentalLevel &parental_level,
355  bool flat_list, int group_type);
356  bool refreshNode(MythGenericTree *node);
357 
358  unsigned int count(void) const
359  {
360  return m_metadataViewFlat.size();
361  }
362 
364  {
365  return m_videoFilter;
366  }
367 
369  {
370  m_videoFilter = filter;
371  }
372 
373  int TryFilter(const VideoFilterSettings &filter) const
374  {
375  int ret = 0;
376  for (auto p = m_metadata.getList().cbegin();
377  p != m_metadata.getList().cend(); ++p)
378  {
379  if (filter.matches_filter(**p)) ++ret;
380  }
381  return ret;
382  }
383 
385  {
386  return m_metadata;
387  }
388 
389  unsigned int getFilterChangedState(void)
390  {
392  }
393 
394  bool Delete(unsigned int video_id, VideoList &/*dummy*/)
395  {
396  bool ret = false;
397  MetadataPtr mp = m_metadata.byID(video_id);
398  if (mp)
399  {
400  ret = mp->DeleteFile();
401  if (ret)
402  {
403  ret = m_metadata.purgeByID(video_id);
404  // Force refresh
406  }
407  }
408 
409  return ret;
410  }
411 
413  {
414  return m_videoTreeRoot.data();
415  }
416 
418  // Set the type to none to avoid refreshList thinking it doesn't
419  // need to.
421 
422  metadata_list ml;
424  m_metadata.setList(ml);
425  }
426 
427  private:
428  void sort_view_data(bool flat_list);
429  void fillMetadata(metadata_list_type whence);
430 
431  void buildFsysList(void);
432  void buildGroupList(metadata_list_type whence);
433  void buildDbList(void);
434  void buildTVList(void);
435  void buildFileList(smart_dir_node &directory, metadata_list &metalist,
436  const QString &prefix);
437 
438  void update_meta_view(bool flat_list);
439 
440  private:
441  bool m_listUnknown {false};
442  bool m_loadMetaData {false};
443 
444  QScopedPointer <MythGenericTree> m_videoTreeRoot;
445 
447  meta_dir_node m_metadataTree; // master list for tree views
448 
451 
453 
455 };
456 
458 {
459  m_imp = new VideoListImp;
460 }
461 
463 {
464  delete m_imp;
465 }
466 
468  bool filebrowser, bool flatlist,
469  int group_type, const ParentalLevel &parental_level,
470  bool include_updirs)
471 {
472  return m_imp->buildVideoList(filebrowser, flatlist,
473  group_type, parental_level, include_updirs);
474 }
475 
476 void VideoList::refreshList(bool filebrowser,
477  const ParentalLevel &parental_level,
478  bool flat_list, int group_type)
479 {
480  m_imp->refreshList(filebrowser, parental_level, flat_list, group_type);
481 }
482 
484 {
485  return m_imp->refreshNode(node);
486 }
487 
488 unsigned int VideoList::count(void) const
489 {
490  return m_imp->count();
491 }
492 
494 {
495  return m_imp->getCurrentVideoFilter();
496 }
497 
499 {
500  m_imp->setCurrentVideoFilter(filter);
501 }
502 
504 {
505  return m_imp->TryFilter(filter);
506 }
507 
509 {
510  return m_imp->getListCache();
511 }
512 
514 {
515  return m_imp->getFilterChangedState();
516 }
517 
518 bool VideoList::Delete(int video_id)
519 {
520  return m_imp->Delete(video_id, *this);
521 }
522 
524 {
525  return m_imp->GetTreeRoot();
526 }
527 
529 {
530  return m_imp->InvalidateCache();
531 }
532 
534 // VideoListImp
536 VideoListImp::VideoListImp() : m_metadataViewTree("", "top")
537 {
538  m_listUnknown = gCoreContext->GetBoolSetting("VideoListUnknownFileTypes", false);
539 
540  m_loadMetaData = gCoreContext->GetBoolSetting("VideoTreeLoadMetaData", false);
541 }
542 
544  bool include_updirs)
545 {
546  if (src->DataIsValid())
547  {
549  dst->SetData(src->GetData());
550  return;
551  }
552 
554  dir != src->dirs_end(); ++dir)
555  {
556  if ((*dir)->has_entries())
557  {
558  bool incUpDir = include_updirs;
559  // Only include upnodes when there is a parent to move up to
560  if (!dst->getParent())
561  incUpDir = false;
562 
564  dst, (*dir)->getName(),
565  (*dir)->getFQPath(), incUpDir, (*dir)->GetHost(),
566  (*dir)->GetPrefix());
567 
568  build_generic_tree(t, dir->get(), include_updirs);
569  }
570  }
571 
573  entry != src->entries_end(); ++entry)
574  {
575  if (((*entry)->getData()->GetSeason() > 0) ||
576  ((*entry)->getData()->GetEpisode() > 0))
577  {
578  QString seas = QString::number((*entry)->getData()->GetSeason());
579  QString ep = QString::number((*entry)->getData()->GetEpisode());
580  QString title = (*entry)->getData()->GetTitle();
581  QString subtitle = (*entry)->getData()->GetSubtitle();
582 
583  if (ep.size() < 2)
584  ep.prepend("0");
585 
586  QString displayTitle = QString("%1 %2x%3 - %4")
587  .arg(title).arg(seas).arg(ep).arg(subtitle);
588 
589  if (src->getName() == title)
590  {
591  displayTitle = QString("%2x%3 - %4")
592  .arg(seas).arg(ep).arg(subtitle);
593  }
594  AddFileNode(dst, displayTitle, (*entry)->getData());
595  }
596  else if ((*entry)->getData()->GetSubtitle().isEmpty())
597  {
598  AddFileNode(
599  dst, (*entry)->getData()->GetTitle(), (*entry)->getData());
600  }
601  else
602  {
603  QString TitleSub = QString("%1 - %2")
604  .arg((*entry)->getData()->GetTitle())
605  .arg((*entry)->getData()->GetSubtitle());
606  AddFileNode(dst, TitleSub, (*entry)->getData());
607  }
608  }
609 }
610 
611 // Build a generic tree containing the video files. You can control the
612 // contents and the shape of the tree in de following ways:
613 // filebrowser:
614 // If true, the actual state of the filesystem is examined. If a video
615 // is already known to the system, this info is retrieved. If not, some
616 // basic info is provided.
617 // If false, only video information already present in the database is
618 // presented.
619 // flatlist:
620 // If true, the tree is reduced to a single level containing all the
621 // videos found.
622 // If false, the hierarchy present on the filesystem or in the database
623 // is preserved. In this mode, both sub-dirs and updirs are present.
625  bool filebrowser, bool flatlist, int group_type,
626  const ParentalLevel &parental_level, bool include_updirs)
627 {
628  refreshList(filebrowser, parental_level, flatlist, group_type);
629 
630  m_videoTreeRoot.reset(new MythGenericTree(QObject::tr("Video Home"),
631  kRootNode, false));
632 
634  include_updirs);
635 
636  if (m_metadataViewFlat.empty())
637  {
638  m_videoTreeRoot.reset(new MythGenericTree(QObject::tr("Video Home"),
639  kRootNode, false));
640  m_videoTreeRoot.data()->addNode(QObject::tr("No files found"),
641  kNoFilesFound, false);
642  }
643 
644  return m_videoTreeRoot.data();
645 }
646 
648 {
649  if (!node)
650  return false;
651 
652  // node->GetData() provides information on how/where to refresh the
653  // data for this node
654 
655  QVariant data = node->GetData();
656  if (!data.isValid())
657  return false;
658 
659  // currently only UPNPScanner can refresh data
661  {
662  // force a refresh
664  return true;
665  }
666 
667  return false;
668 }
669 
670 void VideoListImp::refreshList(bool filebrowser,
671  const ParentalLevel &parental_level,
672  bool flat_list, int group_type)
673 {
674 
675  m_videoFilter.setParentalLevel(parental_level.GetLevel());
676 
677  if (filebrowser)
678  {
680  }
681  else
682  {
683  switch (group_type)
684  {
687  LOG(VB_GENERAL, LOG_DEBUG, "Using Folder mode");
688  break;
691  LOG(VB_GENERAL, LOG_DEBUG, "Using Genre mode");
692  break;
695  LOG(VB_GENERAL, LOG_DEBUG, "Using Category mode");
696  break;
699  LOG(VB_GENERAL, LOG_DEBUG, "Using Year mode");
700  break;
703  LOG(VB_GENERAL, LOG_DEBUG, "Using Director mode");
704  break;
707  LOG(VB_GENERAL, LOG_DEBUG, "Using Studio mode");
708  break;
711  LOG(VB_GENERAL, LOG_DEBUG, "Using Cast Mode");
712  break;
715  LOG(VB_GENERAL, LOG_DEBUG, "Using User Rating Mode");
716  break;
719  LOG(VB_GENERAL, LOG_DEBUG, "Using Insert Date Mode");
720  break;
723  LOG(VB_GENERAL, LOG_DEBUG, "Using TV/Movie Mode");
724  break;
725  default:
727  break;
728  }
729  }
730  update_meta_view(flat_list);
731 }
732 
733 void VideoListImp::sort_view_data(bool flat_list)
734 {
735  if (flat_list)
736  {
737  sort(m_metadataViewFlat.begin(), m_metadataViewFlat.end(),
739  }
740  else
741  {
744  }
745 }
746 
748 {
749  if (m_metadataListType != whence)
750  {
751  m_metadataListType = whence;
752  // flush existing data
753  metadata_list ml;
754  m_metadata.setList(ml);
756 
757  switch (whence)
758  {
759  case ltFileSystem:
760  buildFsysList();
761  break;
762  case ltDBMetadata:
763  buildDbList();
764  break;
765  case ltTVMetadata:
766  buildTVList();
767  break;
768  case ltDBGenreGroup:
769  case ltDBCategoryGroup:
770  case ltDBYearGroup:
771  case ltDBDirectorGroup:
772  case ltDBStudioGroup:
773  case ltDBCastGroup:
774  case ltDBUserRatingGroup:
775  case ltDBInsertDateGroup:
776  buildGroupList(whence);
777  break;
778  case ltNone:
779  break;
780  }
781  }
782 }
783 
785 {
786  metadata_list ml;
788  m_metadata.setList(ml);
789 
790  metadata_view_list mlist;
791  mlist.reserve(m_metadata.getList().size());
792 
793  back_insert_iterator<metadata_view_list> mli(mlist);
794  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
795  mli, to_metadata_ptr());
796 
798  sort(mlist.begin(), mlist.end(), mps);
799 
800  using group_to_node_map = map<QString, meta_dir_node *>;
801  group_to_node_map gtnm;
802 
803  meta_dir_node *video_root = &m_metadataTree;
804 
805  smart_dir_node sdn1 = video_root->addSubDir("All");
806  meta_dir_node* all_group_node = sdn1.get();
807 
808  for (auto p = mlist.begin(); p != mlist.end(); ++p)
809  {
810  VideoMetadata *data = *p;
811 
812  all_group_node->addEntry(smart_meta_node(new meta_data_node(data)));
813 
814  vector<QString> groups;
815 
816  switch (whence)
817  {
818  case ltDBGenreGroup:
819  {
820  vector<pair <int, QString> > genres =
821  data->GetGenres();
822 
823  for (auto i = genres.begin(); i != genres.end(); ++i)
824  {
825  pair<int, QString> item = *i;
826  groups.push_back(item.second);
827  }
828  break;
829  }
830  case ltDBCategoryGroup:
831  {
832  groups.push_back(data->GetCategory());
833  break;
834  }
835  case ltDBYearGroup:
836  {
837  groups.push_back(QString::number(data->GetYear()));
838  break;
839  }
840  case ltDBDirectorGroup:
841  {
842  groups.push_back(data->GetDirector());
843  break;
844  }
845  case ltDBStudioGroup:
846  {
847  groups.push_back(data->GetStudio());
848  break;
849  }
850  case ltDBCastGroup:
851  {
852  vector<pair<int, QString> > cast = data->GetCast();
853 
854  for (auto i = cast.begin(); i != cast.end(); ++i)
855  {
856  pair<int, QString> item = *i;
857  groups.push_back(item.second);
858  }
859  break;
860  }
861  case ltDBUserRatingGroup:
862  {
863  int i = data->GetUserRating();
864  groups.push_back(QString::number(i));
865  break;
866  }
867  case ltDBInsertDateGroup:
868  {
869  QDate date = data->GetInsertdate();
870  QString tmp = MythDate::toString(
872  groups.push_back(tmp);
873  break;
874  }
875  default:
876  {
877  LOG(VB_GENERAL, LOG_ERR, "Invalid type of grouping");
878  break;
879  }
880  }
881 
882  if (groups.empty())
883  {
884  meta_dir_node *group_node = gtnm["Unknown"];
885 
886  if (group_node == nullptr)
887  {
888  smart_dir_node sdn2 = video_root->addSubDir("Unknown");
889  group_node = sdn2.get();
890  gtnm["Unknown"] = group_node;
891  }
892 
893  group_node->addEntry(smart_meta_node(new meta_data_node(data)));
894  }
895 
896  for (auto i = groups.begin(); i != groups.end(); ++i)
897  {
898  QString item = *i;
899 
900  meta_dir_node *group_node = gtnm[item];
901 
902  if (group_node == nullptr)
903  {
904  smart_dir_node sdn2 = video_root->addSubDir(item);
905  group_node = sdn2.get();
906  gtnm[item] = group_node;
907  }
908 
909  group_node->addEntry(smart_meta_node(new meta_data_node(data)));
910  }
911  }
912 }
913 
915 {
916  metadata_list ml;
918  m_metadata.setList(ml);
919 
920  metadata_view_list mlist;
921  mlist.reserve(m_metadata.getList().size());
922 
923  back_insert_iterator<metadata_view_list> mli(mlist);
924  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
925  mli, to_metadata_ptr());
926 
928  sort(mlist.begin(), mlist.end(), mps);
929 
930  meta_dir_node *video_root = &m_metadataTree;
931 
932  smart_dir_node sdn1 = video_root->addSubDir(QObject::tr("Television"));
933  meta_dir_node* television_node = sdn1.get();
934 
935  smart_dir_node vdn = video_root->addSubDir(QObject::tr("Movies"));
936  meta_dir_node* movie_node = vdn.get();
937 
938  for (auto p = mlist.begin(); p != mlist.end(); ++p)
939  {
940  VideoMetadata *data = *p;
941 
942  if (((*p)->GetSeason() > 0) || ((*p)->GetEpisode() > 0))
943  {
944  smart_dir_node sdn2 = television_node->addSubDir((*p)->GetTitle());
945  meta_dir_node* title_node = sdn2.get();
946 
947  smart_dir_node ssdn = title_node->addSubDir(
948  QObject::tr("Season %1").arg((*p)->GetSeason()));
949  meta_dir_node* season_node = ssdn.get();
950 
951  season_node->addEntry(smart_meta_node(new meta_data_node(data)));
952  }
953  else
954  movie_node->addEntry(smart_meta_node(new meta_data_node(data)));
955  }
956 }
957 
959 {
960  metadata_list ml;
962  m_metadata.setList(ml);
963 
964  metadata_view_list mlist;
965  mlist.reserve(m_metadata.getList().size());
966 
967  back_insert_iterator<metadata_view_list> mli(mlist);
968  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
969  mli, to_metadata_ptr());
970 
971 // print_meta_list(mlist);
972 
974  sort(mlist.begin(), mlist.end(), mps);
975 
976  // TODO: break out the prefix in the DB so this isn't needed
977  using prefix_to_node_map = map<QString, meta_dir_node *>;
978  prefix_to_node_map ptnm;
979 
980  QStringList dirs = GetVideoDirs();
981 
982  if (dirs.isEmpty())
983  return;
984 
985  QString test_prefix(dirs[0]);
986 
987  meta_dir_node *video_root = &m_metadataTree;
988  if (dirs.size() == 1)
989  {
990  video_root->setPathRoot();
991  video_root->setPath(test_prefix);
992  video_root->setName("videos");
993  ptnm.insert(prefix_to_node_map::value_type(test_prefix, video_root));
994  }
995 
996  for (auto p = mlist.begin(); p != mlist.end(); ++p)
997  {
998  AddMetadataToDir(*p, video_root);
999  }
1000 
1001 // print_dir_tree(m_metadataTree); // AEW DEBUG
1002 }
1003 
1005 {
1006  //
1007  // Fill metadata from directory structure
1008  //
1009 
1010  using node_to_path_list = vector<pair<QString, QString> >;
1011 
1012  node_to_path_list node_paths;
1013 
1014  QStringList dirs = GetVideoDirs();
1015  if (dirs.size() > 1)
1016  {
1017  for (QStringList::const_iterator iter = dirs.begin();
1018  iter != dirs.end(); ++iter)
1019  {
1020  node_paths.push_back(
1021  node_to_path_list::value_type(path_to_node_name(*iter),
1022  *iter));
1023  }
1024  }
1025  else
1026  {
1027  node_paths.push_back(
1028  node_to_path_list::value_type(QObject::tr("videos"), dirs[0]));
1029  }
1030 
1031  //
1032  // Add all root-nodes to the tree.
1033  //
1034  metadata_list ml;
1035  for (auto p = node_paths.begin(); p != node_paths.end(); ++p)
1036  {
1037  smart_dir_node root = m_metadataTree.addSubDir(p->second, p->first);
1038  root->setPathRoot();
1039 
1040  buildFileList(root, ml, p->second);
1041  }
1042 
1043  // retrieve any MediaServer data that may be available
1044  if (UPNPScanner::Instance())
1046 
1047  // See if we can find this filename in DB
1048  if (m_loadMetaData)
1049  {
1050  // Load the DB data so metadata lookups work
1051  // TODO: ugly, pass the list
1053  metadata_list db_metadata;
1055  mdlm.setList(db_metadata);
1056  for (auto p = ml.begin(); p != ml.end(); ++p)
1057  {
1058  (*p)->FillDataFromFilename(mdlm);
1059  }
1060  }
1061  m_metadata.setList(ml);
1062 }
1063 
1064 
1066  const VideoFilterSettings &filter)
1067 {
1068  for (auto e = src.entries_begin(); e != src.entries_end(); ++e)
1069  {
1070  if (filter.matches_filter(*((*e)->getData())))
1071  {
1072  dst.addEntry(
1073  smart_meta_node(new meta_data_node((*e)->getData())));
1074  }
1075  }
1076 }
1077 
1079  const VideoFilterSettings &filter)
1080 {
1081  copy_entries(dst, src, filter);
1082  for (auto dir = src.dirs_begin(); dir != src.dirs_end(); ++dir)
1083  {
1084  smart_dir_node sdn = dst.addSubDir((*dir)->getPath(),
1085  (*dir)->getName(),
1086  (*dir)->GetHost(),
1087  (*dir)->GetPrefix(),
1088  (*dir)->GetData());
1089  copy_filtered_tree(*sdn, *(dir->get()), filter);
1090  }
1091 }
1092 
1093 void tree_view_to_flat(meta_dir_node &tree,
1096 {
1098 
1100  {
1101  tree_view_to_flat(*(sdn.get()), m_list);
1102  }
1103 
1105 };
1106 
1107 // Fills a flat view with pointers to all entries in a tree.
1110 {
1111  back_insert_iterator<VideoListImp::metadata_view_list> bip(flat);
1112  transform(tree.entries_begin(), tree.entries_end(), bip,
1113  to_metadata_ptr());
1114 
1115  for_each(tree.dirs_begin(), tree.dirs_end(), call_tree_flat(flat));
1116 }
1117 
1119 {
1120  m_metadataViewFlat.clear();
1121  m_metadataViewFlat.reserve(m_metadata.getList().size());
1122 
1124 
1125  if (flat_list)
1126  {
1127  for (auto p = m_metadata.getList().cbegin();
1128  p != m_metadata.getList().cend(); ++p)
1129  {
1130  if (m_videoFilter.matches_filter(*(*p)))
1131  {
1132  m_metadataViewFlat.push_back(p->get());
1133  }
1134  }
1135 
1136  sort_view_data(flat_list);
1137 
1138  for (auto p = m_metadataViewFlat.begin();
1139  p != m_metadataViewFlat.end(); ++p)
1140  {
1142  }
1143  }
1144  else
1145  {
1149  m_videoFilter);
1150 
1151  sort_view_data(flat_list);
1152 
1154  }
1155 }
1156 
1158 {
1159  public:
1160  using free_list = list<simple_ref_ptr<DirectoryHandler> >;
1161 
1162  public:
1163  dirhandler(smart_dir_node &directory, const QString &prefix,
1165  free_list &dh_free_list, bool infer_title) :
1166  m_directory(directory), m_prefix(prefix), m_metalist(metalist),
1167  m_dhFreeList(dh_free_list), m_inferTitle(infer_title)
1168  {
1169  }
1170 
1171  DirectoryHandler *newDir(const QString &dir_name,
1172  const QString &fq_dir_name) override // DirectoryHandler
1173  {
1174  (void) fq_dir_name;
1175  smart_dir_node dir = m_directory->addSubDir(dir_name);
1177  m_dhFreeList,
1178  m_inferTitle);
1179  m_dhFreeList.push_back(dh);
1180  return dh;
1181  }
1182 
1183  void handleFile(const QString &file_name,
1184  const QString &fq_file_name,
1185  const QString &extension)
1186  {
1187  handleFile(file_name, fq_file_name, extension, "");
1188  }
1189 
1190  void handleFile(const QString &file_name,
1191  const QString &fq_file_name,
1192  const QString &extension,
1193  const QString &host) override // DirectoryHandler
1194  {
1195  (void) file_name;
1196  (void) extension;
1197  const QString& file_string(fq_file_name);
1198 
1200  new VideoMetadata(file_string));
1201  QFileInfo qfi(file_string);
1202  QString title = qfi.completeBaseName();
1203  if (m_inferTitle)
1204  {
1205  QString tmptitle(VideoMetadata::FilenameToMeta(file_string, 1));
1206  if (tmptitle.length())
1207  title = tmptitle;
1208  }
1209  myData->SetTitle(title);
1210  myData->SetPrefix(m_prefix);
1211 
1212  myData->SetHost(host);
1213  m_metalist.push_back(myData);
1214 
1215  m_directory->addEntry(new meta_data_node(myData.get()));
1216  }
1217 
1218  private:
1220  const QString &m_prefix;
1223  const bool m_inferTitle;
1224 };
1225 
1227  smart_dir_node &directory, metadata_list &metalist, const QString &prefix)
1228 {
1231 
1233  dirhandler dh(directory, prefix, metalist, fl, false);
1234  (void) ScanVideoDirectory(
1235  directory->getFQPath(), &dh, ext_list, m_listUnknown);
1236 }
Level GetLevel() const
unsigned int count() const
Definition: videolist.cpp:488
MythGenericTree * buildVideoList(bool filebrowser, bool flatlist, int group_type, const ParentalLevel &parental_level, bool include_updirs)
Definition: videolist.cpp:467
TreeNodeDataPrivate(QString path, QString host, QString prefix)
Definition: videolist.cpp:41
bool DataIsValid(void) const
void fillMetadata(metadata_list_type whence)
Definition: videolist.cpp:747
const QString & GetSortFilename() const
VideoMetadata * operator()(const VideoMetadataListManager::VideoMetadataPtr &data)
Definition: videolist.cpp:265
void buildGroupList(metadata_list_type whence)
Definition: videolist.cpp:784
QStringList GetVideoDirs()
Definition: videoutils.cpp:122
const QString & getFQPath()
VideoMetadata * operator()(VideoMetadata &data)
Definition: videolist.cpp:260
MythGenericTree * addNode(const QString &a_string, int an_int=0, bool selectable_flag=false, bool visible=true)
void setCurrentVideoFilter(const VideoFilterSettings &filter)
Definition: videolist.cpp:498
QString GetHost() const
Definition: videolist.cpp:132
uint visibleChildCount() const
TreeNodeDataPrivate(VideoMetadata *metadata)
Definition: videolist.cpp:32
const metadata_list & getList() const
QDate GetInsertdate() const
metadata sort function
Definition: videolist.cpp:147
meta_data_list::const_iterator const_entry_iterator
const QString & GetPrefix() const
static void loadAllFromDatabase(metadata_list &items, const QString &sql="")
Load videometadata database into memory.
const VideoMetadataListManager & getListCache() const
Definition: videolist.cpp:508
void SetText(const QString &text, const QString &name="", const QString &state="")
VideoMetadata * GetMetadata()
Definition: videolist.cpp:109
const QString & getSortPath() const
free_list & m_dhFreeList
Definition: videolist.cpp:1222
MythGenericTree * GetTreeRoot(void)
Definition: videolist.cpp:412
void GetMetadata(VideoMetadataListManager::metadata_list *list, meta_dir_node *node)
Fill the given metadata_list and meta_dir_node with the metadata of content retrieved from known medi...
static bool sort(const VideoMetadata *lhs, const VideoMetadata *rhs)
Definition: videolist.cpp:185
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
VideoMetadata * GetMetadata(void)
Definition: videolist.cpp:46
bool m_loadMetaData
Definition: videolist.cpp:442
void GetInitialMetadata(VideoMetadataListManager::metadata_list *list, meta_dir_node *node)
Fill the given metadata_list and meta_dir_node with the root media server metadata (i....
VideoFilterSettings m_videoFilter
Definition: videolist.cpp:454
QString GetPath(void) const
Definition: videolist.cpp:56
void operator()(smart_dir_node &sdn)
Definition: videolist.cpp:1099
QString GetPrefix(void) const
Definition: videolist.cpp:66
bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler, const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown_extensions)
Definition: dirscan.cpp:227
QString GetPrefix() const
Definition: videolist.cpp:139
const VideoFilterSettings & getCurrentVideoFilter() const
Definition: videolist.cpp:493
void GetImageMap(InfoMap &imageMap)
const QVariant GetData(void) const
MythGenericTree * GetTreeRoot()
Definition: videolist.cpp:523
const QString & GetDirector() const
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
VideoMetadataListManager::metadata_list & m_metalist
Definition: videolist.cpp:1221
metadata_list_type m_metadataListType
Definition: videolist.cpp:452
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
meta_dir_node m_metadataTree
Definition: videolist.cpp:447
void DisplayState(const QString &state, const QString &name="")
bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
Definition: videolist.cpp:151
VideoMetadataListManager::metadata_list metadata_list
Definition: videolist.cpp:341
VideoListImp::metadata_view_list & m_list
Definition: videolist.cpp:1104
QString GetHost(void) const
Definition: videolist.cpp:61
bool operator()(const smart_dir_node &lhs, const smart_dir_node &rhs)
Definition: videolist.cpp:179
static guint32 * tmp
Definition: goom_core.c:35
unsigned int getFilterChangedState(void)
Definition: videolist.cpp:389
void setName(const QString &name)
const QString & getPath() const override
const QString & GetCategory() const
VideoMetadata * operator()(smart_meta_node &smn)
Definition: videolist.cpp:255
void setPathRoot(bool is_root=true)
static bool sort(const QString &lhs, const QString &rhs)
Definition: videolist.cpp:190
static void copy_filtered_tree(meta_dir_node &dst, meta_dir_node &src, const VideoFilterSettings &filter)
Definition: videolist.cpp:1078
const QVariant & GetData() const
smart_dir_node m_directory
Definition: videolist.cpp:1219
int GetYear() const
QString GetText(const QString &name="") const
VideoMetadataListManager m_metadata
Definition: videolist.cpp:446
void SetImage(const QString &filename, const QString &name="")
void sort_view_data(bool flat_list)
Definition: videolist.cpp:733
void setCurrentVideoFilter(const VideoFilterSettings &filter)
Definition: videolist.cpp:368
void SetTextFromMap(const InfoMap &infoMap, const QString &state="")
entry_iterator entries_begin()
unsigned int getFilterChangedState()
Definition: videolist.cpp:513
void setPath(const QString &path, const QString &sortPath=nullptr)
void setList(metadata_list &list)
bool refreshNode(MythGenericTree *node)
Definition: videolist.cpp:647
float GetUserRating() const
bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
Definition: videolist.cpp:174
void buildDbList(void)
Definition: videolist.cpp:958
dirhandler(smart_dir_node &directory, const QString &prefix, VideoMetadataListManager::metadata_list &metalist, free_list &dh_free_list, bool infer_title)
Definition: videolist.cpp:1163
void tree_view_to_flat(meta_dir_node &tree, VideoListImp::metadata_view_list &flat)
Definition: videolist.cpp:1108
void InvalidateCache()
Definition: videolist.cpp:417
Default local time.
Definition: mythdate.h:16
static meta_dir_node * AddMetadataToDir(VideoMetadata *metadata, meta_dir_node *dir, meta_dir_node *hint=nullptr)
Definition: videolist.cpp:208
metadata_sort(const VideoFilterSettings &vfs)
Definition: videolist.cpp:149
bool operator()(const smart_meta_node &lhs, const smart_meta_node &rhs)
Definition: videolist.cpp:156
void buildFileList(smart_dir_node &directory, metadata_list &metalist, const QString &prefix)
Definition: videolist.cpp:1226
void SetImageFromMap(const InfoMap &infoMap)
const bool m_inferTitle
Definition: videolist.cpp:1223
meta_dir_list::const_iterator const_dir_iterator
void toMap(InfoMap &metadataMap)
metadata_view_list m_metadataViewFlat
Definition: videolist.cpp:449
DirectoryHandler * newDir(const QString &dir_name, const QString &fq_dir_name) override
Definition: videolist.cpp:1171
simple_ref_ptr< VideoMetadata > VideoMetadataPtr
const VideoFilterSettings & getCurrentVideoFilter() const
Definition: videolist.cpp:363
const VideoMetadata * GetMetadata(void) const
Definition: videolist.cpp:51
const QString & m_prefix
Definition: videolist.cpp:1220
static QString FilenameToMeta(const QString &file_name, int position)
QString GetPath() const
Definition: videolist.cpp:125
static MythGenericTree * AddDirNode(MythGenericTree *where_to_add, const QString &name, QString fqPath, bool add_up_dirs, QString host="", QString prefix="")
Definition: videolist.cpp:272
class VideoListImp * m_imp
Definition: videolist.h:60
MythGenericTree * buildVideoList(bool filebrowser, bool flatlist, int group_type, const ParentalLevel &parental_level, bool include_updirs)
Definition: videolist.cpp:624
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:101
bool matches_filter(const VideoMetadata &mdata) const
void InvalidateCache()
Definition: videolist.cpp:528
const QString & GetHost() const
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:832
bool meta_less_than(const VideoMetadata &lhs, const VideoMetadata &rhs) const
Compares two VideoMetadata instances.
const cast_list & GetCast() const
smart_dir_node addSubDir(const QString &subdir, const QString &name="", const QString &host="", const QString &prefix="", const QVariant &data=QVariant())
void sort(DirSort dir_sort, EntrySort entry_sort)
void refreshList(bool filebrowser, const ParentalLevel &parental_level, bool flat_list, int group_type)
Definition: videolist.cpp:476
bool m_listUnknown
Definition: videolist.cpp:441
int TryFilter(const VideoFilterSettings &filter) const
Definition: videolist.cpp:503
int getInt() const
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:154
bool refreshNode(MythGenericTree *node)
Definition: videolist.cpp:483
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool operator()(const VideoMetadata &lhs, const VideoMetadata &rhs)
Definition: videolist.cpp:169
const QString & GetFilename() const
void setParentalLevel(ParentalLevel::Level parental_level)
Definition: videofilter.h:195
simple_ref_ptr< meta_data_node > smart_meta_node
static int AddFileNode(MythGenericTree *where_to_add, const QString &name, VideoMetadata *metadata)
Definition: videolist.cpp:296
entry_iterator entries_end()
bool GetBoolSetting(const QString &key, bool defaultval=false)
static QString path_to_node_name(const QString &path)
Definition: videolist.cpp:196
void build_generic_tree(MythGenericTree *dst, meta_dir_node *src, bool include_updirs)
Definition: videolist.cpp:543
void update_meta_view(bool flat_list)
Definition: videolist.cpp:1118
unsigned int count(void) const
Definition: videolist.cpp:358
TreeNodeData & operator=(const TreeNodeData &rhs)
Definition: videolist.cpp:93
void SetData(QVariant data)
VideoMetadataPtr byID(unsigned int db_id) const
vector< VideoMetadata * > metadata_view_list
Definition: videolist.cpp:332
void refreshList(bool filebrowser, const ParentalLevel &parental_level, bool flat_list, int group_type)
Definition: videolist.cpp:670
void handleFile(const QString &file_name, const QString &fq_file_name, const QString &extension, const QString &host) override
Definition: videolist.cpp:1190
void GetStateMap(InfoMap &stateMap)
MythGenericTree * getParent(void) const
T * get() const
Definition: quicksp.h:65
const VideoMetadataListManager & getListCache(void) const
Definition: videolist.cpp:384
metadata_path_sort(void)=default
void handleFile(const QString &file_name, const QString &fq_file_name, const QString &extension)
Definition: videolist.cpp:1183
void setInt(int an_int)
void buildTVList(void)
Definition: videolist.cpp:914
QScopedPointer< MythGenericTree > m_videoTreeRoot
Definition: videolist.cpp:444
const genre_list & GetGenres() const
unsigned int getChangedState()
Definition: videofilter.h:215
bool purgeByID(unsigned int db_id)
bool Delete(int video_id)
Definition: videolist.cpp:518
const QString & GetStudio() const
class TreeNodeDataPrivate * m_d
Definition: videolist.h:83
void buildFsysList(void)
Definition: videolist.cpp:1004
meta_dir_node m_metadataViewTree
Definition: videolist.cpp:450
list< simple_ref_ptr< DirectoryHandler > > free_list
Definition: videolist.cpp:1160
static void copy_entries(meta_dir_node &dst, meta_dir_node &src, const VideoFilterSettings &filter)
Definition: videolist.cpp:1065
int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
bool Delete(unsigned int video_id, VideoList &)
Definition: videolist.cpp:394
static UPNPScanner * Instance(UPNPSubscription *sub=nullptr)
Returns the global UPNPScanner instance if it has been enabled or nullptr if UPNPScanner is currently...
const VideoFilterSettings & m_vfs
Definition: videolist.cpp:162
const QString & getName() const override
void getExtensionIgnoreList(ext_ignore_list &ext_ignore) const
Definition: dbaccess.cpp:812
TreeNodeData()=default
void addEntry(const smart_meta_node &entry)
int TryFilter(const VideoFilterSettings &filter) const
Definition: videolist.cpp:373
call_tree_flat(VideoListImp::metadata_view_list &list)
Definition: videolist.cpp:1097
void DisplayStateFromMap(const InfoMap &infoMap)
std::list< VideoMetadataPtr > metadata_list