diff options
Diffstat (limited to 'xbmc/utils/GroupUtils.cpp')
-rw-r--r-- | xbmc/utils/GroupUtils.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/xbmc/utils/GroupUtils.cpp b/xbmc/utils/GroupUtils.cpp new file mode 100644 index 0000000..a51399f --- /dev/null +++ b/xbmc/utils/GroupUtils.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GroupUtils.h" + +#include "FileItem.h" +#include "filesystem/MultiPathDirectory.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "video/VideoDbUrl.h" +#include "video/VideoInfoTag.h" + +#include <map> +#include <set> + +using SetMap = std::map<int, std::set<CFileItemPtr> >; + +bool GroupUtils::Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */) +{ + CFileItemList ungroupedItems; + return Group(groupBy, baseDir, items, groupedItems, ungroupedItems, groupAttributes); +} + +bool GroupUtils::Group(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItems, CFileItemList &ungroupedItems, GroupAttribute groupAttributes /* = GroupAttributeNone */) +{ + if (groupBy == GroupByNone) + return false; + + // nothing to do if there are no items to group + if (items.Size() <= 0) + return true; + + SetMap setMap; + for (int index = 0; index < items.Size(); index++) + { + bool ungrouped = true; + const CFileItemPtr item = items.Get(index); + + // group by sets + if ((groupBy & GroupBySet) && + item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_set.id > 0) + { + ungrouped = false; + setMap[item->GetVideoInfoTag()->m_set.id].insert(item); + } + + if (ungrouped) + ungroupedItems.Add(item); + } + + if ((groupBy & GroupBySet) && !setMap.empty()) + { + CVideoDbUrl itemsUrl; + if (!itemsUrl.FromString(baseDir)) + return false; + + for (SetMap::const_iterator set = setMap.begin(); set != setMap.end(); ++set) + { + // only one item in the set, so add it to the ungrouped items + if (set->second.size() == 1 && (groupAttributes & GroupAttributeIgnoreSingleItems)) + { + ungroupedItems.Add(*set->second.begin()); + continue; + } + + CFileItemPtr pItem(new CFileItem((*set->second.begin())->GetVideoInfoTag()->m_set.title)); + pItem->GetVideoInfoTag()->m_iDbId = set->first; + pItem->GetVideoInfoTag()->m_type = MediaTypeVideoCollection; + + std::string basePath = StringUtils::Format("videodb://movies/sets/{}/", set->first); + CVideoDbUrl videoUrl; + if (!videoUrl.FromString(basePath)) + pItem->SetPath(basePath); + else + { + videoUrl.AddOptions((*set->second.begin())->GetURL().GetOptions()); + pItem->SetPath(videoUrl.ToString()); + } + pItem->m_bIsFolder = true; + + CVideoInfoTag* setInfo = pItem->GetVideoInfoTag(); + setInfo->m_strPath = pItem->GetPath(); + setInfo->m_strTitle = pItem->GetLabel(); + setInfo->m_strPlot = (*set->second.begin())->GetVideoInfoTag()->m_set.overview; + + int ratings = 0; + float totalRatings = 0; + int iWatched = 0; // have all the movies been played at least once? + std::set<std::string> pathSet; + for (std::set<CFileItemPtr>::const_iterator movie = set->second.begin(); movie != set->second.end(); ++movie) + { + CVideoInfoTag* movieInfo = (*movie)->GetVideoInfoTag(); + // handle rating + if (movieInfo->GetRating().rating > 0.0f) + { + ratings++; + totalRatings += movieInfo->GetRating().rating; + } + + // handle year + if (movieInfo->GetYear() > setInfo->GetYear()) + setInfo->SetYear(movieInfo->GetYear()); + + // handle lastplayed + if (movieInfo->m_lastPlayed.IsValid() && movieInfo->m_lastPlayed > setInfo->m_lastPlayed) + setInfo->m_lastPlayed = movieInfo->m_lastPlayed; + + // handle dateadded + if (movieInfo->m_dateAdded.IsValid() && movieInfo->m_dateAdded > setInfo->m_dateAdded) + setInfo->m_dateAdded = movieInfo->m_dateAdded; + + // handle playcount/watched + setInfo->SetPlayCount(setInfo->GetPlayCount() + movieInfo->GetPlayCount()); + if (movieInfo->GetPlayCount() > 0) + iWatched++; + + //accumulate the path for a multipath construction + CFileItem video(movieInfo->m_basePath, false); + if (video.IsVideo()) + pathSet.insert(URIUtils::GetParentPath(movieInfo->m_basePath)); + else + pathSet.insert(movieInfo->m_basePath); + } + setInfo->m_basePath = XFILE::CMultiPathDirectory::ConstructMultiPath(pathSet); + + if (ratings > 0) + pItem->GetVideoInfoTag()->SetRating(totalRatings / ratings); + + setInfo->SetPlayCount(iWatched >= static_cast<int>(set->second.size()) ? (setInfo->GetPlayCount() / set->second.size()) : 0); + pItem->SetProperty("total", (int)set->second.size()); + pItem->SetProperty("watched", iWatched); + pItem->SetProperty("unwatched", (int)set->second.size() - iWatched); + pItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, setInfo->GetPlayCount() > 0); + + groupedItems.Add(pItem); + } + } + + return true; +} + +bool GroupUtils::GroupAndMix(GroupBy groupBy, const std::string &baseDir, const CFileItemList &items, CFileItemList &groupedItemsMixed, GroupAttribute groupAttributes /* = GroupAttributeNone */) +{ + CFileItemList ungroupedItems; + if (!Group(groupBy, baseDir, items, groupedItemsMixed, ungroupedItems, groupAttributes)) + return false; + + // add all the ungrouped items as well + groupedItemsMixed.Append(ungroupedItems); + + return true; +} |