diff options
author | Kai Sommerfeld <kai.sommerfeld@gmx.com> | 2019-05-20 20:09:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-20 20:09:04 +0200 |
commit | 80a8e0edc54d099b252d7212aea86839003e1796 (patch) | |
tree | 1ed0d33e2d81572c71af123fa471683e459c2382 | |
parent | 18f05f9b5cdd6890d17d5f789820328ec9db5875 (diff) | |
parent | f37ca6e9ae71a7ea97bf81d8bfe47c44c22d9445 (diff) |
Merge pull request #16173 from ksooo/pvr-directory-listings-leia
[PVR] Separate GUI from PVR core: remove CFileItem usage from core: step 1: directory listings.
-rw-r--r-- | xbmc/filesystem/PVRDirectory.cpp | 109 | ||||
-rw-r--r-- | xbmc/filesystem/PVRDirectory.h | 4 | ||||
-rw-r--r-- | xbmc/interfaces/json-rpc/PVROperations.cpp | 26 | ||||
-rw-r--r-- | xbmc/pvr/CMakeLists.txt | 2 | ||||
-rw-r--r-- | xbmc/pvr/PVRGUIDirectory.cpp | 507 | ||||
-rw-r--r-- | xbmc/pvr/PVRGUIDirectory.h | 93 | ||||
-rw-r--r-- | xbmc/pvr/channels/PVRChannelGroup.cpp | 16 | ||||
-rw-r--r-- | xbmc/pvr/channels/PVRChannelGroup.h | 15 | ||||
-rw-r--r-- | xbmc/pvr/channels/PVRChannelGroupsContainer.cpp | 138 | ||||
-rw-r--r-- | xbmc/pvr/channels/PVRChannelGroupsContainer.h | 21 | ||||
-rw-r--r-- | xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp | 7 | ||||
-rw-r--r-- | xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp | 25 | ||||
-rw-r--r-- | xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp | 2 | ||||
-rw-r--r-- | xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp | 11 | ||||
-rw-r--r-- | xbmc/pvr/recordings/PVRRecordings.cpp | 155 | ||||
-rw-r--r-- | xbmc/pvr/recordings/PVRRecordings.h | 25 | ||||
-rw-r--r-- | xbmc/pvr/timers/PVRTimers.cpp | 106 | ||||
-rw-r--r-- | xbmc/pvr/timers/PVRTimers.h | 15 | ||||
-rw-r--r-- | xbmc/pvr/windows/GUIWindowPVRGuide.cpp | 2 |
19 files changed, 704 insertions, 575 deletions
diff --git a/xbmc/filesystem/PVRDirectory.cpp b/xbmc/filesystem/PVRDirectory.cpp index 7fe3b66d6d..b4a5e88962 100644 --- a/xbmc/filesystem/PVRDirectory.cpp +++ b/xbmc/filesystem/PVRDirectory.cpp @@ -6,19 +6,9 @@ * See LICENSES/README.md for more information. */ -#include "FileItem.h" -#include "guilib/LocalizeStrings.h" #include "PVRDirectory.h" -#include "ServiceBroker.h" -#include "URL.h" -#include "utils/log.h" -#include "utils/StringUtils.h" -#include "utils/URIUtils.h" -#include "pvr/PVRManager.h" -#include "pvr/channels/PVRChannelGroupsContainer.h" -#include "pvr/recordings/PVRRecordings.h" -#include "pvr/timers/PVRTimers.h" +#include "pvr/PVRGUIDirectory.h" using namespace XFILE; using namespace PVR; @@ -29,115 +19,38 @@ CPVRDirectory::~CPVRDirectory() = default; bool CPVRDirectory::Exists(const CURL& url) { - if (!CServiceBroker::GetPVRManager().IsStarted()) - return false; - - return (url.IsProtocol("pvr") && StringUtils::StartsWith(url.GetFileName(), "recordings")); + const CPVRGUIDirectory dir(url); + return dir.Exists(); } bool CPVRDirectory::GetDirectory(const CURL& url, CFileItemList &items) { - std::string base(url.Get()); - URIUtils::RemoveSlashAtEnd(base); - - std::string fileName = url.GetFileName(); - URIUtils::RemoveSlashAtEnd(fileName); - CLog::Log(LOGDEBUG, "CPVRDirectory::GetDirectory(%s)", base.c_str()); - items.SetCacheToDisc(CFileItemList::CACHE_NEVER); - - if (fileName == "") - { - if (CServiceBroker::GetPVRManager().IsStarted()) - { - CFileItemPtr item; - - item.reset(new CFileItem(base + "channels/", true)); - item->SetLabel(g_localizeStrings.Get(19019)); - item->SetLabelPreformatted(true); - items.Add(item); - - item.reset(new CFileItem(base + "recordings/active/", true)); - item->SetLabel(g_localizeStrings.Get(19017)); // TV Recordings - item->SetLabelPreformatted(true); - items.Add(item); - - item.reset(new CFileItem(base + "recordings/deleted/", true)); - item->SetLabel(g_localizeStrings.Get(19108)); // Deleted TV Recordings - item->SetLabelPreformatted(true); - items.Add(item); - - // Sort by name only. Labels are preformatted. - items.AddSortMethod(SortByLabel, 551 /* Name */, LABEL_MASKS("%L", "", "%L", "")); - } - return true; - } - else if (StringUtils::StartsWith(fileName, "recordings")) - { - if (CServiceBroker::GetPVRManager().IsStarted()) - { - const std::string pathToUrl(url.Get()); - return CServiceBroker::GetPVRManager().Recordings()->GetDirectory(pathToUrl, items); - } - return true; - } - else if (StringUtils::StartsWith(fileName, "channels")) - { - if (CServiceBroker::GetPVRManager().ChannelGroups() && CServiceBroker::GetPVRManager().ChannelGroups()->Loaded()) - { - const std::string pathToUrl(url.Get()); - return CServiceBroker::GetPVRManager().ChannelGroups()->GetDirectory(pathToUrl, items); - } - return true; - } - else if (StringUtils::StartsWith(fileName, "timers")) - { - if (CServiceBroker::GetPVRManager().IsStarted()) - { - const std::string pathToUrl(url.Get()); - return CServiceBroker::GetPVRManager().Timers()->GetDirectory(pathToUrl, items); - } - return true; - } - - return false; + const CPVRGUIDirectory dir(url); + return dir.GetDirectory(items); } bool CPVRDirectory::SupportsWriteFileOperations(const std::string& strPath) { - CURL url(strPath); - std::string filename = url.GetFileName(); - - return URIUtils::IsPVRRecording(filename); -} - -bool CPVRDirectory::IsLiveTV(const std::string& strPath) -{ - CURL url(strPath); - std::string filename = url.GetFileName(); - - return URIUtils::IsLiveTV(filename); + const CPVRGUIDirectory dir(strPath); + return dir.SupportsWriteFileOperations(); } bool CPVRDirectory::HasTVRecordings() { - return CServiceBroker::GetPVRManager().IsStarted() ? - CServiceBroker::GetPVRManager().Recordings()->GetNumTVRecordings() > 0 : false; + return CPVRGUIDirectory::HasTVRecordings(); } bool CPVRDirectory::HasDeletedTVRecordings() { - return CServiceBroker::GetPVRManager().IsStarted() ? - CServiceBroker::GetPVRManager().Recordings()->HasDeletedTVRecordings() : false; + return CPVRGUIDirectory::HasDeletedTVRecordings(); } bool CPVRDirectory::HasRadioRecordings() { - return CServiceBroker::GetPVRManager().IsStarted() ? - CServiceBroker::GetPVRManager().Recordings()->GetNumRadioRecordings() > 0 : false; + return CPVRGUIDirectory::HasRadioRecordings(); } bool CPVRDirectory::HasDeletedRadioRecordings() { - return CServiceBroker::GetPVRManager().IsStarted() ? - CServiceBroker::GetPVRManager().Recordings()->HasDeletedRadioRecordings() : false; + return CPVRGUIDirectory::HasDeletedRadioRecordings(); } diff --git a/xbmc/filesystem/PVRDirectory.h b/xbmc/filesystem/PVRDirectory.h index ff034a5ade..77e9291849 100644 --- a/xbmc/filesystem/PVRDirectory.h +++ b/xbmc/filesystem/PVRDirectory.h @@ -10,8 +10,6 @@ #include "IDirectory.h" -class CPVRSession; - namespace XFILE { class CPVRDirectory @@ -27,7 +25,7 @@ public: bool Exists(const CURL& url) override; static bool SupportsWriteFileOperations(const std::string& strPath); - static bool IsLiveTV(const std::string& strPath); + static bool HasTVRecordings(); static bool HasDeletedTVRecordings(); static bool HasRadioRecordings(); diff --git a/xbmc/interfaces/json-rpc/PVROperations.cpp b/xbmc/interfaces/json-rpc/PVROperations.cpp index 0e33a03ddf..d6e1660c03 100644 --- a/xbmc/interfaces/json-rpc/PVROperations.cpp +++ b/xbmc/interfaces/json-rpc/PVROperations.cpp @@ -113,8 +113,11 @@ JSONRPC_STATUS CPVROperations::GetChannels(const std::string &method, ITransport return InvalidParams; CFileItemList channels; - if (channelGroup->GetMembers(channels) < 0) - return InvalidParams; + const std::vector<PVRChannelGroupMember> groupMembers = channelGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + for (const auto& groupMember : groupMembers) + { + channels.Add(std::make_shared<CFileItem>(groupMember.channel)); + } HandleFileItemList("channelid", false, "channels", channels, parameterObject, result, true); @@ -280,7 +283,12 @@ void CPVROperations::FillChannelGroupDetails(const CPVRChannelGroupPtr &channelG else { CFileItemList channels; - channelGroup->GetMembers(channels); + const std::vector<PVRChannelGroupMember> groupMembers = channelGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + for (const auto& groupMember : groupMembers) + { + channels.Add(std::make_shared<CFileItem>(groupMember.channel)); + } + object["channels"] = CVariant(CVariant::VariantTypeArray); HandleFileItemList("channelid", false, "channels", channels, parameterObject["channels"], object, false); @@ -298,7 +306,11 @@ JSONRPC_STATUS CPVROperations::GetTimers(const std::string &method, ITransportLa return FailedToExecute; CFileItemList timerList; - timers->GetAll(timerList); + const std::vector<std::shared_ptr<CPVRTimerInfoTag>> tags = timers->GetAll(); + for (const auto& timer : tags) + { + timerList.Add(std::make_shared<CFileItem>(timer)); + } HandleFileItemList("timerid", false, "timers", timerList, parameterObject, result, true); @@ -413,7 +425,11 @@ JSONRPC_STATUS CPVROperations::GetRecordings(const std::string &method, ITranspo return FailedToExecute; CFileItemList recordingsList; - recordings->GetAll(recordingsList); + const std::vector<std::shared_ptr<CPVRRecording>> recs = recordings->GetAll(); + for (const auto& recording : recs) + { + recordingsList.Add(std::make_shared<CFileItem>(recording)); + } HandleFileItemList("recordingid", true, "recordings", recordingsList, parameterObject, result, true); diff --git a/xbmc/pvr/CMakeLists.txt b/xbmc/pvr/CMakeLists.txt index 55fe42704f..c3f05358fc 100644 --- a/xbmc/pvr/CMakeLists.txt +++ b/xbmc/pvr/CMakeLists.txt @@ -9,6 +9,7 @@ set(SOURCES PVRActionListener.cpp PVRChannelNumberInputHandler.cpp PVRJobs.cpp PVRGUIChannelNavigator.cpp + PVRGUIDirectory.cpp PVRGUIProgressHandler.cpp PVRGUITimerInfo.cpp PVRGUITimesInfo.cpp) @@ -25,6 +26,7 @@ set(HEADERS PVRActionListener.h PVRChannelNumberInputHandler.h PVRJobs.h PVRGUIChannelNavigator.h + PVRGUIDirectory.h PVRGUIProgressHandler.h PVRGUITimerInfo.h PVRGUITimesInfo.h) diff --git a/xbmc/pvr/PVRGUIDirectory.cpp b/xbmc/pvr/PVRGUIDirectory.cpp new file mode 100644 index 0000000000..b2ce07ef85 --- /dev/null +++ b/xbmc/pvr/PVRGUIDirectory.cpp @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2012-2019 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 "PVRGUIDirectory.h" + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "URL.h" +#include "guilib/LocalizeStrings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/StringUtils.h" +#include "utils/URIUtils.h" +#include "utils/log.h" + +#include "pvr/PVRManager.h" +#include "pvr/channels/PVRChannelGroups.h" +#include "pvr/channels/PVRChannelGroupsContainer.h" +#include "pvr/recordings/PVRRecordings.h" +#include "pvr/recordings/PVRRecordingsPath.h" +#include "pvr/timers/PVRTimers.h" +#include "pvr/timers/PVRTimersPath.h" + +using namespace PVR; + +bool CPVRGUIDirectory::Exists() const +{ + if (!CServiceBroker::GetPVRManager().IsStarted()) + return false; + + return m_url.IsProtocol("pvr") && StringUtils::StartsWith(m_url.GetFileName(), "recordings"); +} + +bool CPVRGUIDirectory::SupportsWriteFileOperations() const +{ + if (!CServiceBroker::GetPVRManager().IsStarted()) + return false; + + const std::string filename = m_url.GetFileName(); + return URIUtils::IsPVRRecording(filename); +} + +bool CPVRGUIDirectory::GetDirectory(CFileItemList& results) const +{ + std::string base = m_url.Get(); + URIUtils::RemoveSlashAtEnd(base); + + std::string fileName = m_url.GetFileName(); + URIUtils::RemoveSlashAtEnd(fileName); + + results.SetCacheToDisc(CFileItemList::CACHE_NEVER); + + if (fileName.empty()) + { + if (CServiceBroker::GetPVRManager().IsStarted()) + { + std::shared_ptr<CFileItem> item; + + item.reset(new CFileItem(base + "channels/", true)); + item->SetLabel(g_localizeStrings.Get(19019)); + item->SetLabelPreformatted(true); + results.Add(item); + + item.reset(new CFileItem(base + "recordings/active/", true)); + item->SetLabel(g_localizeStrings.Get(19017)); // TV Recordings + item->SetLabelPreformatted(true); + results.Add(item); + + item.reset(new CFileItem(base + "recordings/deleted/", true)); + item->SetLabel(g_localizeStrings.Get(19108)); // Deleted TV Recordings + item->SetLabelPreformatted(true); + results.Add(item); + + // Sort by name only. Labels are preformatted. + results.AddSortMethod(SortByLabel, 551 /* Name */, LABEL_MASKS("%L", "", "%L", "")); + } + return true; + } + else if (StringUtils::StartsWith(fileName, "recordings")) + { + if (CServiceBroker::GetPVRManager().IsStarted()) + { + return GetRecordingsDirectory(results); + } + return true; + } + else if (StringUtils::StartsWith(fileName, "channels")) + { + if (CServiceBroker::GetPVRManager().ChannelGroups() && + CServiceBroker::GetPVRManager().ChannelGroups()->Loaded()) + { + return GetChannelsDirectory(results); + } + return true; + } + else if (StringUtils::StartsWith(fileName, "timers")) + { + if (CServiceBroker::GetPVRManager().IsStarted()) + { + return GetTimersDirectory(results); + } + return true; + } + + return false; +} + +bool CPVRGUIDirectory::HasTVRecordings() +{ + return CServiceBroker::GetPVRManager().IsStarted() && + CServiceBroker::GetPVRManager().Recordings()->GetNumTVRecordings() > 0; +} + +bool CPVRGUIDirectory::HasDeletedTVRecordings() +{ + return CServiceBroker::GetPVRManager().IsStarted() && + CServiceBroker::GetPVRManager().Recordings()->HasDeletedTVRecordings(); +} + +bool CPVRGUIDirectory::HasRadioRecordings() +{ + return CServiceBroker::GetPVRManager().IsStarted() && + CServiceBroker::GetPVRManager().Recordings()->GetNumRadioRecordings() > 0; +} + +bool CPVRGUIDirectory::HasDeletedRadioRecordings() +{ + return CServiceBroker::GetPVRManager().IsStarted() && + CServiceBroker::GetPVRManager().Recordings()->HasDeletedRadioRecordings(); +} + +namespace +{ + +std::string TrimSlashes(const std::string& strOrig) +{ + std::string strReturn = strOrig; + while (strReturn[0] == '/') + strReturn.erase(0, 1); + + URIUtils::RemoveSlashAtEnd(strReturn); + return strReturn; +} + +bool IsDirectoryMember(const std::string& strDirectory, + const std::string& strEntryDirectory, + bool bGrouped) +{ + const std::string strUseDirectory = TrimSlashes(strDirectory); + const std::string strUseEntryDirectory = TrimSlashes(strEntryDirectory); + + // Case-insensitive comparison since sub folders are created with case-insensitive matching (GetSubDirectories) + if (bGrouped) + return StringUtils::EqualsNoCase(strUseDirectory, strUseEntryDirectory); + else + return StringUtils::StartsWithNoCase(strUseEntryDirectory, strUseDirectory); +} + +void GetSubDirectories(const CPVRRecordingsPath& recParentPath, + CVideoDatabase& videoDB, + const std::vector<std::shared_ptr<CPVRRecording>>& recordings, + CFileItemList& results) +{ + // Only active recordings are fetched to provide sub directories. + // Not applicable for deleted view which is supposed to be flattened. + std::set<std::shared_ptr<CFileItem>> unwatchedFolders; + bool bRadio = recParentPath.IsRadio(); + + for (const auto& recording : recordings) + { + if (recording->IsDeleted()) + continue; + + if (recording->IsRadio() != bRadio) + continue; + + const std::string strCurrent = recParentPath.GetUnescapedSubDirectoryPath(recording->m_strDirectory); + if (strCurrent.empty()) + continue; + + CPVRRecordingsPath recChildPath(recParentPath); + recChildPath.AppendSegment(strCurrent); + const std::string strFilePath = recChildPath; + + recording->UpdateMetadata(videoDB); + + std::shared_ptr<CFileItem> item; + if (!results.Contains(strFilePath)) + { + item.reset(new CFileItem(strCurrent, true)); + item->SetPath(strFilePath); + item->SetLabel(strCurrent); + item->SetLabelPreformatted(true); + item->m_dateTime = recording->RecordingTimeAsLocalTime(); + + // Assume all folders are watched, we'll change the overlay later + item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_WATCHED, false); + results.Add(item); + } + else + { + item = results.Get(strFilePath); + if (item->m_dateTime < recording->RecordingTimeAsLocalTime()) + item->m_dateTime = recording->RecordingTimeAsLocalTime(); + } + + if (recording->GetPlayCount() == 0) + unwatchedFolders.insert(item); + } + + // Change the watched overlay to unwatched for folders containing unwatched entries + for (auto& item : unwatchedFolders) + item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, false); +} + +} // unnamed namespace + +bool CPVRGUIDirectory::GetRecordingsDirectory(CFileItemList& results) const +{ + bool bGrouped = false; + const std::shared_ptr<CPVRRecordings> recs = CServiceBroker::GetPVRManager().Recordings(); + const std::vector<std::shared_ptr<CPVRRecording>> recordings = recs->GetAll(); + CVideoDatabase& videoDB = recs->GetVideoDatabase(); + + if (m_url.HasOption("view")) + { + const std::string view = m_url.GetOption("view"); + if (view == "grouped") + bGrouped = true; + else if (view == "flat") + bGrouped = false; + else + { + CLog::LogF(LOGERROR, "Unsupported value '%s' for url parameter 'view'", view.c_str()); + return false; + } + } + else + { + bGrouped = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRRECORD_GROUPRECORDINGS); + } + + const CPVRRecordingsPath recPath(m_url.GetWithoutOptions()); + if (recPath.IsValid()) + { + // Get the directory structure if in non-flatten mode + // Deleted view is always flatten. So only for an active view + const std::string strDirectory = recPath.GetUnescapedDirectoryPath(); + if (!recPath.IsDeleted() && bGrouped) + GetSubDirectories(recPath, videoDB, recordings, results); + + // get all files of the current directory or recursively all files starting at the current directory if in flatten mode + std::shared_ptr<CFileItem> item; + for (const auto& recording : recordings) + { + // Omit recordings not matching criteria + if (recording->IsDeleted() != recPath.IsDeleted() || + recording->IsRadio() != recPath.IsRadio() || + !IsDirectoryMember(strDirectory, recording->m_strDirectory, bGrouped)) + continue; + + recording->UpdateMetadata(videoDB); + + item = std::make_shared<CFileItem>(recording); + item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, recording->GetPlayCount() > 0); + results.Add(item); + } + } + + return recPath.IsValid(); +} + +bool CPVRGUIDirectory::FilterDirectory(CFileItemList& results) const +{ + if (!results.IsEmpty()) + { + if (m_url.HasOption("view")) + { + const std::string view = m_url.GetOption("view"); + if (view == "lastplayed") + { + // remove channels never played so far + for (int i = 0; i < results.Size(); ++i) + { + const std::shared_ptr<CPVRChannel> channel = results.Get(i)->GetPVRChannelInfoTag(); + time_t lastWatched = channel->LastWatched(); + if (!lastWatched) + { + results.Remove(i); + --i; + } + } + } + else + { + CLog::LogF(LOGERROR, "Unsupported value '%s' for channel list URL parameter 'view'", view.c_str()); + return false; + } + } + } + return true; +} + +bool CPVRGUIDirectory::GetChannelGroupsDirectory(bool bRadio, CFileItemList& results) const +{ + const CPVRChannelGroups* channelGroups = CServiceBroker::GetPVRManager().ChannelGroups()->Get(bRadio); + if (channelGroups) + { + channelGroups->GetGroupList(&results); + return true; + } + return false; +} + +bool CPVRGUIDirectory::GetChannelsDirectory(CFileItemList& results) const +{ + std::string base = m_url.Get(); + URIUtils::RemoveSlashAtEnd(base); + + std::string fileName = m_url.GetFileName(); + URIUtils::RemoveSlashAtEnd(fileName); + + if (fileName == "channels") + { + std::shared_ptr<CFileItem> item; + + // all tv channels + item.reset(new CFileItem(base + "/tv/", true)); + item->SetLabel(g_localizeStrings.Get(19020)); + item->SetLabelPreformatted(true); + results.Add(item); + + // all radio channels + item.reset(new CFileItem(base + "/radio/", true)); + item->SetLabel(g_localizeStrings.Get(19021)); + item->SetLabelPreformatted(true); + results.Add(item); + + return true; + } + else if (fileName == "channels/tv") + { + return GetChannelGroupsDirectory(false, results); + } + else if (fileName == "channels/radio") + { + return GetChannelGroupsDirectory(true, results); + } + else if (StringUtils::StartsWith(fileName, "channels/tv/")) + { + std::string strGroupName = fileName.substr(12); + URIUtils::RemoveSlashAtEnd(strGroupName); + + std::shared_ptr<CPVRChannelGroup> group; + bool bShowHiddenChannels = StringUtils::EndsWithNoCase(fileName, ".hidden"); + if (bShowHiddenChannels || strGroupName == "*") // all channels + group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllTV(); + else + group = CServiceBroker::GetPVRManager().ChannelGroups()->GetTV()->GetByName(strGroupName); + + if (group) + { + const std::vector<PVRChannelGroupMember> groupMembers = group->GetMembers(); + for (const auto& groupMember : groupMembers) + { + if (bShowHiddenChannels != groupMember.channel->IsHidden()) + continue; + + results.Add(std::make_shared<CFileItem>(groupMember.channel)); + } + } + else + { + CLog::LogF(LOGERROR, "Unable to obtain members of channel group '%s'", strGroupName.c_str()); + return false; + } + + FilterDirectory(results); + return true; + } + else if (StringUtils::StartsWith(fileName, "channels/radio/")) + { + std::string strGroupName = fileName.substr(15); + URIUtils::RemoveSlashAtEnd(strGroupName); + + std::shared_ptr<CPVRChannelGroup> group; + bool bShowHiddenChannels = StringUtils::EndsWithNoCase(fileName, ".hidden"); + if (bShowHiddenChannels || strGroupName == "*") // all channels + group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAllRadio(); + else + group = CServiceBroker::GetPVRManager().ChannelGroups()->GetRadio()->GetByName(strGroupName); + + if (group) + { + const std::vector<PVRChannelGroupMember> groupMembers = group->GetMembers(); + for (const auto& groupMember : groupMembers) + { + if (bShowHiddenChannels != groupMember.channel->IsHidden()) + continue; + + results.Add(std::make_shared<CFileItem>(groupMember.channel)); + } + } + else + { + CLog::LogF(LOGERROR, "Unable to obtain members of channel group '%s'", strGroupName.c_str()); + return false; + } + + FilterDirectory(results); + return true; + } + + return false; +} + +namespace +{ + +bool GetTimersRootDirectory(const CPVRTimersPath& path, + const std::vector<std::shared_ptr<CPVRTimerInfoTag>>& timers, + CFileItemList& results) +{ + std::shared_ptr<CFileItem> item(new CFileItem(CPVRTimersPath::PATH_ADDTIMER, false)); + item->SetLabel(g_localizeStrings.Get(19026)); // "Add timer..." + item->SetLabelPreformatted(true); + item->SetSpecialSort(SortSpecialOnTop); + item->SetIconImage("DefaultTVShows.png"); + results.Add(item); + + bool bRadio = path.IsRadio(); + bool bRules = path.IsRules(); + + bool bHideDisabled = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRTIMERS_HIDEDISABLEDTIMERS); + + for (const auto& timer : timers) + { + if ((bRadio == timer->m_bIsRadio || (bRules && timer->m_iClientChannelUid == PVR_TIMER_ANY_CHANNEL)) && + (bRules == timer->IsTimerRule()) && + (!bHideDisabled || (timer->m_state != PVR_TIMER_STATE_DISABLED))) + { + item.reset(new CFileItem(timer)); + const CPVRTimersPath timersPath(path.GetPath(), timer->m_iClientId, timer->m_iClientIndex); + item->SetPath(timersPath.GetPath()); + results.Add(item); + } + } + return true; +} + +bool GetTimersSubDirectory(const CPVRTimersPath& path, + const std::vector<std::shared_ptr<CPVRTimerInfoTag>>& timers, + CFileItemList& results) +{ + bool bRadio = path.IsRadio(); + unsigned int iParentId = path.GetParentId(); + int iClientId = path.GetClientId(); + + bool bHideDisabled = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRTIMERS_HIDEDISABLEDTIMERS); + + std::shared_ptr<CFileItem> item; + + for (const auto& timer : timers) + { + if ((timer->m_bIsRadio == bRadio) && + (timer->m_iParentClientIndex != PVR_TIMER_NO_PARENT) && + (timer->m_iClientId == iClientId) && + (timer->m_iParentClientIndex == iParentId) && + (!bHideDisabled || (timer->m_state != PVR_TIMER_STATE_DISABLED))) + { + item.reset(new CFileItem(timer)); + const CPVRTimersPath timersPath(path.GetPath(), timer->m_iClientId, timer->m_iClientIndex); + item->SetPath(timersPath.GetPath()); + results.Add(item); + } + } + return true; +} + +} // unnamed namespace + +bool CPVRGUIDirectory::GetTimersDirectory(CFileItemList& results) const +{ + const CPVRTimersPath path(m_url.GetWithoutOptions()); + if (path.IsValid()) + { + const std::vector<std::shared_ptr<CPVRTimerInfoTag>> timers = CServiceBroker::GetPVRManager().Timers()->GetAll(); + + if (path.IsTimersRoot()) + { + /* Root folder containing either timer rules or timers. */ + return GetTimersRootDirectory(path, timers, results); + } + else if (path.IsTimerRule()) + { + /* Sub folder containing the timers scheduled by the given timer rule. */ + return GetTimersSubDirectory(path, timers, results); + } + } + + return false; +} diff --git a/xbmc/pvr/PVRGUIDirectory.h b/xbmc/pvr/PVRGUIDirectory.h new file mode 100644 index 0000000000..86d83fea31 --- /dev/null +++ b/xbmc/pvr/PVRGUIDirectory.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012-2019 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. + */ + +#pragma once + +#include "URL.h" + +class CFileItemList; + +namespace PVR +{ + +class CPVRGUIDirectory +{ +public: + /*! + * @brief PVR GUI directory ctor. + * @param url The directory's URL. + */ + explicit CPVRGUIDirectory(const CURL& url) : m_url(url) {} + + /*! + * @brief PVR GUI directory ctor. + * @param path The directory's path. + */ + explicit CPVRGUIDirectory(const std::string& path) : m_url(path) {} + + /*! + * @brief PVR GUI directory dtor. + */ + virtual ~CPVRGUIDirectory() = default; + + /*! + * @brief Check existense of this directory. + * @return True if the directory exists, false otherwise. + */ + bool Exists() const; + + /*! + * @brief Obtain the directory listing. + * @param results The list to fill with the results. + * @return True on success, false otherwise. + */ + bool GetDirectory(CFileItemList& results) const; + + /*! + * @brief Check if this directory supports file write operations. + * @return True if the directory supports file write operations, false otherwise. + */ + bool SupportsWriteFileOperations() const; + + /*! + * @brief Check if any TV recordings are existing. + * @return True if TV recordings exists, false otherwise. + */ + static bool HasTVRecordings(); + + /*! + * @brief Check if any deleted TV recordings are existing. + * @return True if deleted TV recordings exists, false otherwise. + */ + static bool HasDeletedTVRecordings(); + + /*! + * @brief Check if any radio recordings are existing. + * @return True if radio recordings exists, false otherwise. + */ + static bool HasRadioRecordings(); + + /*! + * @brief Check if any deleted radio recordings are existing. + * @return True if deleted radio recordings exists, false otherwise. + */ + static bool HasDeletedRadioRecordings(); + +private: + + bool FilterDirectory(CFileItemList& results) const; + + bool GetChannelGroupsDirectory(bool bRadio, CFileItemList& results) const; + bool GetChannelsDirectory(CFileItemList& results) const; + bool GetTimersDirectory(CFileItemList& results) const; + bool GetRecordingsDirectory(CFileItemList& results) const; + + const CURL m_url; +}; + +} diff --git a/xbmc/pvr/channels/PVRChannelGroup.cpp b/xbmc/pvr/channels/PVRChannelGroup.cpp index 77b83b783a..12b1ec613a 100644 --- a/xbmc/pvr/channels/PVRChannelGroup.cpp +++ b/xbmc/pvr/channels/PVRChannelGroup.cpp @@ -490,17 +490,13 @@ CFileItemPtr CPVRChannelGroup::GetPreviousChannel(const CPVRChannelPtr &channel) return retval; } -PVR_CHANNEL_GROUP_SORTED_MEMBERS CPVRChannelGroup::GetMembers(void) const +std::vector<PVRChannelGroupMember> CPVRChannelGroup::GetMembers(Include eFilter /* = Include::ALL */) const { CSingleLock lock(m_critSection); - return m_sortedMembers; -} - -int CPVRChannelGroup::GetMembers(CFileItemList &results, Include eFilter /* = Include::ONLY_VISIBLE */) const -{ - int iOrigSize = results.Size(); - CSingleLock lock(m_critSection); + if (eFilter == Include::ALL) + return m_sortedMembers; + std::vector<PVRChannelGroupMember> members; for (const auto& member : m_sortedMembers) { switch (eFilter) @@ -517,10 +513,10 @@ int CPVRChannelGroup::GetMembers(CFileItemList &results, Include eFilter /* = In break; } - results.Add(std::make_shared<CFileItem>(member.channel)); + members.emplace_back(member); } - return results.Size() - iOrigSize; + return members; } void CPVRChannelGroup::GetChannelNumbers(std::vector<std::string>& channelNumbers) const diff --git a/xbmc/pvr/channels/PVRChannelGroup.h b/xbmc/pvr/channels/PVRChannelGroup.h index e0253767f0..6d9ddbdd18 100644 --- a/xbmc/pvr/channels/PVRChannelGroup.h +++ b/xbmc/pvr/channels/PVRChannelGroup.h @@ -314,12 +314,6 @@ namespace PVR */ CPVRChannelPtr GetByChannelID(int iChannelID) const; - /*! - * Get the current members of this group - * @return The group members - */ - PVR_CHANNEL_GROUP_SORTED_MEMBERS GetMembers(void) const; - enum class Include { ALL, @@ -328,12 +322,11 @@ namespace PVR }; /*! - * @brief Get a filtered list of channels in this group. - * @param results The file list to store the results in. - * @param eFilter A filter to apply to the list. - * @return The amount of channels that were added to the list. + * @brief Get the current members of this group + * @param eFilter A filter to apply. + * @return The group members */ - int GetMembers(CFileItemList &results, Include eFilter = Include::ONLY_VISIBLE) const; + std::vector<PVRChannelGroupMember> GetMembers(Include eFilter = Include::ALL) const; /*! * @brief Get the list of channel numbers in a group. diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp index fb47e02d2c..23bc0cb209 100644 --- a/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp +++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.cpp @@ -8,13 +8,9 @@ #include "PVRChannelGroupsContainer.h" -#include "URL.h" -#include "guilib/LocalizeStrings.h" -#include "utils/StringUtils.h" -#include "utils/URIUtils.h" +#include "FileItem.h" #include "utils/log.h" -#include "pvr/PVRManager.h" #include "pvr/epg/EpgInfoTag.h" using namespace PVR; @@ -115,17 +111,6 @@ std::shared_ptr<CPVRChannel> CPVRChannelGroupsContainer::GetChannelForEpgTag(con return groups->GetGroupAll()->GetByUniqueID(epgTag->UniqueChannelID(), epgTag->ClientID()); } -bool CPVRChannelGroupsContainer::GetGroupsDirectory(CFileItemList *results, bool bRadio) const -{ - const CPVRChannelGroups *channelGroups = Get(bRadio); - if (channelGroups) - { - channelGroups->GetGroupList(results); - return true; - } - return false; -} - CFileItemPtr CPVRChannelGroupsContainer::GetByPath(const std::string &strPath) const { for (unsigned int bRadio = 0; bRadio <= 1; ++bRadio) @@ -140,127 +125,6 @@ CFileItemPtr CPVRChannelGroupsContainer::GetByPath(const std::string &strPath) c return retVal; } -bool CPVRChannelGroupsContainer::GetDirectory(const std::string& strPath, CFileItemList &results) const -{ - std::string strBase(strPath); - URIUtils::RemoveSlashAtEnd(strBase); - - /* get the filename from curl */ - CURL url(strPath); - std::string fileName = url.GetFileName(); - URIUtils::RemoveSlashAtEnd(fileName); - - if (fileName == "channels") - { - CFileItemPtr item; - - /* all tv channels */ - item.reset(new CFileItem(strBase + "/tv/", true)); - item->SetLabel(g_localizeStrings.Get(19020)); - item->SetLabelPreformatted(true); - results.Add(item); - - /* all radio channels */ - item.reset(new CFileItem(strBase + "/radio/", true)); - item->SetLabel(g_localizeStrings.Get(19021)); - item->SetLabelPreformatted(true); - results.Add(item); - - return true; - } - else if (fileName == "channels/tv") - { - return GetGroupsDirectory(&results, false); - } - else if (fileName == "channels/radio") - { - return GetGroupsDirectory(&results, true); - } - else if (StringUtils::StartsWith(fileName, "channels/tv/")) - { - std::string strGroupName(fileName.substr(12)); - URIUtils::RemoveSlashAtEnd(strGroupName); - - CPVRChannelGroupPtr group; - bool bShowHiddenChannels = StringUtils::EndsWithNoCase(fileName, ".hidden"); - if (strGroupName == "*" || bShowHiddenChannels) // all channels - group = GetGroupAllTV(); - else - group = GetTV()->GetByName(strGroupName); - - if (group) - { - group->GetMembers(results, bShowHiddenChannels ? CPVRChannelGroup::Include::ONLY_HIDDEN : CPVRChannelGroup::Include::ONLY_VISIBLE); - } - else - { - CLog::LogF(LOGERROR, "Unable to obtain members of channel group '%s'", strGroupName.c_str()); - return false; - } - - FilterDirectory(url, results); - return true; - } - else if (StringUtils::StartsWith(fileName, "channels/radio/")) - { - std::string strGroupName(fileName.substr(15)); - URIUtils::RemoveSlashAtEnd(strGroupName); - - CPVRChannelGroupPtr group; - bool bShowHiddenChannels = StringUtils::EndsWithNoCase(fileName, ".hidden"); - if (strGroupName == "*" || bShowHiddenChannels) // all channels - group = GetGroupAllRadio(); - else - group = GetRadio()->GetByName(strGroupName); - - if (group) - { - group->GetMembers(results, bShowHiddenChannels ? CPVRChannelGroup::Include::ONLY_HIDDEN : CPVRChannelGroup::Include::ONLY_VISIBLE); - } - else - { - CLog::LogF(LOGERROR, "Unable to obtain members of channel group '%s'", strGroupName.c_str()); - return false; - } - - FilterDirectory(url, results); - return true; - } - - return false; -} - -bool CPVRChannelGroupsContainer::FilterDirectory(const CURL &url, CFileItemList &results) const -{ - if (!results.IsEmpty()) - { - if (url.HasOption("view")) - { - const std::string view(url.GetOption("view")); - if (view == "lastplayed") - { - // remove channels never played so far - for (int i = 0; i < results.Size(); ++i) - { - const CPVRChannelPtr channel(results.Get(i)->GetPVRChannelInfoTag()); - time_t lastWatched = channel->LastWatched(); - if (!lastWatched) - { - results.Remove(i); - --i; - } - } - } - else - { - CLog::LogF(LOGERROR, "Unsupported value '%s' for channel list URL parameter 'view'", view.c_str()); - return false; - } - } - } - return true; -} - CPVRChannelGroupPtr CPVRChannelGroupsContainer::GetSelectedGroup(bool bRadio) const { return Get(bRadio)->GetSelectedGroup(); diff --git a/xbmc/pvr/channels/PVRChannelGroupsContainer.h b/xbmc/pvr/channels/PVRChannelGroupsContainer.h index 5417e45611..f88dd2b5d4 100644 --- a/xbmc/pvr/channels/PVRChannelGroupsContainer.h +++ b/xbmc/pvr/channels/PVRChannelGroupsContainer.h @@ -12,8 +12,6 @@ #include "pvr/channels/PVRChannelGroups.h" -class CURL; - namespace PVR { class CPVRChannelGroupsContainer @@ -120,15 +118,6 @@ namespace PVR std::shared_ptr<CPVRChannel> GetChannelForEpgTag(const std::shared_ptr<CPVREpgInfoTag>& epgTag) const; /*! - * @brief Get the groups list for a directory. - * @param strBase The directory path. - * @param results The file list to store the results in. - * @param bRadio Get radio channels or tv channels. - * @return True if the list was filled successfully. - */ - bool GetGroupsDirectory(CFileItemList *results, bool bRadio) const; - - /*! * @brief Get a channel given it's path. * @param strPath The path. * @return The channel or NULL if it wasn't found. @@ -136,14 +125,6 @@ namespace PVR CFileItemPtr GetByPath(const std::string &strPath) const; /*! - * @brief Get the directory for a path. - * @param strPath The path. - * @param results The file list to store the results in. - * @return True if the directory was found, false if not. - */ - bool GetDirectory(const std::string& strPath, CFileItemList &results) const; - - /*! * @brief Get the group that is currently selected in the UI. * @param bRadio True to get the selected radio group, false to get the selected TV group. * @return The selected group. @@ -206,8 +187,6 @@ namespace PVR CPVRChannelGroupsContainer& operator=(const CPVRChannelGroupsContainer&) = delete; CPVRChannelGroupsContainer(const CPVRChannelGroupsContainer&) = delete; - bool FilterDirectory(const CURL &url, CFileItemList &results) const; - bool m_bLoaded = false; }; } diff --git a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp index be73f42332..dc6ea592c2 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRChannelsOSD.cpp @@ -166,7 +166,12 @@ void CGUIDialogPVRChannelsOSD::Update() const CPVRChannelGroupPtr group = pvrMgr.GetPlayingGroup(channel->IsRadio()); if (group) { - group->GetMembers(*m_vecItems); + const std::vector<PVRChannelGroupMember> groupMembers = group->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + for (const auto& groupMember : groupMembers) + { + m_vecItems->Add(std::make_shared<CFileItem>(groupMember.channel)); + } + m_viewControl.SetItems(*m_vecItems); if (!m_group) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp index 8dae3b3aec..30fbed9509 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRGroupManager.cpp @@ -403,21 +403,30 @@ void CGUIDialogPVRGroupManager::Update() // Slightly different handling for "all" group... if (m_selectedGroup->IsInternalGroup()) { - m_selectedGroup->GetMembers(*m_groupMembers, CPVRChannelGroup::Include::ONLY_VISIBLE); - m_selectedGroup->GetMembers(*m_ungroupedChannels, CPVRChannelGroup::Include::ONLY_HIDDEN); + const std::vector<PVRChannelGroupMember> groupMembers = m_selectedGroup->GetMembers(CPVRChannelGroup::Include::ALL); + for (const auto& groupMember : groupMembers) + { + if (groupMember.channel->IsHidden()) + m_ungroupedChannels->Add(std::make_shared<CFileItem>(groupMember.channel)); + else + m_groupMembers->Add(std::make_shared<CFileItem>(groupMember.channel)); + } } else { - m_selectedGroup->GetMembers(*m_groupMembers, CPVRChannelGroup::Include::ALL); + const std::vector<PVRChannelGroupMember> groupMembers = m_selectedGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + for (const auto& groupMember : groupMembers) + { + m_groupMembers->Add(std::make_shared<CFileItem>(groupMember.channel)); + } /* for the center part, get all channels of the "all" channels group that are not in this group */ const CPVRChannelGroupPtr allGroup = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio); - CFileItemList allChannels; - allGroup->GetMembers(allChannels, CPVRChannelGroup::Include::ALL); - for (const auto& channelItem : allChannels) + const std::vector<PVRChannelGroupMember> allGroupMembers = allGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + for (const auto& groupMember : allGroupMembers) { - if (!m_selectedGroup->IsGroupMember(channelItem->GetPVRChannelInfoTag())) - m_ungroupedChannels->Add(channelItem); + if (!m_selectedGroup->IsGroupMember(groupMember.channel)) + m_ungroupedChannels->Add(std::make_shared<CFileItem>(groupMember.channel)); } } m_viewGroupMembers.SetItems(*m_groupMembers); diff --git a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp index 1e4b119c76..9f0b6fcc5f 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRGuideSearch.cpp @@ -67,7 +67,7 @@ void CGUIDialogPVRGuideSearch::UpdateChannelSpin(void) group = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_searchFilter->IsRadio()); m_channelNumbersMap.clear(); - const std::vector<PVRChannelGroupMember> groupMembers(group->GetMembers()); + const std::vector<PVRChannelGroupMember> groupMembers(group->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE)); int iIndex = 0; int iSelectedChannel = EPG_SEARCH_UNSET; for (const auto& groupMember : groupMembers) diff --git a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp index db2e4a7294..65088fed19 100644 --- a/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp +++ b/xbmc/pvr/dialogs/GUIDialogPVRTimerSettings.cpp @@ -771,16 +771,17 @@ void CGUIDialogPVRTimerSettings::InitializeChannelsList() { m_channelEntries.clear(); - CFileItemList channelsList; - CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio)->GetMembers(channelsList); - - for (int i = 0; i < channelsList.Size(); ++i) + const std::shared_ptr<CPVRChannelGroup> allGroup = CServiceBroker::GetPVRManager().ChannelGroups()->GetGroupAll(m_bIsRadio); + const std::vector<PVRChannelGroupMember> groupMembers = allGroup->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); + int i = 0; + for (const auto& groupMember : groupMembers) { - const CPVRChannelPtr channel(channelsList[i]->GetPVRChannelInfoTag()); + const std::shared_ptr<CPVRChannel> channel = groupMember.channel; std::string channelDescription( StringUtils::Format("%s %s", channel->ChannelNumber().FormattedChannelNumber().c_str(), channel->ChannelName().c_str())); m_channelEntries.insert( std::make_pair(i, ChannelDescriptor(channel->UniqueID(), channel->ClientID(), channelDescription))); + i++; } // Add special "any channel" entry (used for epg-based timer rules). diff --git a/xbmc/pvr/recordings/PVRRecordings.cpp b/xbmc/pvr/recordings/PVRRecordings.cpp index 777e5a1320..ee69673d87 100644 --- a/xbmc/pvr/recordings/PVRRecordings.cpp +++ b/xbmc/pvr/recordings/PVRRecordings.cpp @@ -12,12 +12,8 @@ #include "FileItem.h" #include "ServiceBroker.h" -#include "URL.h" #include "filesystem/Directory.h" -#include "settings/Settings.h" -#include "settings/SettingsComponent.h" #include "threads/SingleLock.h" -#include "utils/StringUtils.h" #include "utils/URIUtils.h" #include "utils/log.h" #include "video/VideoDatabase.h" @@ -44,84 +40,6 @@ void CPVRRecordings::UpdateFromClients(void) CServiceBroker::GetPVRManager().Clients()->GetRecordings(this, true); } -std::string CPVRRecordings::TrimSlashes(const std::string &strOrig) const -{ - std::string strReturn(strOrig); - while (strReturn[0] == '/') - strReturn.erase(0, 1); - - URIUtils::RemoveSlashAtEnd(strReturn); - - return strReturn; -} - -bool CPVRRecordings::IsDirectoryMember(const std::string &strDirectory, const std::string &strEntryDirectory, bool bGrouped) const -{ - std::string strUseDirectory = TrimSlashes(strDirectory); - std::string strUseEntryDirectory = TrimSlashes(strEntryDirectory); - - /* Case-insensitive comparison since sub folders are created with case-insensitive matching (GetSubDirectories) */ - if (bGrouped) - return StringUtils::EqualsNoCase(strUseDirectory, strUseEntryDirectory); - else - return StringUtils::StartsWithNoCase(strUseEntryDirectory, strUseDirectory); -} - -void CPVRRecordings::GetSubDirectories(const CPVRRecordingsPath &recParentPath, CFileItemList *results) -{ - // Only active recordings are fetched to provide sub directories. - // Not applicable for deleted view which is supposed to be flattened. - std::set<CFileItemPtr> unwatchedFolders; - bool bRadio = recParentPath.IsRadio(); - - for (const auto recording : m_recordings) - { - CPVRRecordingPtr current = recording.second; - if (current->IsDeleted()) - continue; - - if (current->IsRadio() != bRadio) - continue; - - const std::string strCurrent(recParentPath.GetUnescapedSubDirectoryPath(current->m_strDirectory)); - if (strCurrent.empty()) - continue; - - CPVRRecordingsPath recChildPath(recParentPath); - recChildPath.AppendSegment(strCurrent); - std::string strFilePath(recChildPath); - - current->UpdateMetadata(GetVideoDatabase()); - - CFileItemPtr pFileItem; - if (!results->Contains(strFilePath)) - { - pFileItem.reset(new CFileItem(strCurrent, true)); - pFileItem->SetPath(strFilePath); - pFileItem->SetLabel(strCurrent); - pFileItem->SetLabelPreformatted(true); - pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); - - // Assume all folders are watched, we'll change the overlay later - pFileItem->SetOverlayImage(CGUIListItem::ICON_OVERLAY_WATCHED, false); - results->Add(pFileItem); - } - else - { - pFileItem = results->Get(strFilePath); - if (pFileItem->m_dateTime < current->RecordingTimeAsLocalTime()) - pFileItem->m_dateTime = current->RecordingTimeAsLocalTime(); - } - - if (current->GetPlayCount() == 0) - unwatchedFolders.insert(pFileItem); - } - - // Change the watched overlay to unwatched for folders containing unwatched entries - for (auto item : unwatchedFolders) - item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, false); -} - int CPVRRecordings::Load(void) { Unload(); @@ -251,76 +169,17 @@ bool CPVRRecordings::IncrementRecordingsPlayCount(const CFileItemPtr &item) return ChangeRecordingsPlayCount(item, INCREMENT_PLAY_COUNT); } -bool CPVRRecordings::GetDirectory(const std::string& strPath, CFileItemList &items) +std::vector<std::shared_ptr<CPVRRecording>> CPVRRecordings::GetAll() const { - CSingleLock lock(m_critSection); - - bool bGrouped = false; - const CURL url(strPath); - if (url.HasOption("view")) - { - const std::string view(url.GetOption("view")); - if (view == "grouped") - bGrouped = true; - else if (view == "flat") - bGrouped = false; - else - { - CLog::LogF(LOGERROR, "Unsupported value '%s' for url parameter 'view'", view.c_str()); - return false; - } - } - else - { - bGrouped = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_PVRRECORD_GROUPRECORDINGS); - } - - CPVRRecordingsPath recPath(url.GetWithoutOptions()); - if (recPath.IsValid()) - { - // Get the directory structure if in non-flatten mode - // Deleted view is always flatten. So only for an active view - std::string strDirectory(recPath.GetUnescapedDirectoryPath()); - if (!recPath.IsDeleted() && bGrouped) - GetSubDirectories(recPath, &items); - - // get all files of the current directory or recursively all files starting at the current directory if in flatten mode - for (const auto recording : m_recordings) - { - const CPVRRecordingPtr current = recording.second; + std::vector<std::shared_ptr<CPVRRecording>> recordings; - // Omit recordings not matching criteria - if (!IsDirectoryMember(strDirectory, current->m_strDirectory, bGrouped) || - current->IsDeleted() != recPath.IsDeleted() || - current->IsRadio() != recPath.IsRadio()) - continue; - - current->UpdateMetadata(GetVideoDatabase()); - - const CFileItemPtr item = std::make_shared<CFileItem>(current); - item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, current->GetPlayCount() > 0); - items.Add(item); - } - } - - return recPath.IsValid(); -} - -void CPVRRecordings::GetAll(CFileItemList &items, bool bDeleted) -{ CSingleLock lock(m_critSection); - for (const auto recording : m_recordings) + for (const auto& recordingEntry : m_recordings) { - const CPVRRecordingPtr current = recording.second; - if (current->IsDeleted() != bDeleted) - continue; - - current->UpdateMetadata(GetVideoDatabase()); - - const CFileItemPtr item = std::make_shared<CFileItem>(current); - item->SetOverlayImage(CGUIListItem::ICON_OVERLAY_UNWATCHED, current->GetPlayCount() > 0); - items.Add(item); + recordings.emplace_back(recordingEntry.second); } + + return recordings; } CFileItemPtr CPVRRecordings::GetById(unsigned int iId) const @@ -367,7 +226,7 @@ CPVRRecordingPtr CPVRRecordings::GetById(int iClientId, const std::string &strRe { CPVRRecordingPtr retVal; CSingleLock lock(m_critSection); - PVR_RECORDINGMAP_CITR it = m_recordings.find(CPVRRecordingUid(iClientId, strRecordingId)); + const auto it = m_recordings.find(CPVRRecordingUid(iClientId, strRecordingId)); if (it != m_recordings.end()) retVal = it->second; diff --git a/xbmc/pvr/recordings/PVRRecordings.h b/xbmc/pvr/recordings/PVRRecordings.h index 4672fb0d40..79352d0d90 100644 --- a/xbmc/pvr/recordings/PVRRecordings.h +++ b/xbmc/pvr/recordings/PVRRecordings.h @@ -70,10 +70,10 @@ namespace PVR */ bool ResetResumePoint(const CFileItemPtr item); - bool GetDirectory(const std::string& strPath, CFileItemList &items); + std::vector<std::shared_ptr<CPVRRecording>> GetAll() const; + CFileItemPtr GetByPath(const std::string &path); CPVRRecordingPtr GetById(int iClientId, const std::string &strRecordingId) const; - void GetAll(CFileItemList &items, bool bDeleted = false); CFileItemPtr GetById(unsigned int iId) const; /*! @@ -83,14 +83,16 @@ namespace PVR */ CPVRRecordingPtr GetRecordingForEpgTag(const CPVREpgInfoTagPtr &epgTag) const; - private: - typedef std::map<CPVRRecordingUid, CPVRRecordingPtr> PVR_RECORDINGMAP; - typedef PVR_RECORDINGMAP::iterator PVR_RECORDINGMAP_ITR; - typedef PVR_RECORDINGMAP::const_iterator PVR_RECORDINGMAP_CITR; + /** + * @brief Get/Open the video database. + * @return A reference to the video database. + */ + CVideoDatabase& GetVideoDatabase(); + private: mutable CCriticalSection m_critSection; bool m_bIsUpdating = false; - PVR_RECORDINGMAP m_recordings; + std::map<CPVRRecordingUid, CPVRRecordingPtr> m_recordings; unsigned int m_iLastId = 0; std::unique_ptr<CVideoDatabase> m_database; bool m_bDeletedTVRecordings = false; @@ -99,15 +101,6 @@ namespace PVR unsigned int m_iRadioRecordings = 0; void UpdateFromClients(void); - std::string TrimSlashes(const std::string &strOrig) const; - bool IsDirectoryMember(const std::string &strDirectory, const std::string &strEntryDirectory, bool bGrouped) const; - void GetSubDirectories(const CPVRRecordingsPath &recParentPath, CFileItemList *results); - - /** - * @brief Get/Open the video database. - * @return A reference to the video database. - */ - CVideoDatabase& GetVideoDatabase(); /** * @brief recursively deletes all recordings in the specified directory diff --git a/xbmc/pvr/timers/PVRTimers.cpp b/xbmc/pvr/timers/PVRTimers.cpp index 23e18c3f9e..b0a2edc124 100644 --- a/xbmc/pvr/timers/PVRTimers.cpp +++ b/xbmc/pvr/timers/PVRTimers.cpp @@ -13,7 +13,6 @@ #include "FileItem.h" #include "ServiceBroker.h" #include "addons/PVRClient.h" -#include "guilib/LocalizeStrings.h" #include "settings/Settings.h" #include "threads/SingleLock.h" #include "utils/log.h" @@ -23,7 +22,6 @@ #include "pvr/addons/PVRClients.h" #include "pvr/channels/PVRChannelGroupsContainer.h" #include "pvr/epg/EpgContainer.h" -#include "pvr/timers/PVRTimersPath.h" using namespace PVR; @@ -78,8 +76,7 @@ CPVRTimers::CPVRTimers(void) CSettings::SETTING_PVRPOWERMANAGEMENT_PREWAKEUP, CSettings::SETTING_PVRPOWERMANAGEMENT_BACKENDIDLETIME, CSettings::SETTING_PVRPOWERMANAGEMENT_DAILYWAKEUPTIME, - CSettings::SETTING_PVRRECORD_TIMERNOTIFICATIONS, - CSettings::SETTING_PVRTIMERS_HIDEDISABLEDTIMERS + CSettings::SETTING_PVRRECORD_TIMERNOTIFICATIONS }) { } @@ -491,93 +488,6 @@ bool CPVRTimers::HasActiveTimers(void) const return false; } -bool CPVRTimers::GetRootDirectory(const CPVRTimersPath &path, CFileItemList &items) const -{ - CFileItemPtr item(new CFileItem(CPVRTimersPath::PATH_ADDTIMER, false)); - item->SetLabel(g_localizeStrings.Get(19026)); // "Add timer..." - item->SetLabelPreformatted(true); - item->SetSpecialSort(SortSpecialOnTop); - item->SetIconImage("DefaultTVShows.png"); - items.Add(item); - - bool bRadio = path.IsRadio(); - bool bRules = path.IsRules(); - - bool bHideDisabled = m_settings.GetBoolValue(CSettings::SETTING_PVRTIMERS_HIDEDISABLEDTIMERS); - - CSingleLock lock(m_critSection); - for (const auto &tagsEntry : m_tags) - { - for (const auto &timer : tagsEntry.second) - { - if ((bRadio == timer->m_bIsRadio || (bRules && timer->m_iClientChannelUid == PVR_TIMER_ANY_CHANNEL)) && - (bRules == timer->IsTimerRule()) && - (!bHideDisabled || (timer->m_state != PVR_TIMER_STATE_DISABLED))) - { - item.reset(new CFileItem(timer)); - std::string strItemPath( - CPVRTimersPath(path.GetPath(), timer->m_iClientId, timer->m_iClientIndex).GetPath()); - item->SetPath(strItemPath); - items.Add(item); - } - } - } - return true; -} - -bool CPVRTimers::GetSubDirectory(const CPVRTimersPath &path, CFileItemList &items) const -{ - bool bRadio = path.IsRadio(); - unsigned int iParentId = path.GetParentId(); - int iClientId = path.GetClientId(); - - bool bHideDisabled = m_settings.GetBoolValue(CSettings::SETTING_PVRTIMERS_HIDEDISABLEDTIMERS); - - CFileItemPtr item; - - CSingleLock lock(m_critSection); - for (const auto &tagsEntry : m_tags) - { - for (const auto &timer : tagsEntry.second) - { - if ((timer->m_bIsRadio == bRadio) && - (timer->m_iParentClientIndex != PVR_TIMER_NO_PARENT) && - (timer->m_iClientId == iClientId) && - (timer->m_iParentClientIndex == iParentId) && - (!bHideDisabled || (timer->m_state != PVR_TIMER_STATE_DISABLED))) - { - item.reset(new CFileItem(timer)); - std::string strItemPath( - CPVRTimersPath(path.GetPath(), timer->m_iClientId, timer->m_iClientIndex).GetPath()); - item->SetPath(strItemPath); - items.Add(item); - } - } - } - return true; -} - -bool CPVRTimers::GetDirectory(const std::string& strPath, CFileItemList &items) const -{ - CPVRTimersPath path(strPath); - if (path.IsValid()) - { - if (path.IsTimersRoot()) - { - /* Root folder containing either timer rules or timers. */ - return GetRootDirectory(path, items); - } - else if (path.IsTimerRule()) - { - /* Sub folder containing the timers scheduled by the given timer rule. */ - return GetSubDirectory(path, items); - } - } - - CLog::LogF(LOGERROR,"Invalid URL %s", strPath.c_str()); - return false; -} - /********** channel methods **********/ bool CPVRTimers::DeleteTimersOnChannel(const CPVRChannelPtr &channel, bool bDeleteTimerRules /* = true */, bool bCurrentlyActiveOnly /* = false */) @@ -823,18 +733,20 @@ void CPVRTimers::UpdateChannels(void) } } -void CPVRTimers::GetAll(CFileItemList& items) const +std::vector<std::shared_ptr<CPVRTimerInfoTag>> CPVRTimers::GetAll() const { - CFileItemPtr item; + std::vector<std::shared_ptr<CPVRTimerInfoTag>> timers; + CSingleLock lock(m_critSection); - for (MapTags::const_iterator it = m_tags.begin(); it != m_tags.end(); ++it) + for (const auto& tagsEntry : m_tags) { - for (VecTimerInfoTag::const_iterator timerIt = it->second.begin(); timerIt != it->second.end(); ++timerIt) + for (const auto& timer : tagsEntry.second) { - item.reset(new CFileItem(*timerIt)); - items.Add(item); + timers.emplace_back(timer); } } + + return timers; } CPVRTimerInfoTagPtr CPVRTimers::GetById(unsigned int iTimerId) const diff --git a/xbmc/pvr/timers/PVRTimers.h b/xbmc/pvr/timers/PVRTimers.h index 4664c37a1b..89d6ddb1b7 100644 --- a/xbmc/pvr/timers/PVRTimers.h +++ b/xbmc/pvr/timers/PVRTimers.h @@ -21,7 +21,6 @@ #include "pvr/timers/PVRTimerInfoTag.h" class CFileItem; -class CFileItemList; typedef std::shared_ptr<CFileItem> CFileItemPtr; namespace PVR @@ -107,9 +106,9 @@ namespace PVR /*! * Get all timers - * @param items The list to add the timers to + * @return The list of all timers */ - void GetAll(CFileItemList& items) const; + std::vector<std::shared_ptr<CPVRTimerInfoTag>> GetAll() const; /*! * @return True when there is at least one timer that is active (states scheduled or recording), false otherwise. @@ -181,14 +180,6 @@ namespace PVR int AmountActiveRadioRecordings(void) const; /*! - * @brief Get all timers for the given path. - * @param strPath The vfs path to get the timers for. - * @param items The results. - * @return True when the path was valid, false otherwise. - */ - bool GetDirectory(const std::string& strPath, CFileItemList &items) const; - - /*! * @brief Delete all timers on a channel. * @param channel The channel to delete the timers for. * @param bDeleteTimerRules True to delete timer rules too, false otherwise. @@ -270,8 +261,6 @@ namespace PVR private: bool UpdateEntries(const CPVRTimersContainer &timers, const std::vector<int> &failedClients); - bool GetRootDirectory(const CPVRTimersPath &path, CFileItemList &items) const; - bool GetSubDirectory(const CPVRTimersPath &path, CFileItemList &items) const; enum TimerKind { diff --git a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp index 37fad820f9..1cf24d72be 100644 --- a/xbmc/pvr/windows/GUIWindowPVRGuide.cpp +++ b/xbmc/pvr/windows/GUIWindowPVRGuide.cpp @@ -623,7 +623,7 @@ bool CGUIWindowPVRGuideBase::RefreshTimelineItems() m_bFirstOpen = false; // very first open of the window. come up with some data very fast... - const std::vector<PVRChannelGroupMember> groupMembers = group->GetMembers(); + const std::vector<PVRChannelGroupMember> groupMembers = group->GetMembers(CPVRChannelGroup::Include::ONLY_VISIBLE); for (const auto& groupMember : groupMembers) { // fake a channel without epg |