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