1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/*
* 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?
int inProgress = 0;
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++;
// handle resume points
CBookmark bookmark = movieInfo->GetResumePoint();
if (bookmark.IsSet())
inProgress++;
//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->SetProperty("inprogress", inProgress);
pItem->SetOverlayImage(setInfo->GetPlayCount() > 0 ? CGUIListItem::ICON_OVERLAY_WATCHED
: CGUIListItem::ICON_OVERLAY_UNWATCHED);
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;
}
|