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