00001 #include <qfileinfo.h>
00002
00003 #include <mythtv/mythcontext.h>
00004 #include <mythtv/uitypes.h>
00005 #include <mythtv/mythmediamonitor.h>
00006
00007 #include "videolist.h"
00008 #include "videofilter.h"
00009 #include "metadata.h"
00010 #include "metadatalistmanager.h"
00011 #include "dbaccess.h"
00012
00013 #include "quicksp.h"
00014 #include "dirscan.h"
00015 #include "videoutils.h"
00016 #include "parentalcontrols.h"
00017
00018 #include <memory>
00019 #include <algorithm>
00020 #include <iterator>
00021 #include <map>
00022
00023 namespace fake_unnamed
00024 {
00025 class meta_node
00026 {
00027 public:
00028 meta_node(meta_node *parent, bool is_path_root = false) :
00029 m_parent(parent), m_path_root(is_path_root) {}
00030 virtual ~meta_node() {}
00031
00032 virtual const QString &getName() const = 0;
00033
00034 virtual const QString &getPath() const
00035 {
00036 return m_empty_path;
00037 }
00038
00039 const QString &getFQPath()
00040 {
00041 if (m_fq_path.length())
00042 return m_fq_path;
00043
00044 if (m_parent && !m_path_root)
00045 m_fq_path = m_parent->getFQPath() + "/" + getPath();
00046 else
00047 {
00048 QString p = getPath();
00049 m_fq_path = ((p.length() && p[0] != '/') ? "/" : "") + p;
00050 }
00051
00052 return m_fq_path;
00053 }
00054
00055 void setParent(meta_node *parent)
00056 {
00057 m_parent = parent;
00058 }
00059
00060 void setPathRoot(bool is_root = true)
00061 {
00062 m_path_root = is_root;
00063 }
00064
00065 protected:
00066 meta_node *m_parent;
00067
00068 private:
00069 QString m_fq_path;
00070 bool m_path_root;
00071 static const QString m_empty_path;
00072 };
00073 const QString meta_node::m_empty_path;
00074
00075 class meta_data_node : public meta_node
00076 {
00077 public:
00078 meta_data_node(Metadata *data, meta_node *parent = NULL) :
00079 meta_node(parent), m_data(data)
00080 {
00081 }
00082
00083 const QString &getName() const
00084 {
00085 if (m_data)
00086 {
00087 return m_data->Title();
00088 }
00089
00090 return m_meta_bug;
00091 }
00092
00093 const Metadata *getData() const
00094 {
00095 return m_data;
00096 }
00097
00098 Metadata *getData()
00099 {
00100 return m_data;
00101 }
00102
00103 private:
00104 Metadata *m_data;
00105 static const QString m_meta_bug;
00106 };
00107 const QString meta_data_node::m_meta_bug = "Bug";
00108
00109 class meta_dir_node;
00110
00111 typedef simple_ref_ptr<meta_dir_node> smart_dir_node;
00112 typedef simple_ref_ptr<meta_data_node> smart_meta_node;
00113
00114 typedef std::list<smart_dir_node> meta_dir_list;
00115 typedef std::list<smart_meta_node> meta_data_list;
00116
00117 class meta_dir_node : public meta_node
00118 {
00119 public:
00120 typedef meta_dir_list::iterator dir_iterator;
00121 typedef meta_dir_list::const_iterator const_dir_iterator;
00122
00123 typedef meta_data_list::iterator entry_iterator;
00124 typedef meta_data_list::const_iterator const_entry_iterator;
00125
00126 public:
00127 meta_dir_node(const QString &path, const QString &name = "",
00128 meta_dir_node *parent = NULL, bool is_path_root = false) :
00129 meta_node(parent, is_path_root), m_path(path), m_name(name)
00130 {
00131 if (!name.length())
00132 {
00133 m_name = path;
00134 }
00135 }
00136
00137 meta_dir_node() : meta_node(NULL)
00138 {
00139 }
00140
00141 void setName(const QString &name)
00142 {
00143 m_name = name;
00144 }
00145
00146 const QString &getName() const
00147 {
00148 return m_name;
00149 }
00150
00151 const QString &getPath() const
00152 {
00153 return m_path;
00154 }
00155
00156 void setPath(const QString &path)
00157 {
00158 m_path = path;
00159 }
00160
00161 smart_dir_node addSubDir(const QString &subdir,
00162 const QString &name = "")
00163 {
00164 return getSubDir(subdir, name, true);
00165 }
00166
00167 void addSubDir(const smart_dir_node &subdir)
00168 {
00169 m_subdirs.push_back(subdir);
00170 }
00171
00172 smart_dir_node getSubDir(const QString &subdir,
00173 const QString &name = "", bool create = true)
00174 {
00175 for (meta_dir_list::const_iterator p = m_subdirs.begin();
00176 p != m_subdirs.end(); ++p)
00177 {
00178 if (subdir == (*p)->getPath())
00179 {
00180 return *p;
00181 }
00182 }
00183
00184 if (create)
00185 {
00186 smart_dir_node node(new meta_dir_node(subdir, name, this));
00187 m_subdirs.push_back(node);
00188 return node;
00189 }
00190
00191 return smart_dir_node();
00192 }
00193
00194 void addEntry(const smart_meta_node &entry)
00195 {
00196 entry->setParent(this);
00197 m_entries.push_back(entry);
00198 }
00199
00200 void clear()
00201 {
00202 m_subdirs.clear();
00203 m_entries.clear();
00204 }
00205
00206 bool empty() const
00207 {
00208 return m_subdirs.empty() && m_entries.empty();
00209 }
00210
00211 int subdir_count() const {
00212 return m_subdirs.size();
00213 }
00214
00215 template <typename DirSort, typename EntrySort>
00216 void sort(DirSort dir_sort, EntrySort entry_sort)
00217 {
00218 m_subdirs.sort(dir_sort);
00219 m_entries.sort(entry_sort);
00220
00221 for (meta_dir_list::iterator p = m_subdirs.begin();
00222 p != m_subdirs.end(); ++p)
00223 {
00224 (*p)->sort(dir_sort, entry_sort);
00225 }
00226 }
00227
00228 dir_iterator dirs_begin()
00229 {
00230 return m_subdirs.begin();
00231 }
00232
00233 dir_iterator dirs_end()
00234 {
00235 return m_subdirs.end();
00236 }
00237
00238 const_dir_iterator dirs_begin() const
00239 {
00240 return m_subdirs.begin();
00241 }
00242
00243 const_dir_iterator dirs_end() const
00244 {
00245 return m_subdirs.end();
00246 }
00247
00248 entry_iterator entries_begin()
00249 {
00250 return m_entries.begin();
00251 }
00252
00253 entry_iterator entries_end()
00254 {
00255 return m_entries.end();
00256 }
00257
00258 const_entry_iterator entries_begin() const
00259 {
00260 return m_entries.begin();
00261 }
00262
00263 const_entry_iterator entries_end() const
00264 {
00265 return m_entries.end();
00266 }
00267
00268
00269
00270 bool has_entries() const
00271 {
00272 bool ret = m_entries.size();
00273
00274 if (!ret)
00275 {
00276 for (meta_dir_list::const_iterator p = m_subdirs.begin();
00277 p != m_subdirs.end(); ++p)
00278 {
00279 ret = (*p)->has_entries();
00280 if (ret) break;
00281 }
00282 }
00283
00284 return ret;
00285 }
00286
00287 private:
00288 QString m_path;
00289 QString m_name;
00290 meta_dir_list m_subdirs;
00291 meta_data_list m_entries;
00292 };
00293
00295 struct metadata_sort
00296 {
00297 metadata_sort(const VideoFilterSettings &vfs, bool sort_ignores_case) :
00298 m_vfs(vfs), m_sic(sort_ignores_case) {}
00299
00300 bool operator()(const Metadata *lhs, const Metadata *rhs)
00301 {
00302 return m_vfs.meta_less_than(*lhs, *rhs, m_sic);
00303 }
00304
00305 bool operator()(const smart_meta_node &lhs, const smart_meta_node &rhs)
00306 {
00307 return m_vfs.meta_less_than(*(lhs->getData()), *(rhs->getData()),
00308 m_sic);
00309 }
00310
00311 private:
00312 const VideoFilterSettings &m_vfs;
00313 bool m_sic;
00314 };
00315
00316 struct metadata_path_sort
00317 {
00318 metadata_path_sort(bool ignore_case) : m_ignore_case(ignore_case) {}
00319
00320 bool operator()(const Metadata &lhs, const Metadata &rhs)
00321 {
00322 return sort(&lhs, &rhs);
00323 }
00324
00325 bool operator()(const Metadata *lhs, const Metadata *rhs)
00326 {
00327 return sort(lhs, rhs);
00328 }
00329
00330 bool operator()(const smart_dir_node &lhs, const smart_dir_node &rhs)
00331 {
00332 return sort(lhs->getPath(), rhs->getPath());
00333 }
00334
00335 private:
00336 bool sort(const Metadata *lhs, const Metadata *rhs)
00337 {
00338 return sort(lhs->Filename(), rhs->Filename());
00339 }
00340
00341 bool sort(const QString &lhs, const QString &rhs)
00342 {
00343 QString lhs_comp(lhs);
00344 QString rhs_comp(rhs);
00345 if (m_ignore_case)
00346 {
00347 lhs_comp = lhs_comp.lower();
00348 rhs_comp = rhs_comp.lower();
00349 }
00350 return QString::localeAwareCompare(lhs_comp, rhs_comp) < 0;
00351 }
00352
00353 bool m_ignore_case;
00354 };
00355
00356 QString path_to_node_name(const QString &path)
00357 {
00358 QString ret;
00359 int slashLoc = path.findRev("/", -2) + 1;
00360 if (path.right(1) == "/")
00361 ret = path.mid(slashLoc, path.length() - slashLoc - 2);
00362 else
00363 ret = path.mid(slashLoc);
00364
00365 return ret;
00366 }
00367
00368 meta_dir_node *AddMetadataToDir(Metadata *metadata, meta_dir_node *dir,
00369 meta_dir_node *hint = NULL)
00370 {
00371 meta_dir_node *start = dir;
00372 QString insert_chunk = metadata->Filename();
00373
00374 if (hint)
00375 {
00376 if (metadata->Filename().startsWith(hint->getFQPath() + "/"))
00377 {
00378 start = hint;
00379 insert_chunk =
00380 metadata->Filename().mid(hint->getFQPath().length());
00381 }
00382 }
00383
00384 if (insert_chunk.startsWith(dir->getFQPath() + "/"))
00385 {
00386 insert_chunk = metadata->Filename().mid(dir->getFQPath().length());
00387 }
00388
00389 QStringList path = QStringList::split("/", insert_chunk);
00390 if (path.size() > 1)
00391 {
00392 path.pop_back();
00393 }
00394 else
00395 {
00396 path.clear();
00397 }
00398
00399 for (QStringList::const_iterator p = path.begin(); p != path.end(); ++p)
00400 {
00401 smart_dir_node sdn = start->addSubDir(*p);
00402 start = sdn.get();
00403 }
00404
00405 start->addEntry(smart_meta_node(new meta_data_node(metadata)));
00406
00407 return start;
00408 }
00409
00410 struct to_metadata_ptr
00411 {
00412 Metadata *operator()(smart_meta_node &smn)
00413 {
00414 return smn->getData();
00415 }
00416
00417 Metadata *operator()(Metadata &data)
00418 {
00419 return &data;
00420 }
00421
00422 Metadata *operator()(const MetadataListManager::MetadataPtr &data)
00423 {
00424 return data.get();
00425 }
00426 };
00427
00428
00429
00430 enum NodeOrder {
00431 kOrderUp,
00432 kOrderSub,
00433 kOrderItem
00434 };
00435 }
00436 using namespace fake_unnamed;
00437
00438 class VideoListImp
00439 {
00440 public:
00441 typedef std::vector<Metadata *> metadata_view_list;
00442
00443 private:
00444 enum metadata_list_type { ltNone, ltFileSystem, ltDBMetadata };
00445 typedef MetadataListManager::metadata_list metadata_list;
00446 typedef MetadataListManager::MetadataPtr MetadataPtr;
00447
00448 public:
00449 VideoListImp();
00450
00451 void build_generic_tree(GenericTree *dst, meta_dir_node *src,
00452 bool include_updirs);
00453 GenericTree *buildVideoList(bool filebrowser, bool flatlist,
00454 const ParentalLevel &parental_level,
00455 bool include_updirs);
00456
00457 void refreshList(bool filebrowser, const ParentalLevel &parental_level,
00458 bool flat_list);
00459 void resortList(bool flat_list);
00460
00461 Metadata *getVideoListMetadata(int index);
00462
00463 unsigned int count() const
00464 {
00465 return m_metadata_view_flat.size();
00466 }
00467
00468 const VideoFilterSettings &getCurrentVideoFilter()
00469 {
00470 return m_video_filter;
00471 }
00472
00473 void setCurrentVideoFilter(const VideoFilterSettings &filter)
00474 {
00475 m_video_filter = filter;
00476 }
00477
00478 int test_filter(const VideoFilterSettings &filter) const
00479 {
00480 int ret = 0;
00481 for (metadata_list::const_iterator p = m_metadata.getList().begin();
00482 p != m_metadata.getList().end(); ++p)
00483 {
00484 if (filter.matches_filter(**p)) ++ret;
00485 }
00486 return ret;
00487 }
00488
00489 const MetadataListManager &getListCache() const
00490 {
00491 return m_metadata;
00492 }
00493
00494 QString getFolderPath(int folder_id) const
00495 {
00496 QString ret;
00497 id_string_map::const_iterator p = m_folder_id_to_path.find(folder_id);
00498 if (p != m_folder_id_to_path.end())
00499 ret = p->second;
00500 return ret;
00501 }
00502
00503 unsigned int getFilterChangedState()
00504 {
00505 return m_video_filter.getChangedState();
00506 }
00507
00508 bool Delete(unsigned int video_id)
00509 {
00510 bool ret = false;
00511 MetadataPtr mp = m_metadata.byID(video_id);
00512 if (mp)
00513 {
00514 ret = mp->deleteFile();
00515 if (ret) ret = m_metadata.purgeByID(video_id);
00516 }
00517
00518 return ret;
00519 }
00520
00521 private:
00522 void update_flat_index();
00523 void sort_view_data(bool flat_list);
00524 void fillMetadata(metadata_list_type whence);
00525
00526 void buildFsysList();
00527 void buildDbList();
00528 void buildFileList(smart_dir_node &directory, metadata_list &metalist,
00529 const QString &prefix);
00530
00531 GenericTree *addDirNode(GenericTree *where_to_add, const QString &dname,
00532 bool add_up_dirs);
00533 int addFileNode(GenericTree *where_to_add, const QString &name, int id);
00534
00535 void update_meta_view(bool flat_list);
00536
00537 private:
00538 bool m_ListUnknown;
00539 bool m_LoadMetaData;
00540
00541 std::auto_ptr<GenericTree> video_tree_root;
00542
00543 MetadataListManager m_metadata;
00544 meta_dir_node m_metadata_tree;
00545
00546 metadata_view_list m_metadata_view_flat;
00547 meta_dir_node m_metadata_view_tree;
00548
00549 metadata_list_type m_metadata_list_type;
00550
00551 VideoFilterSettings m_video_filter;
00552
00553 bool m_sort_ignores_case;
00554
00555
00556 typedef std::map<int, QString> id_string_map;
00557 id_string_map m_folder_id_to_path;
00558 int m_folder_id;
00559 };
00560
00561 VideoList::VideoList()
00562 {
00563 m_imp = new VideoListImp;
00564 }
00565
00566 VideoList::~VideoList()
00567 {
00568 delete m_imp;
00569 }
00570
00571 GenericTree *VideoList::buildVideoList(bool filebrowser, bool flatlist,
00572 const ParentalLevel &parental_level, bool include_updirs)
00573 {
00574 return m_imp->buildVideoList(filebrowser, flatlist, parental_level,
00575 include_updirs);
00576 }
00577
00578 void VideoList::refreshList(bool filebrowser,
00579 const ParentalLevel &parental_level, bool flat_list)
00580 {
00581 m_imp->refreshList(filebrowser, parental_level, flat_list);
00582 }
00583
00584 void VideoList::resortList(bool flat_list)
00585 {
00586 m_imp->resortList(flat_list);
00587 }
00588
00589 Metadata *VideoList::getVideoListMetadata(int index)
00590 {
00591 return m_imp->getVideoListMetadata(index);
00592 }
00593
00594 const Metadata *VideoList::getVideoListMetadata(int index) const
00595 {
00596 return m_imp->getVideoListMetadata(index);
00597 }
00598
00599 unsigned int VideoList::count() const
00600 {
00601 return m_imp->count();
00602 }
00603
00604 const VideoFilterSettings &VideoList::getCurrentVideoFilter()
00605 {
00606 return m_imp->getCurrentVideoFilter();
00607 }
00608
00609 void VideoList::setCurrentVideoFilter(const VideoFilterSettings &filter)
00610 {
00611 m_imp->setCurrentVideoFilter(filter);
00612 }
00613
00614 int VideoList::test_filter(const VideoFilterSettings &filter) const
00615 {
00616 return m_imp->test_filter(filter);
00617 }
00618
00619 const MetadataListManager &VideoList::getListCache() const
00620 {
00621 return m_imp->getListCache();
00622 }
00623
00624 QString VideoList::getFolderPath(int folder_id) const
00625 {
00626 return m_imp->getFolderPath(folder_id);
00627 }
00628
00629 unsigned int VideoList::getFilterChangedState()
00630 {
00631 return m_imp->getFilterChangedState();
00632 }
00633
00634 bool VideoList::Delete(int video_id)
00635 {
00636 return m_imp->Delete(video_id);
00637 }
00638
00640
00642 VideoListImp::VideoListImp() : m_metadata_view_tree("", "top"),
00643 m_metadata_list_type(ltNone)
00644 {
00645 m_ListUnknown = gContext->GetNumSetting("VideoListUnknownFileTypes", 1);
00646
00647 m_LoadMetaData = gContext->GetNumSetting("VideoTreeLoadMetaData", 0);
00648
00649 m_sort_ignores_case =
00650 gContext->GetNumSetting("mythvideo.sort_ignores_case", 1);
00651 }
00652
00653 void VideoListImp::build_generic_tree(GenericTree *dst, meta_dir_node *src,
00654 bool include_updirs)
00655 {
00656 for (meta_dir_node::const_dir_iterator dir = src->dirs_begin();
00657 dir != src->dirs_end(); ++dir)
00658 {
00659 if ((*dir)->has_entries())
00660 {
00661 GenericTree *t = addDirNode(dst, (*dir)->getName(), include_updirs);
00662 t->setAttribute(kFolderPath, m_folder_id);
00663 m_folder_id_to_path.
00664 insert(id_string_map::value_type(m_folder_id,
00665 (*dir)->getFQPath()));
00666 ++m_folder_id;
00667
00668 build_generic_tree(t, dir->get(), include_updirs);
00669 }
00670 }
00671
00672 for (meta_dir_node::const_entry_iterator entry = src->entries_begin();
00673 entry != src->entries_end(); ++entry)
00674 {
00675 addFileNode(dst, (*entry)->getData()->Title(),
00676 (*entry)->getData()->getFlatIndex());
00677 }
00678 }
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 GenericTree *VideoListImp::buildVideoList(bool filebrowser, bool flatlist,
00694 const ParentalLevel &parental_level,
00695 bool include_updirs)
00696 {
00697 refreshList(filebrowser, parental_level, flatlist);
00698
00699 typedef std::map<QString, GenericTree *> string_to_tree;
00700 string_to_tree prefix_tree_map;
00701
00702 video_tree_root.reset(new GenericTree("video root", kRootNode, false));
00703
00704 m_folder_id_to_path.clear();
00705 m_folder_id = 1;
00706 build_generic_tree(video_tree_root.get(), &m_metadata_view_tree,
00707 include_updirs);
00708
00709 if (m_metadata_view_flat.empty())
00710 {
00711 video_tree_root.reset(new GenericTree("video root", kRootNode, false));
00712 addDirNode(video_tree_root.get(), QObject::tr("No files found"),
00713 include_updirs);
00714 }
00715
00716 return video_tree_root.get();
00717 }
00718
00719 void VideoListImp::refreshList(bool filebrowser,
00720 const ParentalLevel &parental_level,
00721 bool flat_list)
00722 {
00723 m_video_filter.setParentalLevel(parental_level.GetLevel());
00724
00725 fillMetadata(filebrowser ? ltFileSystem : ltDBMetadata);
00726
00727 update_meta_view(flat_list);
00728 }
00729
00730 void VideoListImp::resortList(bool flat_list)
00731 {
00732 sort_view_data(flat_list);
00733 update_flat_index();
00734 }
00735
00736 Metadata *VideoListImp::getVideoListMetadata(int index)
00737 {
00738 if (index < 0)
00739 return NULL;
00740
00741 if ((unsigned int)index < m_metadata_view_flat.size())
00742 return m_metadata_view_flat[index];
00743
00744 VERBOSE(VB_IMPORTANT,
00745 QString("%1: getVideoListMetadata: index out of bounds: %2")
00746 .arg(__FILE__).arg(index));
00747 return NULL;
00748 }
00749
00750 void VideoListImp::update_flat_index()
00751 {
00752
00753
00754
00755 int flat_index = 0;
00756 for (metadata_view_list::iterator p = m_metadata_view_flat.begin();
00757 p != m_metadata_view_flat.end(); ++p)
00758 {
00759 (*p)->setFlatIndex(flat_index++);
00760 }
00761 }
00762
00763 void VideoListImp::sort_view_data(bool flat_list)
00764 {
00765 if (flat_list)
00766 {
00767 std::sort(m_metadata_view_flat.begin(), m_metadata_view_flat.end(),
00768 metadata_sort(m_video_filter, m_sort_ignores_case));
00769 }
00770 else
00771 {
00772 m_metadata_view_tree.sort(metadata_path_sort(m_sort_ignores_case),
00773 metadata_sort(m_video_filter,
00774 m_sort_ignores_case));
00775 }
00776 }
00777
00778 void VideoListImp::fillMetadata(metadata_list_type whence)
00779 {
00780 if (m_metadata_list_type != whence)
00781 {
00782 m_metadata_list_type = whence;
00783
00784 metadata_list ml;
00785 m_metadata.setList(ml);
00786 m_metadata_tree.clear();
00787
00788 if (whence == ltFileSystem)
00789 {
00790 buildFsysList();
00791 }
00792 else
00793 {
00794 buildDbList();
00795 }
00796 }
00797 }
00798
00799 void VideoListImp::buildDbList()
00800 {
00801 metadata_list ml;
00802 MetadataListManager::loadAllFromDatabase(ml);
00803 m_metadata.setList(ml);
00804
00805 metadata_view_list mlist;
00806 mlist.reserve(m_metadata.getList().size());
00807
00808 std::back_insert_iterator<metadata_view_list> mli(mlist);
00809 std::transform(m_metadata.getList().begin(), m_metadata.getList().end(),
00810 mli, to_metadata_ptr());
00811
00812
00813
00814 metadata_path_sort mps(m_sort_ignores_case);
00815 std::sort(mlist.begin(), mlist.end(), mps);
00816
00817
00818 typedef std::map<QString, meta_dir_node *> prefix_to_node_map;
00819 prefix_to_node_map ptnm;
00820
00821 QStringList dirs = GetVideoDirs();
00822 QString test_prefix(dirs[0]);
00823
00824 meta_dir_node *video_root = &m_metadata_tree;
00825 if (dirs.size() == 1)
00826 {
00827 video_root->setPathRoot();
00828 video_root->setPath(test_prefix);
00829 video_root->setName("videos");
00830 ptnm.insert(prefix_to_node_map::value_type(test_prefix, video_root));
00831 }
00832
00833 smart_dir_node unknown_prefix_root(new meta_dir_node("",
00834 QObject::tr("Unknown Prefix"),
00835 NULL, true));
00836
00837 meta_dir_node *insert_hint = NULL;
00838 for (metadata_view_list::iterator p = mlist.begin(); p != mlist.end(); ++p)
00839 {
00840 bool found_prefix = false;
00841 if ((*p)->Filename().startsWith(test_prefix))
00842 {
00843 found_prefix = true;
00844 }
00845 else
00846 {
00847 for (QStringList::const_iterator prefix = dirs.begin();
00848 prefix != dirs.end(); ++prefix)
00849 {
00850 if ((*p)->Filename().startsWith(*prefix))
00851 {
00852 test_prefix = *prefix;
00853 found_prefix = true;
00854 break;
00855 }
00856 }
00857 }
00858
00859 if (found_prefix)
00860 {
00861 meta_dir_node *insert_base;
00862 prefix_to_node_map::iterator np = ptnm.find(test_prefix);
00863 if (np == ptnm.end())
00864 {
00865 smart_dir_node sdn =
00866 video_root->addSubDir(test_prefix,
00867 path_to_node_name(test_prefix));
00868 insert_base = sdn.get();
00869 insert_base->setPathRoot();
00870
00871 ptnm.insert(prefix_to_node_map::value_type(test_prefix,
00872 insert_base));
00873 }
00874 else
00875 {
00876 insert_base = np->second;
00877 }
00878
00879 (*p)->setPrefix(test_prefix);
00880 insert_hint = AddMetadataToDir(*p, insert_base, insert_hint);
00881 }
00882 else
00883 {
00884 AddMetadataToDir(*p, unknown_prefix_root.get());
00885 }
00886 }
00887
00888 if (!unknown_prefix_root->empty())
00889 {
00890 video_root->addSubDir(unknown_prefix_root);
00891 }
00892
00893
00894 }
00895
00896 void VideoListImp::buildFsysList()
00897 {
00898
00899
00900
00901
00902 typedef std::vector<std::pair<QString, QString> > node_to_path_list;
00903
00904 node_to_path_list node_paths;
00905
00906 QStringList dirs = GetVideoDirs();
00907 if (dirs.size() > 1)
00908 {
00909 for (QStringList::iterator iter = dirs.begin(); iter != dirs.end();
00910 ++iter)
00911 {
00912 node_paths.push_back(
00913 node_to_path_list::value_type(path_to_node_name(*iter),
00914 *iter));
00915 }
00916 }
00917 else
00918 {
00919 node_paths.push_back(
00920 node_to_path_list::value_type(QObject::tr("videos"), dirs[0]));
00921 }
00922
00923
00924
00925
00926
00927 MediaMonitor *mon = MediaMonitor::GetMediaMonitor();
00928 if (mon)
00929 {
00930 QValueList <MythMediaDevice*> medias = mon->GetMedias(MEDIATYPE_DATA);
00931
00932 for (QValueList <MythMediaDevice*>::Iterator itr = medias.begin();
00933 itr != medias.end(); ++itr)
00934 {
00935 MythMediaDevice *pDev = *itr;
00936 if (mon->ValidateAndLock(pDev))
00937 {
00938 QString path = pDev->getMountPath();
00939 if (path.length())
00940 {
00941 VERBOSE(VB_GENERAL,
00942 QString("MythVideo: Adding MediaMonitor "
00943 "device: %1").arg(path));
00944 node_paths.push_back(node_to_path_list::
00945 value_type(path_to_node_name(path),
00946 path));
00947 }
00948
00949 mon->Unlock(pDev);
00950 }
00951 }
00952 }
00953
00954
00955
00956
00957 metadata_list ml;
00958 for (node_to_path_list::iterator p = node_paths.begin();
00959 p != node_paths.end(); ++p)
00960 {
00961 smart_dir_node root = m_metadata_tree.addSubDir(p->second, p->first);
00962 root->setPathRoot();
00963
00964 buildFileList(root, ml, p->second);
00965 }
00966
00967
00968 if (m_LoadMetaData)
00969 {
00970
00971
00972 MetadataListManager mdlm;
00973 metadata_list db_metadata;
00974 MetadataListManager::loadAllFromDatabase(db_metadata);
00975 mdlm.setList(db_metadata);
00976 for (metadata_list::iterator p = ml.begin(); p != ml.end(); ++p)
00977 {
00978 (*p)->fillDataFromFilename(mdlm);
00979 }
00980 }
00981 m_metadata.setList(ml);
00982 }
00983
00984 GenericTree *VideoListImp::addDirNode(GenericTree *where_to_add,
00985 const QString &dname, bool add_up_dirs)
00986 {
00987
00988 GenericTree *sub_node = where_to_add->addNode(dname, kSubFolder, false);
00989 sub_node->setAttribute(kNodeSort, kOrderSub);
00990 sub_node->setOrderingIndex(kNodeSort);
00991
00992
00993 if (add_up_dirs)
00994 {
00995 GenericTree *up_node = sub_node->addNode(where_to_add->getString(),
00996 kUpFolder, true);
00997 up_node->setAttribute(kNodeSort, kOrderUp);
00998 up_node->setOrderingIndex(kNodeSort);
00999 }
01000
01001 return sub_node;
01002 }
01003
01004 int VideoListImp::addFileNode(GenericTree *where_to_add, const QString &name,
01005 int index)
01006 {
01007 GenericTree *sub_node = where_to_add->addNode(name, index, true);
01008 sub_node->setAttribute(kNodeSort, kOrderItem);
01009 sub_node->setOrderingIndex(kNodeSort);
01010
01011 return 1;
01012 }
01013
01014 namespace fake_unnamed
01015 {
01016 void copy_entries(meta_dir_node &dst, meta_dir_node &src,
01017 const VideoFilterSettings &filter)
01018 {
01019 for (meta_dir_node::entry_iterator e = src.entries_begin();
01020 e != src.entries_end(); ++e)
01021 {
01022 if (filter.matches_filter(*((*e)->getData())))
01023 {
01024 dst.addEntry(
01025 smart_meta_node(new meta_data_node((*e)->getData())));
01026 }
01027 }
01028 }
01029
01030 void copy_filtered_tree(meta_dir_node &dst, meta_dir_node &src,
01031 const VideoFilterSettings &filter)
01032 {
01033 copy_entries(dst, src, filter);
01034 for (meta_dir_node::dir_iterator dir = src.dirs_begin();
01035 dir != src.dirs_end(); ++dir)
01036 {
01037 smart_dir_node sdn = dst.addSubDir((*dir)->getPath(),
01038 (*dir)->getName());
01039 copy_filtered_tree(*sdn, *(dir->get()), filter);
01040 }
01041 }
01042
01043 void tree_view_to_flat(meta_dir_node &tree,
01044 VideoListImp::metadata_view_list &flat);
01045 struct call_tree_flat
01046 {
01047 call_tree_flat(VideoListImp::metadata_view_list &list) : m_list(list) {}
01048
01049 void operator()(smart_dir_node &sdn)
01050 {
01051 tree_view_to_flat(*(sdn.get()), m_list);
01052 }
01053
01054 VideoListImp::metadata_view_list &m_list;
01055 };
01056
01057
01058 void tree_view_to_flat(meta_dir_node &tree,
01059 VideoListImp::metadata_view_list &flat)
01060 {
01061 std::back_insert_iterator<VideoListImp::metadata_view_list> bip(flat);
01062 std::transform(tree.entries_begin(), tree.entries_end(), bip,
01063 to_metadata_ptr());
01064
01065 std::for_each(tree.dirs_begin(), tree.dirs_end(), call_tree_flat(flat));
01066 }
01067 }
01068
01069 void VideoListImp::update_meta_view(bool flat_list)
01070 {
01071 m_metadata_view_flat.clear();
01072 m_metadata_view_flat.reserve(m_metadata.getList().size());
01073
01074 m_metadata_view_tree.clear();
01075
01076
01077
01078
01079 for (metadata_list::const_iterator si = m_metadata.getList().begin();
01080 si != m_metadata.getList().end(); ++si)
01081 {
01082 if (!(*si)->hasSortKey())
01083 {
01084 Metadata::SortKey skey =
01085 Metadata::GenerateDefaultSortKey(*(*si),
01086 m_sort_ignores_case);
01087 (*si)->setSortKey(skey);
01088 }
01089 }
01090
01091 if (flat_list)
01092 {
01093 for (metadata_list::const_iterator p = m_metadata.getList().begin();
01094 p != m_metadata.getList().end(); ++p)
01095 {
01096 if (m_video_filter.matches_filter(*(*p)))
01097 {
01098 m_metadata_view_flat.push_back(p->get());
01099 }
01100 }
01101
01102 sort_view_data(flat_list);
01103
01104 for (metadata_view_list::iterator p = m_metadata_view_flat.begin();
01105 p != m_metadata_view_flat.end(); ++p)
01106 {
01107 m_metadata_view_tree.addEntry(new meta_data_node(*p));
01108 }
01109 }
01110 else
01111 {
01112 m_metadata_view_tree.setPath(m_metadata_tree.getPath());
01113 m_metadata_view_tree.setName(m_metadata_tree.getName());
01114 copy_filtered_tree(m_metadata_view_tree, m_metadata_tree,
01115 m_video_filter);
01116
01117 sort_view_data(flat_list);
01118
01119 tree_view_to_flat(m_metadata_view_tree, m_metadata_view_flat);
01120 }
01121
01122 update_flat_index();
01123 }
01124
01125 namespace fake_unnamed
01126 {
01127 class dirhandler : public DirectoryHandler
01128 {
01129 public:
01130 typedef std::list<simple_ref_ptr<DirectoryHandler> > free_list;
01131
01132 public:
01133 dirhandler(smart_dir_node &directory, const QString &prefix,
01134 MetadataListManager::metadata_list &metalist,
01135 free_list &dh_free_list, bool infer_title) :
01136 m_directory(directory), m_prefix(prefix), m_metalist(metalist),
01137 m_dh_free_list(dh_free_list), m_infer_title(infer_title)
01138 {
01139 }
01140
01141 DirectoryHandler *newDir(const QString &dir_name,
01142 const QString &fq_dir_name)
01143 {
01144 (void)fq_dir_name;
01145 smart_dir_node dir = m_directory->addSubDir(dir_name);
01146 DirectoryHandler *dh = new dirhandler(dir, m_prefix, m_metalist,
01147 m_dh_free_list,
01148 m_infer_title);
01149 m_dh_free_list.push_back(dh);
01150 return dh;
01151 }
01152
01153 void handleFile(const QString &file_name,
01154 const QString &fq_file_name,
01155 const QString &extension)
01156 {
01157 (void)file_name;
01158 (void)extension;
01159 QString file_string(fq_file_name);
01160
01161 MetadataListManager::MetadataPtr myData(new Metadata(file_string));
01162 QFileInfo qfi(file_string);
01163 QString title = qfi.baseName(true);
01164 if (m_infer_title)
01165 {
01166 QString tmptitle(Metadata::FilenameToTitle(file_string));
01167 if (tmptitle.length())
01168 title = tmptitle;
01169 }
01170 myData->setTitle(title);
01171 myData->setPrefix(m_prefix);
01172
01173 m_metalist.push_back(myData);
01174
01175 m_directory->addEntry(new meta_data_node(myData.get()));
01176 }
01177
01178 private:
01179 smart_dir_node m_directory;
01180 const QString &m_prefix;
01181 MetadataListManager::metadata_list &m_metalist;
01182 free_list &m_dh_free_list;
01183 const bool m_infer_title;
01184 };
01185 }
01186
01187 void VideoListImp::buildFileList(smart_dir_node &directory,
01188 metadata_list &metalist, const QString &prefix)
01189 {
01190 FileAssociations::ext_ignore_list ext_list;
01191 FileAssociations::getFileAssociation().getExtensionIgnoreList(ext_list);
01192
01193 dirhandler::free_list fl;
01194 dirhandler dh(directory, prefix, metalist, fl, false);
01195 ScanVideoDirectory(directory->getFQPath(), &dh, ext_list, m_ListUnknown);
01196 }