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 (const auto & md : m_metadata.getList())
377  if (filter.matches_filter(*md)) ++ret;
378  return ret;
379  }
380 
382  {
383  return m_metadata;
384  }
385 
386  unsigned int getFilterChangedState(void)
387  {
389  }
390 
391  bool Delete(unsigned int video_id, VideoList &/*dummy*/)
392  {
393  bool ret = false;
394  MetadataPtr mp = m_metadata.byID(video_id);
395  if (mp)
396  {
397  ret = mp->DeleteFile();
398  if (ret)
399  {
400  ret = m_metadata.purgeByID(video_id);
401  // Force refresh
403  }
404  }
405 
406  return ret;
407  }
408 
410  {
411  return m_videoTreeRoot.data();
412  }
413 
415  // Set the type to none to avoid refreshList thinking it doesn't
416  // need to.
418 
419  metadata_list ml;
421  m_metadata.setList(ml);
422  }
423 
424  private:
425  void sort_view_data(bool flat_list);
426  void fillMetadata(metadata_list_type whence);
427 
428  void buildFsysList(void);
429  void buildGroupList(metadata_list_type whence);
430  void buildDbList(void);
431  void buildTVList(void);
432  void buildFileList(smart_dir_node &directory, metadata_list &metalist,
433  const QString &prefix);
434 
435  void update_meta_view(bool flat_list);
436 
437  private:
438  bool m_listUnknown {false};
439  bool m_loadMetaData {false};
440 
441  QScopedPointer <MythGenericTree> m_videoTreeRoot;
442 
444  meta_dir_node m_metadataTree; // master list for tree views
445 
448 
450 
452 };
453 
455 {
456  m_imp = new VideoListImp;
457 }
458 
460 {
461  delete m_imp;
462 }
463 
465  bool filebrowser, bool flatlist,
466  int group_type, const ParentalLevel &parental_level,
467  bool include_updirs)
468 {
469  return m_imp->buildVideoList(filebrowser, flatlist,
470  group_type, parental_level, include_updirs);
471 }
472 
473 void VideoList::refreshList(bool filebrowser,
474  const ParentalLevel &parental_level,
475  bool flat_list, int group_type)
476 {
477  m_imp->refreshList(filebrowser, parental_level, flat_list, group_type);
478 }
479 
481 {
482  return m_imp->refreshNode(node);
483 }
484 
485 unsigned int VideoList::count(void) const
486 {
487  return m_imp->count();
488 }
489 
491 {
492  return m_imp->getCurrentVideoFilter();
493 }
494 
496 {
497  m_imp->setCurrentVideoFilter(filter);
498 }
499 
501 {
502  return m_imp->TryFilter(filter);
503 }
504 
506 {
507  return m_imp->getListCache();
508 }
509 
511 {
512  return m_imp->getFilterChangedState();
513 }
514 
515 bool VideoList::Delete(int video_id)
516 {
517  return m_imp->Delete(video_id, *this);
518 }
519 
521 {
522  return m_imp->GetTreeRoot();
523 }
524 
526 {
527  return m_imp->InvalidateCache();
528 }
529 
531 // VideoListImp
533 VideoListImp::VideoListImp() : m_metadataViewTree("", "top")
534 {
535  m_listUnknown = gCoreContext->GetBoolSetting("VideoListUnknownFileTypes", false);
536 
537  m_loadMetaData = gCoreContext->GetBoolSetting("VideoTreeLoadMetaData", false);
538 }
539 
541  bool include_updirs)
542 {
543  if (src->DataIsValid())
544  {
546  dst->SetData(src->GetData());
547  return;
548  }
549 
551  dir != src->dirs_end(); ++dir)
552  {
553  if ((*dir)->has_entries())
554  {
555  bool incUpDir = include_updirs;
556  // Only include upnodes when there is a parent to move up to
557  if (!dst->getParent())
558  incUpDir = false;
559 
561  dst, (*dir)->getName(),
562  (*dir)->getFQPath(), incUpDir, (*dir)->GetHost(),
563  (*dir)->GetPrefix());
564 
565  build_generic_tree(t, dir->get(), include_updirs);
566  }
567  }
568 
570  entry != src->entries_end(); ++entry)
571  {
572  if (((*entry)->getData()->GetSeason() > 0) ||
573  ((*entry)->getData()->GetEpisode() > 0))
574  {
575  QString seas = QString::number((*entry)->getData()->GetSeason());
576  QString ep = QString::number((*entry)->getData()->GetEpisode());
577  QString title = (*entry)->getData()->GetTitle();
578  QString subtitle = (*entry)->getData()->GetSubtitle();
579 
580  if (ep.size() < 2)
581  ep.prepend("0");
582 
583  QString displayTitle = QString("%1 %2x%3 - %4")
584  .arg(title).arg(seas).arg(ep).arg(subtitle);
585 
586  if (src->getName() == title)
587  {
588  displayTitle = QString("%2x%3 - %4")
589  .arg(seas).arg(ep).arg(subtitle);
590  }
591  AddFileNode(dst, displayTitle, (*entry)->getData());
592  }
593  else if ((*entry)->getData()->GetSubtitle().isEmpty())
594  {
595  AddFileNode(
596  dst, (*entry)->getData()->GetTitle(), (*entry)->getData());
597  }
598  else
599  {
600  QString TitleSub = QString("%1 - %2")
601  .arg((*entry)->getData()->GetTitle())
602  .arg((*entry)->getData()->GetSubtitle());
603  AddFileNode(dst, TitleSub, (*entry)->getData());
604  }
605  }
606 }
607 
608 // Build a generic tree containing the video files. You can control the
609 // contents and the shape of the tree in de following ways:
610 // filebrowser:
611 // If true, the actual state of the filesystem is examined. If a video
612 // is already known to the system, this info is retrieved. If not, some
613 // basic info is provided.
614 // If false, only video information already present in the database is
615 // presented.
616 // flatlist:
617 // If true, the tree is reduced to a single level containing all the
618 // videos found.
619 // If false, the hierarchy present on the filesystem or in the database
620 // is preserved. In this mode, both sub-dirs and updirs are present.
622  bool filebrowser, bool flatlist, int group_type,
623  const ParentalLevel &parental_level, bool include_updirs)
624 {
625  refreshList(filebrowser, parental_level, flatlist, group_type);
626 
627  m_videoTreeRoot.reset(new MythGenericTree(QObject::tr("Video Home"),
628  kRootNode, false));
629 
631  include_updirs);
632 
633  if (m_metadataViewFlat.empty())
634  {
635  m_videoTreeRoot.reset(new MythGenericTree(QObject::tr("Video Home"),
636  kRootNode, false));
637  m_videoTreeRoot.data()->addNode(QObject::tr("No files found"),
638  kNoFilesFound, false);
639  }
640 
641  return m_videoTreeRoot.data();
642 }
643 
645 {
646  if (!node)
647  return false;
648 
649  // node->GetData() provides information on how/where to refresh the
650  // data for this node
651 
652  QVariant data = node->GetData();
653  if (!data.isValid())
654  return false;
655 
656  // currently only UPNPScanner can refresh data
658  {
659  // force a refresh
661  return true;
662  }
663 
664  return false;
665 }
666 
667 void VideoListImp::refreshList(bool filebrowser,
668  const ParentalLevel &parental_level,
669  bool flat_list, int group_type)
670 {
671 
672  m_videoFilter.setParentalLevel(parental_level.GetLevel());
673 
674  if (filebrowser)
675  {
677  }
678  else
679  {
680  switch (group_type)
681  {
684  LOG(VB_GENERAL, LOG_DEBUG, "Using Folder mode");
685  break;
688  LOG(VB_GENERAL, LOG_DEBUG, "Using Genre mode");
689  break;
692  LOG(VB_GENERAL, LOG_DEBUG, "Using Category mode");
693  break;
696  LOG(VB_GENERAL, LOG_DEBUG, "Using Year mode");
697  break;
700  LOG(VB_GENERAL, LOG_DEBUG, "Using Director mode");
701  break;
704  LOG(VB_GENERAL, LOG_DEBUG, "Using Studio mode");
705  break;
708  LOG(VB_GENERAL, LOG_DEBUG, "Using Cast Mode");
709  break;
712  LOG(VB_GENERAL, LOG_DEBUG, "Using User Rating Mode");
713  break;
716  LOG(VB_GENERAL, LOG_DEBUG, "Using Insert Date Mode");
717  break;
720  LOG(VB_GENERAL, LOG_DEBUG, "Using TV/Movie Mode");
721  break;
722  default:
724  break;
725  }
726  }
727  update_meta_view(flat_list);
728 }
729 
730 void VideoListImp::sort_view_data(bool flat_list)
731 {
732  if (flat_list)
733  {
734  sort(m_metadataViewFlat.begin(), m_metadataViewFlat.end(),
736  }
737  else
738  {
741  }
742 }
743 
745 {
746  if (m_metadataListType != whence)
747  {
748  m_metadataListType = whence;
749  // flush existing data
750  metadata_list ml;
751  m_metadata.setList(ml);
753 
754  switch (whence)
755  {
756  case ltFileSystem:
757  buildFsysList();
758  break;
759  case ltDBMetadata:
760  buildDbList();
761  break;
762  case ltTVMetadata:
763  buildTVList();
764  break;
765  case ltDBGenreGroup:
766  case ltDBCategoryGroup:
767  case ltDBYearGroup:
768  case ltDBDirectorGroup:
769  case ltDBStudioGroup:
770  case ltDBCastGroup:
771  case ltDBUserRatingGroup:
772  case ltDBInsertDateGroup:
773  buildGroupList(whence);
774  break;
775  case ltNone:
776  break;
777  }
778  }
779 }
780 
782 {
783  metadata_list ml;
785  m_metadata.setList(ml);
786 
787  metadata_view_list mlist;
788  mlist.reserve(m_metadata.getList().size());
789 
790  back_insert_iterator<metadata_view_list> mli(mlist);
791  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
792  mli, to_metadata_ptr());
793 
795  sort(mlist.begin(), mlist.end(), mps);
796 
797  using group_to_node_map = map<QString, meta_dir_node *>;
798  group_to_node_map gtnm;
799 
800  meta_dir_node *video_root = &m_metadataTree;
801 
802  smart_dir_node sdn1 = video_root->addSubDir("All");
803  meta_dir_node* all_group_node = sdn1.get();
804 
805  for (auto data : mlist)
806  {
807  all_group_node->addEntry(smart_meta_node(new meta_data_node(data)));
808 
809  vector<QString> groups;
810 
811  switch (whence)
812  {
813  case ltDBGenreGroup:
814  {
815  vector<pair <int, QString> > genres =
816  data->GetGenres();
817 
818  for (const auto& item : genres)
819  groups.push_back(item.second);
820  break;
821  }
822  case ltDBCategoryGroup:
823  {
824  groups.push_back(data->GetCategory());
825  break;
826  }
827  case ltDBYearGroup:
828  {
829  groups.push_back(QString::number(data->GetYear()));
830  break;
831  }
832  case ltDBDirectorGroup:
833  {
834  groups.push_back(data->GetDirector());
835  break;
836  }
837  case ltDBStudioGroup:
838  {
839  groups.push_back(data->GetStudio());
840  break;
841  }
842  case ltDBCastGroup:
843  {
844  vector<pair<int, QString> > cast = data->GetCast();
845 
846  for (const auto& item : cast)
847  groups.push_back(item.second);
848  break;
849  }
850  case ltDBUserRatingGroup:
851  {
852  int i = data->GetUserRating();
853  groups.push_back(QString::number(i));
854  break;
855  }
856  case ltDBInsertDateGroup:
857  {
858  QDate date = data->GetInsertdate();
859  QString tmp = MythDate::toString(
861  groups.push_back(tmp);
862  break;
863  }
864  default:
865  {
866  LOG(VB_GENERAL, LOG_ERR, "Invalid type of grouping");
867  break;
868  }
869  }
870 
871  if (groups.empty())
872  {
873  meta_dir_node *group_node = gtnm["Unknown"];
874 
875  if (group_node == nullptr)
876  {
877  smart_dir_node sdn2 = video_root->addSubDir("Unknown");
878  group_node = sdn2.get();
879  gtnm["Unknown"] = group_node;
880  }
881 
882  group_node->addEntry(smart_meta_node(new meta_data_node(data)));
883  }
884 
885  for (const auto& item : groups)
886  {
887  meta_dir_node *group_node = gtnm[item];
888 
889  if (group_node == nullptr)
890  {
891  smart_dir_node sdn2 = video_root->addSubDir(item);
892  group_node = sdn2.get();
893  gtnm[item] = group_node;
894  }
895 
896  group_node->addEntry(smart_meta_node(new meta_data_node(data)));
897  }
898  }
899 }
900 
902 {
903  metadata_list ml;
905  m_metadata.setList(ml);
906 
907  metadata_view_list mlist;
908  mlist.reserve(m_metadata.getList().size());
909 
910  back_insert_iterator<metadata_view_list> mli(mlist);
911  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
912  mli, to_metadata_ptr());
913 
915  sort(mlist.begin(), mlist.end(), mps);
916 
917  meta_dir_node *video_root = &m_metadataTree;
918 
919  smart_dir_node sdn1 = video_root->addSubDir(QObject::tr("Television"));
920  meta_dir_node* television_node = sdn1.get();
921 
922  smart_dir_node vdn = video_root->addSubDir(QObject::tr("Movies"));
923  meta_dir_node* movie_node = vdn.get();
924 
925  for (auto & p : mlist)
926  {
927  VideoMetadata *data = p;
928 
929  if ((p->GetSeason() > 0) || (p->GetEpisode() > 0))
930  {
931  smart_dir_node sdn2 = television_node->addSubDir(p->GetTitle());
932  meta_dir_node* title_node = sdn2.get();
933 
934  smart_dir_node ssdn = title_node->addSubDir(
935  QObject::tr("Season %1").arg(p->GetSeason()));
936  meta_dir_node* season_node = ssdn.get();
937 
938  season_node->addEntry(smart_meta_node(new meta_data_node(data)));
939  }
940  else
941  movie_node->addEntry(smart_meta_node(new meta_data_node(data)));
942  }
943 }
944 
946 {
947  metadata_list ml;
949  m_metadata.setList(ml);
950 
951  metadata_view_list mlist;
952  mlist.reserve(m_metadata.getList().size());
953 
954  back_insert_iterator<metadata_view_list> mli(mlist);
955  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
956  mli, to_metadata_ptr());
957 
958 // print_meta_list(mlist);
959 
961  sort(mlist.begin(), mlist.end(), mps);
962 
963  // TODO: break out the prefix in the DB so this isn't needed
964  using prefix_to_node_map = map<QString, meta_dir_node *>;
965  prefix_to_node_map ptnm;
966 
967  QStringList dirs = GetVideoDirs();
968 
969  if (dirs.isEmpty())
970  return;
971 
972  QString test_prefix(dirs[0]);
973 
974  meta_dir_node *video_root = &m_metadataTree;
975  if (dirs.size() == 1)
976  {
977  video_root->setPathRoot();
978  video_root->setPath(test_prefix);
979  video_root->setName("videos");
980  ptnm.insert(prefix_to_node_map::value_type(test_prefix, video_root));
981  }
982 
983  for (auto & mv : mlist)
984  AddMetadataToDir(mv, video_root);
985 
986 // print_dir_tree(m_metadataTree); // AEW DEBUG
987 }
988 
990 {
991  //
992  // Fill metadata from directory structure
993  //
994 
995  using node_to_path_list = vector<pair<QString, QString> >;
996 
997  node_to_path_list node_paths;
998 
999  QStringList dirs = GetVideoDirs();
1000  if (dirs.size() > 1)
1001  {
1002  for (QStringList::const_iterator iter = dirs.begin();
1003  iter != dirs.end(); ++iter)
1004  {
1005  node_paths.push_back(
1006  node_to_path_list::value_type(path_to_node_name(*iter),
1007  *iter));
1008  }
1009  }
1010  else
1011  {
1012  node_paths.push_back(
1013  node_to_path_list::value_type(QObject::tr("videos"), dirs[0]));
1014  }
1015 
1016  //
1017  // Add all root-nodes to the tree.
1018  //
1019  metadata_list ml;
1020  for (auto & path : node_paths)
1021  {
1022  smart_dir_node root = m_metadataTree.addSubDir(path.second, path.first);
1023  root->setPathRoot();
1024 
1025  buildFileList(root, ml, path.second);
1026  }
1027 
1028  // retrieve any MediaServer data that may be available
1029  if (UPNPScanner::Instance())
1031 
1032  // See if we can find this filename in DB
1033  if (m_loadMetaData)
1034  {
1035  // Load the DB data so metadata lookups work
1036  // TODO: ugly, pass the list
1038  metadata_list db_metadata;
1040  mdlm.setList(db_metadata);
1041  for (auto & list : ml)
1042  list->FillDataFromFilename(mdlm);
1043  }
1044  m_metadata.setList(ml);
1045 }
1046 
1047 
1049  const VideoFilterSettings &filter)
1050 {
1051  for (auto e = src.entries_begin(); e != src.entries_end(); ++e)
1052  {
1053  if (filter.matches_filter(*((*e)->getData())))
1054  {
1055  dst.addEntry(
1056  smart_meta_node(new meta_data_node((*e)->getData())));
1057  }
1058  }
1059 }
1060 
1062  const VideoFilterSettings &filter)
1063 {
1064  copy_entries(dst, src, filter);
1065  for (auto dir = src.dirs_begin(); dir != src.dirs_end(); ++dir)
1066  {
1067  smart_dir_node sdn = dst.addSubDir((*dir)->getPath(),
1068  (*dir)->getName(),
1069  (*dir)->GetHost(),
1070  (*dir)->GetPrefix(),
1071  (*dir)->GetData());
1072  copy_filtered_tree(*sdn, *(dir->get()), filter);
1073  }
1074 }
1075 
1076 void tree_view_to_flat(meta_dir_node &tree,
1079 {
1081 
1083  {
1084  tree_view_to_flat(*(sdn.get()), m_list);
1085  }
1086 
1088 };
1089 
1090 // Fills a flat view with pointers to all entries in a tree.
1093 {
1094  back_insert_iterator<VideoListImp::metadata_view_list> bip(flat);
1095  transform(tree.entries_begin(), tree.entries_end(), bip,
1096  to_metadata_ptr());
1097 
1098  for_each(tree.dirs_begin(), tree.dirs_end(), call_tree_flat(flat));
1099 }
1100 
1102 {
1103  m_metadataViewFlat.clear();
1104  m_metadataViewFlat.reserve(m_metadata.getList().size());
1105 
1107 
1108  if (flat_list)
1109  {
1110  for (const auto & md : m_metadata.getList())
1111  {
1112  if (m_videoFilter.matches_filter(*md))
1113  {
1114  m_metadataViewFlat.push_back(md.get());
1115  }
1116  }
1117 
1118  sort_view_data(flat_list);
1119 
1120  for (auto & md : m_metadataViewFlat)
1122  }
1123  else
1124  {
1128  m_videoFilter);
1129 
1130  sort_view_data(flat_list);
1131 
1133  }
1134 }
1135 
1137 {
1138  public:
1139  using free_list = list<simple_ref_ptr<DirectoryHandler> >;
1140 
1141  public:
1142  dirhandler(smart_dir_node &directory, const QString &prefix,
1144  free_list &dh_free_list, bool infer_title) :
1145  m_directory(directory), m_prefix(prefix), m_metalist(metalist),
1146  m_dhFreeList(dh_free_list), m_inferTitle(infer_title)
1147  {
1148  }
1149 
1150  DirectoryHandler *newDir(const QString &dir_name,
1151  const QString &fq_dir_name) override // DirectoryHandler
1152  {
1153  (void) fq_dir_name;
1154  smart_dir_node dir = m_directory->addSubDir(dir_name);
1156  m_dhFreeList,
1157  m_inferTitle);
1158  m_dhFreeList.push_back(dh);
1159  return dh;
1160  }
1161 
1162  void handleFile(const QString &file_name,
1163  const QString &fq_file_name,
1164  const QString &extension)
1165  {
1166  handleFile(file_name, fq_file_name, extension, "");
1167  }
1168 
1169  void handleFile(const QString &file_name,
1170  const QString &fq_file_name,
1171  const QString &extension,
1172  const QString &host) override // DirectoryHandler
1173  {
1174  (void) file_name;
1175  (void) extension;
1176  const QString& file_string(fq_file_name);
1177 
1179  new VideoMetadata(file_string));
1180  QFileInfo qfi(file_string);
1181  QString title = qfi.completeBaseName();
1182  if (m_inferTitle)
1183  {
1184  QString tmptitle(VideoMetadata::FilenameToMeta(file_string, 1));
1185  if (tmptitle.length())
1186  title = tmptitle;
1187  }
1188  myData->SetTitle(title);
1189  myData->SetPrefix(m_prefix);
1190 
1191  myData->SetHost(host);
1192  m_metalist.push_back(myData);
1193 
1194  m_directory->addEntry(new meta_data_node(myData.get()));
1195  }
1196 
1197  private:
1199  const QString &m_prefix;
1202  const bool m_inferTitle;
1203 };
1204 
1206  smart_dir_node &directory, metadata_list &metalist, const QString &prefix)
1207 {
1210 
1212  dirhandler dh(directory, prefix, metalist, fl, false);
1213  (void) ScanVideoDirectory(
1214  directory->getFQPath(), &dh, ext_list, m_listUnknown);
1215 }
Level GetLevel() const
unsigned int count() const
Definition: videolist.cpp:485
MythGenericTree * buildVideoList(bool filebrowser, bool flatlist, int group_type, const ParentalLevel &parental_level, bool include_updirs)
Definition: videolist.cpp:464
TreeNodeDataPrivate(QString path, QString host, QString prefix)
Definition: videolist.cpp:41
bool DataIsValid(void) const
void fillMetadata(metadata_list_type whence)
Definition: videolist.cpp:744
const QString & GetSortFilename() const
VideoMetadata * operator()(const VideoMetadataListManager::VideoMetadataPtr &data)
Definition: videolist.cpp:265
void buildGroupList(metadata_list_type whence)
Definition: videolist.cpp:781
QStringList GetVideoDirs()
Definition: videoutils.cpp:120
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:495
QString GetHost() const
Definition: videolist.cpp:132
uint visibleChildCount() const
TreeNodeDataPrivate(VideoMetadata *metadata)
Definition: videolist.cpp:32
const metadata_list & getList() 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:505
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:1201
MythGenericTree * GetTreeRoot(void)
Definition: videolist.cpp:409
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:439
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:451
QString GetPath(void) const
Definition: videolist.cpp:56
void operator()(smart_dir_node &sdn)
Definition: videolist.cpp:1082
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:226
QString GetPrefix() const
Definition: videolist.cpp:139
const VideoFilterSettings & getCurrentVideoFilter() const
Definition: videolist.cpp:490
void GetImageMap(InfoMap &imageMap)
MythGenericTree * GetTreeRoot()
Definition: videolist.cpp:520
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
VideoMetadataListManager::metadata_list & m_metalist
Definition: videolist.cpp:1200
metadata_list_type m_metadataListType
Definition: videolist.cpp:449
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
meta_dir_node m_metadataTree
Definition: videolist.cpp:444
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:1087
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:386
void setName(const QString &name)
const QString & getPath() const override
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:1061
const QVariant & GetData() const
smart_dir_node m_directory
Definition: videolist.cpp:1198
QString GetText(const QString &name="") const
VideoMetadataListManager m_metadata
Definition: videolist.cpp:443
void SetImage(const QString &filename, const QString &name="")
void sort_view_data(bool flat_list)
Definition: videolist.cpp:730
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:510
void setPath(const QString &path, const QString &sortPath=nullptr)
void setList(metadata_list &list)
bool refreshNode(MythGenericTree *node)
Definition: videolist.cpp:644
bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
Definition: videolist.cpp:174
void buildDbList(void)
Definition: videolist.cpp:945
dirhandler(smart_dir_node &directory, const QString &prefix, VideoMetadataListManager::metadata_list &metalist, free_list &dh_free_list, bool infer_title)
Definition: videolist.cpp:1142
void tree_view_to_flat(meta_dir_node &tree, VideoListImp::metadata_view_list &flat)
Definition: videolist.cpp:1091
void InvalidateCache()
Definition: videolist.cpp:414
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:1205
void SetImageFromMap(const InfoMap &infoMap)
const bool m_inferTitle
Definition: videolist.cpp:1202
meta_dir_list::const_iterator const_dir_iterator
void toMap(InfoMap &metadataMap)
metadata_view_list m_metadataViewFlat
Definition: videolist.cpp:446
DirectoryHandler * newDir(const QString &dir_name, const QString &fq_dir_name) override
Definition: videolist.cpp:1150
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:1199
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:61
MythGenericTree * buildVideoList(bool filebrowser, bool flatlist, int group_type, const ParentalLevel &parental_level, bool include_updirs)
Definition: videolist.cpp:621
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:525
const QString & GetHost() const
static FileAssociations & getFileAssociation()
Definition: dbaccess.cpp:831
bool meta_less_than(const VideoMetadata &lhs, const VideoMetadata &rhs) const
Compares two VideoMetadata instances.
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:473
bool m_listUnknown
Definition: videolist.cpp:438
int TryFilter(const VideoFilterSettings &filter) const
Definition: videolist.cpp:500
int getInt() const
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:155
bool refreshNode(MythGenericTree *node)
Definition: videolist.cpp:480
#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:193
QVariant GetData(void) const
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:540
void update_meta_view(bool flat_list)
Definition: videolist.cpp:1101
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:667
void handleFile(const QString &file_name, const QString &fq_file_name, const QString &extension, const QString &host) override
Definition: videolist.cpp:1169
void GetStateMap(InfoMap &stateMap)
MythGenericTree * getParent(void) const
T * get() const
Definition: quicksp.h:65
const VideoMetadataListManager & getListCache(void) const
Definition: videolist.cpp:381
metadata_path_sort(void)=default
void handleFile(const QString &file_name, const QString &fq_file_name, const QString &extension)
Definition: videolist.cpp:1162
void setInt(int an_int)
void buildTVList(void)
Definition: videolist.cpp:901
QScopedPointer< MythGenericTree > m_videoTreeRoot
Definition: videolist.cpp:441
unsigned int getChangedState()
Definition: videofilter.h:213
bool purgeByID(unsigned int db_id)
bool Delete(int video_id)
Definition: videolist.cpp:515
class TreeNodeDataPrivate * m_d
Definition: videolist.h:84
void buildFsysList(void)
Definition: videolist.cpp:989
meta_dir_node m_metadataViewTree
Definition: videolist.cpp:447
list< simple_ref_ptr< DirectoryHandler > > free_list
Definition: videolist.cpp:1139
static void copy_entries(meta_dir_node &dst, meta_dir_node &src, const VideoFilterSettings &filter)
Definition: videolist.cpp:1048
int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity)
bool Delete(unsigned int video_id, VideoList &)
Definition: videolist.cpp:391
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:811
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:1080
void DisplayStateFromMap(const InfoMap &infoMap)
std::list< VideoMetadataPtr > metadata_list