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  bool sort(const VideoMetadata *lhs, const VideoMetadata *rhs)
186  {
187  return sort(lhs->GetSortFilename(), rhs->GetSortFilename());
188  }
189 
190  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  typedef vector<VideoMetadata *> metadata_view_list;
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_metadata_view_flat.size();
361  }
362 
364  {
365  return m_video_filter;
366  }
367 
369  {
370  m_video_filter = filter;
371  }
372 
373  int TryFilter(const VideoFilterSettings &filter) const
374  {
375  int ret = 0;
376  for (metadata_list::const_iterator p = m_metadata.getList().begin();
377  p != m_metadata.getList().end(); ++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 video_tree_root.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> video_tree_root;
445 
447  meta_dir_node m_metadata_tree; // 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_metadata_view_tree("", "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  video_tree_root.reset(new MythGenericTree(QObject::tr("Video Home"),
631  kRootNode, false));
632 
634  include_updirs);
635 
636  if (m_metadata_view_flat.empty())
637  {
638  video_tree_root.reset(new MythGenericTree(QObject::tr("Video Home"),
639  kRootNode, false));
640  video_tree_root.data()->addNode(QObject::tr("No files found"),
641  kNoFilesFound, false);
642  }
643 
644  return video_tree_root.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_video_filter.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_metadata_view_flat.begin(), m_metadata_view_flat.end(),
739  }
740  else
741  {
744  }
745 }
746 
748 {
749  if (m_metadata_list_type != whence)
750  {
751  m_metadata_list_type = 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  typedef map<QString, meta_dir_node *> group_to_node_map;
801  group_to_node_map gtnm;
802 
803  meta_dir_node *video_root = &m_metadata_tree;
804 
805  smart_dir_node sdn1 = video_root->addSubDir("All");
806  meta_dir_node* all_group_node = sdn1.get();
807 
808  for (metadata_view_list::iterator 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 (vector<pair <int, QString> >::iterator i =
824  genres.begin(); i != genres.end(); ++i)
825  {
826  pair<int, QString> item = *i;
827  groups.push_back(item.second);
828  }
829  break;
830  }
831  case ltDBCategoryGroup:
832  {
833  groups.push_back(data->GetCategory());
834  break;
835  }
836  case ltDBYearGroup:
837  {
838  groups.push_back(QString::number(data->GetYear()));
839  break;
840  }
841  case ltDBDirectorGroup:
842  {
843  groups.push_back(data->GetDirector());
844  break;
845  }
846  case ltDBStudioGroup:
847  {
848  groups.push_back(data->GetStudio());
849  break;
850  }
851  case ltDBCastGroup:
852  {
853  vector<pair<int, QString> > cast = data->GetCast();
854 
855  for (vector<pair<int, QString> >::iterator i =
856  cast.begin(); i != cast.end(); ++i)
857  {
858  pair<int, QString> item = *i;
859  groups.push_back(item.second);
860  }
861  break;
862  }
863  case ltDBUserRatingGroup:
864  {
865  int i = data->GetUserRating();
866  groups.push_back(QString::number(i));
867  break;
868  }
869  case ltDBInsertDateGroup:
870  {
871  QDate date = data->GetInsertdate();
872  QString tmp = MythDate::toString(
874  groups.push_back(tmp);
875  break;
876  }
877  default:
878  {
879  LOG(VB_GENERAL, LOG_ERR, "Invalid type of grouping");
880  break;
881  }
882  }
883 
884  if (groups.empty())
885  {
886  meta_dir_node *group_node = gtnm["Unknown"];
887 
888  if (group_node == nullptr)
889  {
890  smart_dir_node sdn2 = video_root->addSubDir("Unknown");
891  group_node = sdn2.get();
892  gtnm["Unknown"] = group_node;
893  }
894 
895  group_node->addEntry(smart_meta_node(new meta_data_node(data)));
896  }
897 
898  for (vector<QString>::iterator i = groups.begin();
899  i != groups.end(); ++i)
900  {
901  QString item = *i;
902 
903  meta_dir_node *group_node = gtnm[item];
904 
905  if (group_node == nullptr)
906  {
907  smart_dir_node sdn2 = video_root->addSubDir(item);
908  group_node = sdn2.get();
909  gtnm[item] = group_node;
910  }
911 
912  group_node->addEntry(smart_meta_node(new meta_data_node(data)));
913  }
914  }
915 }
916 
918 {
919  metadata_list ml;
921  m_metadata.setList(ml);
922 
923  metadata_view_list mlist;
924  mlist.reserve(m_metadata.getList().size());
925 
926  back_insert_iterator<metadata_view_list> mli(mlist);
927  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
928  mli, to_metadata_ptr());
929 
931  sort(mlist.begin(), mlist.end(), mps);
932 
933  meta_dir_node *video_root = &m_metadata_tree;
934 
935  smart_dir_node sdn1 = video_root->addSubDir(QObject::tr("Television"));
936  meta_dir_node* television_node = sdn1.get();
937 
938  smart_dir_node vdn = video_root->addSubDir(QObject::tr("Movies"));
939  meta_dir_node* movie_node = vdn.get();
940 
941  for (metadata_view_list::iterator p = mlist.begin(); p != mlist.end(); ++p)
942  {
943  VideoMetadata *data = *p;
944 
945  if (((*p)->GetSeason() > 0) || ((*p)->GetEpisode() > 0))
946  {
947  smart_dir_node sdn2 = television_node->addSubDir((*p)->GetTitle());
948  meta_dir_node* title_node = sdn2.get();
949 
950  smart_dir_node ssdn = title_node->addSubDir(
951  QObject::tr("Season %1").arg((*p)->GetSeason()));
952  meta_dir_node* season_node = ssdn.get();
953 
954  season_node->addEntry(smart_meta_node(new meta_data_node(data)));
955  }
956  else
957  movie_node->addEntry(smart_meta_node(new meta_data_node(data)));
958  }
959 }
960 
962 {
963  metadata_list ml;
965  m_metadata.setList(ml);
966 
967  metadata_view_list mlist;
968  mlist.reserve(m_metadata.getList().size());
969 
970  back_insert_iterator<metadata_view_list> mli(mlist);
971  transform(m_metadata.getList().begin(), m_metadata.getList().end(),
972  mli, to_metadata_ptr());
973 
974 // print_meta_list(mlist);
975 
977  sort(mlist.begin(), mlist.end(), mps);
978 
979  // TODO: break out the prefix in the DB so this isn't needed
980  typedef map<QString, meta_dir_node *> prefix_to_node_map;
981  prefix_to_node_map ptnm;
982 
983  QStringList dirs = GetVideoDirs();
984 
985  if (dirs.isEmpty())
986  return;
987 
988  QString test_prefix(dirs[0]);
989 
990  meta_dir_node *video_root = &m_metadata_tree;
991  if (dirs.size() == 1)
992  {
993  video_root->setPathRoot();
994  video_root->setPath(test_prefix);
995  video_root->setName("videos");
996  ptnm.insert(prefix_to_node_map::value_type(test_prefix, video_root));
997  }
998 
999  for (metadata_view_list::iterator p = mlist.begin(); p != mlist.end(); ++p)
1000  {
1001  AddMetadataToDir(*p, video_root);
1002  }
1003 
1004 // print_dir_tree(m_metadata_tree); // AEW DEBUG
1005 }
1006 
1008 {
1009  //
1010  // Fill metadata from directory structure
1011  //
1012 
1013  typedef vector<pair<QString, QString> > node_to_path_list;
1014 
1015  node_to_path_list node_paths;
1016 
1017  QStringList dirs = GetVideoDirs();
1018  if (dirs.size() > 1)
1019  {
1020  for (QStringList::const_iterator iter = dirs.begin();
1021  iter != dirs.end(); ++iter)
1022  {
1023  node_paths.push_back(
1024  node_to_path_list::value_type(path_to_node_name(*iter),
1025  *iter));
1026  }
1027  }
1028  else
1029  {
1030  node_paths.push_back(
1031  node_to_path_list::value_type(QObject::tr("videos"), dirs[0]));
1032  }
1033 
1034  //
1035  // Add all root-nodes to the tree.
1036  //
1037  metadata_list ml;
1038  for (node_to_path_list::iterator p = node_paths.begin();
1039  p != node_paths.end(); ++p)
1040  {
1041  smart_dir_node root = m_metadata_tree.addSubDir(p->second, p->first);
1042  root->setPathRoot();
1043 
1044  buildFileList(root, ml, p->second);
1045  }
1046 
1047  // retrieve any MediaServer data that may be available
1048  if (UPNPScanner::Instance())
1050 
1051  // See if we can find this filename in DB
1052  if (m_LoadMetaData)
1053  {
1054  // Load the DB data so metadata lookups work
1055  // TODO: ugly, pass the list
1057  metadata_list db_metadata;
1059  mdlm.setList(db_metadata);
1060  for (metadata_list::iterator p = ml.begin(); p != ml.end(); ++p)
1061  {
1062  (*p)->FillDataFromFilename(mdlm);
1063  }
1064  }
1065  m_metadata.setList(ml);
1066 }
1067 
1068 
1070  const VideoFilterSettings &filter)
1071 {
1073  e != src.entries_end(); ++e)
1074  {
1075  if (filter.matches_filter(*((*e)->getData())))
1076  {
1077  dst.addEntry(
1078  smart_meta_node(new meta_data_node((*e)->getData())));
1079  }
1080  }
1081 }
1082 
1084  const VideoFilterSettings &filter)
1085 {
1086  copy_entries(dst, src, filter);
1087  for (meta_dir_node::dir_iterator dir = src.dirs_begin();
1088  dir != src.dirs_end(); ++dir)
1089  {
1090  smart_dir_node sdn = dst.addSubDir((*dir)->getPath(),
1091  (*dir)->getName(),
1092  (*dir)->GetHost(),
1093  (*dir)->GetPrefix(),
1094  (*dir)->GetData());
1095  copy_filtered_tree(*sdn, *(dir->get()), filter);
1096  }
1097 }
1098 
1099 void tree_view_to_flat(meta_dir_node &tree,
1102 {
1104 
1106  {
1107  tree_view_to_flat(*(sdn.get()), m_list);
1108  }
1109 
1111 };
1112 
1113 // Fills a flat view with pointers to all entries in a tree.
1116 {
1117  back_insert_iterator<VideoListImp::metadata_view_list> bip(flat);
1118  transform(tree.entries_begin(), tree.entries_end(), bip,
1119  to_metadata_ptr());
1120 
1121  for_each(tree.dirs_begin(), tree.dirs_end(), call_tree_flat(flat));
1122 }
1123 
1125 {
1126  m_metadata_view_flat.clear();
1127  m_metadata_view_flat.reserve(m_metadata.getList().size());
1128 
1130 
1131  if (flat_list)
1132  {
1133  for (metadata_list::const_iterator p = m_metadata.getList().begin();
1134  p != m_metadata.getList().end(); ++p)
1135  {
1136  if (m_video_filter.matches_filter(*(*p)))
1137  {
1138  m_metadata_view_flat.push_back(p->get());
1139  }
1140  }
1141 
1142  sort_view_data(flat_list);
1143 
1144  for (metadata_view_list::iterator p = m_metadata_view_flat.begin();
1145  p != m_metadata_view_flat.end(); ++p)
1146  {
1148  }
1149  }
1150  else
1151  {
1155  m_video_filter);
1156 
1157  sort_view_data(flat_list);
1158 
1160  }
1161 }
1162 
1164 {
1165  public:
1166  typedef list<simple_ref_ptr<DirectoryHandler> > free_list;
1167 
1168  public:
1169  dirhandler(smart_dir_node &directory, const QString &prefix,
1171  free_list &dh_free_list, bool infer_title) :
1172  m_directory(directory), m_prefix(prefix), m_metalist(metalist),
1173  m_dh_free_list(dh_free_list), m_infer_title(infer_title)
1174  {
1175  }
1176 
1177  DirectoryHandler *newDir(const QString &dir_name,
1178  const QString &fq_dir_name) override // DirectoryHandler
1179  {
1180  (void) fq_dir_name;
1181  smart_dir_node dir = m_directory->addSubDir(dir_name);
1184  m_infer_title);
1185  m_dh_free_list.push_back(dh);
1186  return dh;
1187  }
1188 
1189  void handleFile(const QString &file_name,
1190  const QString &fq_file_name,
1191  const QString &extension)
1192  {
1193  handleFile(file_name, fq_file_name, extension, "");
1194  }
1195 
1196  void handleFile(const QString &file_name,
1197  const QString &fq_file_name,
1198  const QString &extension,
1199  const QString &host) override // DirectoryHandler
1200  {
1201  (void) file_name;
1202  (void) extension;
1203  const QString& file_string(fq_file_name);
1204 
1206  new VideoMetadata(file_string));
1207  QFileInfo qfi(file_string);
1208  QString title = qfi.completeBaseName();
1209  if (m_infer_title)
1210  {
1211  QString tmptitle(VideoMetadata::FilenameToMeta(file_string, 1));
1212  if (tmptitle.length())
1213  title = tmptitle;
1214  }
1215  myData->SetTitle(title);
1216  myData->SetPrefix(m_prefix);
1217 
1218  myData->SetHost(host);
1219  m_metalist.push_back(myData);
1220 
1221  m_directory->addEntry(new meta_data_node(myData.get()));
1222  }
1223 
1224  private:
1226  const QString &m_prefix;
1229  const bool m_infer_title;
1230 };
1231 
1233  smart_dir_node &directory, metadata_list &metalist, const QString &prefix)
1234 {
1237 
1239  dirhandler dh(directory, prefix, metalist, fl, false);
1240  (void) ScanVideoDirectory(
1241  directory->getFQPath(), &dh, ext_list, m_ListUnknown);
1242 }
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()
std::vector< std::pair< QString, bool > > ext_ignore_list
Definition: dbaccess.h:154
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
meta_dir_list::iterator dir_iterator
uint visibleChildCount() const
TreeNodeDataPrivate(VideoMetadata *metadata)
Definition: videolist.cpp:32
metadata_view_list m_metadata_view_flat
Definition: videolist.cpp:449
const metadata_list & getList() const
QDate GetInsertdate() const
bool m_ListUnknown
Definition: videolist.cpp:441
metadata sort function
Definition: videolist.cpp:147
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
meta_dir_list::const_iterator const_dir_iterator
meta_data_list::const_iterator const_entry_iterator
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...
bool m_LoadMetaData
Definition: videolist.cpp:442
VideoMetadata * GetMetadata(void)
Definition: videolist.cpp:46
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....
vector< VideoMetadata * > metadata_view_list
Definition: videolist.cpp:332
QString GetPath(void) const
Definition: videolist.cpp:56
void operator()(smart_dir_node &sdn)
Definition: videolist.cpp:1105
QString GetPrefix(void) const
Definition: videolist.cpp:66
VideoMetadataListManager::VideoMetadataPtr MetadataPtr
Definition: videolist.cpp:342
bool ScanVideoDirectory(const QString &start_path, DirectoryHandler *handler, const FileAssociations::ext_ignore_list &ext_disposition, bool list_unknown_extensions)
Definition: dirscan.cpp:226
simple_ref_ptr< meta_data_node > smart_meta_node
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
const bool m_infer_title
Definition: videolist.cpp:1229
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
VideoMetadataListManager::metadata_list & m_metalist
Definition: videolist.cpp:1227
void DisplayState(const QString &state, const QString &name="")
bool operator()(const VideoMetadata *lhs, const VideoMetadata *rhs)
Definition: videolist.cpp:151
VideoListImp::metadata_view_list & m_list
Definition: videolist.cpp:1110
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)
meta_dir_node m_metadata_view_tree
Definition: videolist.cpp:450
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)
metadata_list_type m_metadata_list_type
Definition: videolist.cpp:452
static void copy_filtered_tree(meta_dir_node &dst, meta_dir_node &src, const VideoFilterSettings &filter)
Definition: videolist.cpp:1083
const QVariant & GetData() const
smart_dir_node m_directory
Definition: videolist.cpp:1225
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
QScopedPointer< MythGenericTree > video_tree_root
Definition: videolist.cpp:444
void setPath(const QString &path, const QString &sortPath=nullptr)
list< simple_ref_ptr< DirectoryHandler > > free_list
Definition: videolist.cpp:1166
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:961
dirhandler(smart_dir_node &directory, const QString &prefix, VideoMetadataListManager::metadata_list &metalist, free_list &dh_free_list, bool infer_title)
Definition: videolist.cpp:1169
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
void tree_view_to_flat(meta_dir_node &tree, VideoListImp::metadata_view_list &flat)
Definition: videolist.cpp:1114
void InvalidateCache()
Definition: videolist.cpp:417
unsigned char t
Definition: ParseText.cpp:329
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:1232
Default local time.
Definition: mythdate.h:16
void SetImageFromMap(const InfoMap &infoMap)
void toMap(InfoMap &metadataMap)
DirectoryHandler * newDir(const QString &dir_name, const QString &fq_dir_name) override
Definition: videolist.cpp:1177
const VideoFilterSettings & getCurrentVideoFilter() const
Definition: videolist.cpp:363
const VideoMetadata * GetMetadata(void) const
Definition: videolist.cpp:51
const QString & m_prefix
Definition: videolist.cpp:1226
Do Today/Yesterday/Tomorrow transform.
Definition: mythdate.h:23
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
const char * name
Definition: ParseText.cpp:328
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:836
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
int TryFilter(const VideoFilterSettings &filter) const
Definition: videolist.cpp:503
int getInt() const
std::list< VideoMetadataPtr > metadata_list
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
meta_dir_node m_metadata_tree
Definition: videolist.cpp:447
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)
meta_data_list::iterator entry_iterator
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:1124
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
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:1196
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:1189
void setInt(int an_int)
void buildTVList(void)
Definition: videolist.cpp:917
VideoFilterSettings m_video_filter
Definition: videolist.cpp:454
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
free_list & m_dh_free_list
Definition: videolist.cpp:1228
const QString & GetStudio() const
bool sort(const VideoMetadata *lhs, const VideoMetadata *rhs)
Definition: videolist.cpp:185
class TreeNodeDataPrivate * m_d
Definition: videolist.h:83
void buildFsysList(void)
Definition: videolist.cpp:1007
static void copy_entries(meta_dir_node &dst, meta_dir_node &src, const VideoFilterSettings &filter)
Definition: videolist.cpp:1069
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:816
TreeNodeData()=default
void addEntry(const smart_meta_node &entry)
VideoMetadataListManager::metadata_list metadata_list
Definition: videolist.cpp:341
int TryFilter(const VideoFilterSettings &filter) const
Definition: videolist.cpp:373
bool sort(const QString &lhs, const QString &rhs)
Definition: videolist.cpp:190
call_tree_flat(VideoListImp::metadata_view_list &list)
Definition: videolist.cpp:1103
void DisplayStateFromMap(const InfoMap &infoMap)