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