aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/resource.language.en_gb/resources/strings.po8
-rw-r--r--xbmc/pvr/channels/CMakeLists.txt2
-rw-r--r--xbmc/pvr/channels/PVRChannelGroup.h16
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupAllChannels.h2
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.cpp95
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.h95
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupFactory.cpp31
-rw-r--r--xbmc/pvr/channels/PVRChannelGroupFactory.h11
-rw-r--r--xbmc/pvr/channels/PVRChannelGroups.cpp37
-rw-r--r--xbmc/pvr/channels/PVRChannelGroups.h2
10 files changed, 286 insertions, 13 deletions
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index 53523fc9e6..ab0a84adac 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -3996,7 +3996,13 @@ msgctxt "#858"
msgid "User"
msgstr ""
-#empty strings from id 859 to 996
+#. Label postfix for channel groups containing content from all channels (e.g. "PVR Client 1 [All channels]")
+#: xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.cpp
+msgctxt "#859"
+msgid "{0:s} [All channels]"
+msgstr ""
+
+#empty strings from id 860 to 996
#: xbmc/windows/GUIMediaWindow.cpp
msgctxt "#997"
diff --git a/xbmc/pvr/channels/CMakeLists.txt b/xbmc/pvr/channels/CMakeLists.txt
index c1eb19f4df..7094e029e6 100644
--- a/xbmc/pvr/channels/CMakeLists.txt
+++ b/xbmc/pvr/channels/CMakeLists.txt
@@ -2,6 +2,7 @@ set(SOURCES PVRChannel.cpp
PVRChannelGroup.cpp
PVRChannelGroupAllChannels.cpp
PVRChannelGroupFactory.cpp
+ PVRChannelGroupAllChannelsSingleClient.cpp
PVRChannelGroupFromClient.cpp
PVRChannelGroupMember.cpp
PVRChannelGroupSettings.cpp
@@ -15,6 +16,7 @@ set(HEADERS PVRChannel.h
PVRChannelGroup.h
PVRChannelGroupAllChannels.h
PVRChannelGroupFactory.h
+ PVRChannelGroupAllChannelsSingleClient.h
PVRChannelGroupFromClient.h
PVRChannelGroupFromUser.h
PVRChannelGroupMember.h
diff --git a/xbmc/pvr/channels/PVRChannelGroup.h b/xbmc/pvr/channels/PVRChannelGroup.h
index 4582a273a3..af521abf98 100644
--- a/xbmc/pvr/channels/PVRChannelGroup.h
+++ b/xbmc/pvr/channels/PVRChannelGroup.h
@@ -25,8 +25,9 @@ struct PVR_CHANNEL_GROUP;
namespace PVR
{
static constexpr int PVR_GROUP_TYPE_CLIENT = 0;
-static constexpr int PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS = 1;
+static constexpr int PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_ALL_CLIENTS = 1;
static constexpr int PVR_GROUP_TYPE_USER = 2;
+static constexpr int PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_SINGLE_CLIENT = 3;
static constexpr int PVR_GROUP_CLIENT_ID_UNKNOWN = -2;
static constexpr int PVR_GROUP_CLIENT_ID_LOCAL = -1;
@@ -526,6 +527,19 @@ public:
virtual bool ShouldBeIgnored(
const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups) const;
+ /*!
+ * @brief Update all group members.
+ * @param allChannelsGroup The all channels group.
+ * @param allChannelGroups All available channel groups.
+ * @return True on success, false otherwise.
+ */
+ virtual bool UpdateGroupMembers(
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups)
+ {
+ return true;
+ }
+
protected:
/*!
* @brief Remove deleted group members from this group.
diff --git a/xbmc/pvr/channels/PVRChannelGroupAllChannels.h b/xbmc/pvr/channels/PVRChannelGroupAllChannels.h
index a51aadae76..53e166c830 100644
--- a/xbmc/pvr/channels/PVRChannelGroupAllChannels.h
+++ b/xbmc/pvr/channels/PVRChannelGroupAllChannels.h
@@ -62,7 +62,7 @@ public:
/*!
* @brief Return the type of this group.
*/
- int GroupType() const override { return PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS; }
+ int GroupType() const override { return PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_ALL_CLIENTS; }
/*!
* @brief Check whether this group could be deleted by the user.
diff --git a/xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.cpp b/xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.cpp
new file mode 100644
index 0000000000..40b1649ecc
--- /dev/null
+++ b/xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 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 "PVRChannelGroupAllChannelsSingleClient.h"
+
+#include "ServiceBroker.h"
+#include "guilib/LocalizeStrings.h"
+#include "pvr/PVRManager.h"
+#include "pvr/addons/PVRClient.h"
+#include "pvr/channels/PVRChannelGroupMember.h"
+#include "pvr/channels/PVRChannelsPath.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include <algorithm>
+#include <unordered_set>
+
+using namespace PVR;
+
+std::vector<std::shared_ptr<CPVRChannelGroup>> CPVRChannelGroupAllChannelsSingleClient::
+ CreateMissingGroups(const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups)
+{
+ const std::vector<std::shared_ptr<CPVRChannelGroupMember>> allGroupMembers{
+ allChannelsGroup->GetMembers()};
+
+ // Create a unique list of active client ids from current members of the all channels list.
+ std::unordered_set<int> clientIds;
+ for (const auto& member : allGroupMembers)
+ {
+ clientIds.insert(member->ChannelClientID());
+ }
+
+ // If only one client is active, global all channels group would be identical to the all
+ // channels group for the client. No need to create it.
+ if (clientIds.size() <= 1)
+ return {};
+
+ std::vector<std::shared_ptr<CPVRChannelGroup>> addedGroups;
+
+ for (int clientId : clientIds)
+ {
+ const std::shared_ptr<const CPVRClient> client{
+ CServiceBroker().GetPVRManager().GetClient(clientId)};
+ if (!client)
+ {
+ CLog::LogFC(LOGERROR, LOGPVR, "Failed to get client instance for client id {}", clientId);
+ continue;
+ }
+
+ // Create a group containg all channels for this client, if not yet existing.
+ const auto it = std::find_if(allChannelGroups.cbegin(), allChannelGroups.cend(),
+ [&client](const auto& group)
+ {
+ return (group->GroupType() ==
+ PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_SINGLE_CLIENT) &&
+ (group->GetClientID() == client->GetID());
+ });
+ if (it == allChannelGroups.cend())
+ {
+ const std::string name{
+ StringUtils::Format(g_localizeStrings.Get(859), client->GetFullClientName())};
+ const CPVRChannelsPath path{allChannelsGroup->IsRadio(), name, client->GetID()};
+ addedGroups.emplace_back(
+ std::make_shared<CPVRChannelGroupAllChannelsSingleClient>(path, allChannelsGroup));
+ }
+ }
+
+ return addedGroups;
+}
+
+bool CPVRChannelGroupAllChannelsSingleClient::UpdateGroupMembers(
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups)
+{
+ std::vector<std::shared_ptr<CPVRChannelGroupMember>> groupMembers;
+
+ // Collect and populate matching members.
+ const auto allChannelsGroupMembers{allChannelsGroup->GetMembers()};
+ for (const auto& member : allChannelsGroupMembers)
+ {
+ if (member->ChannelClientID() != GetClientID())
+ continue;
+
+ groupMembers.emplace_back(std::make_shared<CPVRChannelGroupMember>(
+ GroupID(), GroupName(), GetClientID(), member->Channel()));
+ }
+
+ return UpdateGroupEntries(groupMembers);
+}
diff --git a/xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.h b/xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.h
new file mode 100644
index 0000000000..9e096c9a27
--- /dev/null
+++ b/xbmc/pvr/channels/PVRChannelGroupAllChannelsSingleClient.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 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 "pvr/channels/PVRChannelGroup.h"
+
+namespace PVR
+{
+
+class CPVRChannelGroupAllChannelsSingleClient : public CPVRChannelGroup
+{
+public:
+ /*!
+ * @brief Create a new channel group instance.
+ * @param path The channel group path.
+ * @param allChannelsGroup The channel group containing all TV or radio channels.
+ */
+ CPVRChannelGroupAllChannelsSingleClient(
+ const CPVRChannelsPath& path, const std::shared_ptr<const CPVRChannelGroup>& allChannelsGroup)
+ : CPVRChannelGroup(path, allChannelsGroup)
+ {
+ }
+
+ /*!
+ * @brief Get the group's origin.
+ * @return The origin.
+ */
+ Origin GetOrigin() const override { return Origin::SYSTEM; }
+
+ /*!
+ * @brief Return the type of this group.
+ */
+ int GroupType() const override { return PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_SINGLE_CLIENT; }
+
+ /*!
+ * @brief Check whether this group could be deleted by the user.
+ * @return True if the group could be deleted, false otherwise.
+ */
+ bool SupportsDelete() const override { return false; }
+
+ /*!
+ * @brief Check whether members could be added to this group by the user.
+ * @return True if members could be added, false otherwise.
+ */
+ bool SupportsMemberAdd() const override { return false; }
+
+ /*!
+ * @brief Check whether members could be removed from this group by the user.
+ * @return True if members could be removed, false otherwise.
+ */
+ bool SupportsMemberRemove() const override { return false; }
+
+ /*!
+ * @brief Check whether this group is owner of the channel instances it contains.
+ * @return True if owner, false otherwise.
+ */
+ bool IsChannelsOwner() const override { return false; }
+
+ /*!
+ * @brief Update data with channel group members from the given clients, sync with local data.
+ * @param clients The clients to fetch data from. Leave empty to fetch data from all created clients.
+ * @return True on success, false otherwise.
+ */
+ bool UpdateFromClients(const std::vector<std::shared_ptr<CPVRClient>>& clients) override
+ {
+ return true; // Nothing to update from any client for locally managed groups.
+ }
+
+ /*!
+ * @brief Create any missing channel groups (e.g. after an update of groups/members/clients).
+ * @param allChannelsGroup The all channels group.
+ * @param allChannelGroups All channel groups.
+ * @return The newly created groups, if any.
+ */
+ static std::vector<std::shared_ptr<CPVRChannelGroup>> CreateMissingGroups(
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups);
+
+ /*!
+ * @brief Update all group members.
+ * @param allChannelsGroup The all channels group.
+ * @param allChannelGroups All available channel groups.
+ * @return True on success, false otherwise.
+ */
+ bool UpdateGroupMembers(
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups) override;
+};
+} // namespace PVR
diff --git a/xbmc/pvr/channels/PVRChannelGroupFactory.cpp b/xbmc/pvr/channels/PVRChannelGroupFactory.cpp
index a895b53554..0eec8b5e08 100644
--- a/xbmc/pvr/channels/PVRChannelGroupFactory.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroupFactory.cpp
@@ -9,6 +9,7 @@
#include "PVRChannelGroupFactory.h"
#include "pvr/channels/PVRChannelGroupAllChannels.h"
+#include "pvr/channels/PVRChannelGroupAllChannelsSingleClient.h"
#include "pvr/channels/PVRChannelGroupFromClient.h"
#include "pvr/channels/PVRChannelGroupFromUser.h"
#include "pvr/channels/PVRChannelsPath.h"
@@ -45,10 +46,12 @@ std::shared_ptr<CPVRChannelGroup> CPVRChannelGroupFactory::CreateGroup(
{
switch (groupType)
{
- case PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS:
+ case PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_ALL_CLIENTS:
return std::make_shared<CPVRChannelGroupAllChannels>(groupPath);
case PVR_GROUP_TYPE_USER:
return std::make_shared<CPVRChannelGroupFromUser>(groupPath, allChannels);
+ case PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_SINGLE_CLIENT:
+ return std::make_shared<CPVRChannelGroupAllChannelsSingleClient>(groupPath, allChannels);
case PVR_GROUP_TYPE_CLIENT:
return std::make_shared<CPVRChannelGroupFromClient>(groupPath, allChannels);
default:
@@ -63,13 +66,31 @@ int CPVRChannelGroupFactory::GetGroupTypePriority(
{
switch (group->GroupType())
{
- case PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS:
+ // System groups, created and managed by Kodi
+ case PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_ALL_CLIENTS:
return 0; // highest
- case PVR_GROUP_TYPE_USER:
+ case PVR_GROUP_TYPE_SYSTEM_ALL_CHANNELS_SINGLE_CLIENT:
return 1;
+
+ // User groups, created and managed by the user
+ case PVR_GROUP_TYPE_USER:
+ return 20;
+
+ // Client groups, created and managed by a PVR client add-on
case PVR_GROUP_TYPE_CLIENT:
- return 2;
+ return 40;
+
default:
- return 3;
+ CLog::LogFC(LOGWARNING, LOGPVR, "Using default priority for group '{}' with type {}'.",
+ group->GroupName(), group->GroupType());
+ return 60;
}
}
+
+std::vector<std::shared_ptr<CPVRChannelGroup>> CPVRChannelGroupFactory::CreateMissingGroups(
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups)
+{
+ return CPVRChannelGroupAllChannelsSingleClient::CreateMissingGroups(allChannelsGroup,
+ allChannelGroups);
+}
diff --git a/xbmc/pvr/channels/PVRChannelGroupFactory.h b/xbmc/pvr/channels/PVRChannelGroupFactory.h
index 569eb9b332..8f126b09d3 100644
--- a/xbmc/pvr/channels/PVRChannelGroupFactory.h
+++ b/xbmc/pvr/channels/PVRChannelGroupFactory.h
@@ -9,6 +9,7 @@
#pragma once
#include <memory>
+#include <vector>
struct PVR_CHANNEL_GROUP;
@@ -73,5 +74,15 @@ public:
* @return The group's type priority.
*/
int GetGroupTypePriority(const std::shared_ptr<const CPVRChannelGroup>& group) const;
+
+ /*!
+ * @brief Create any missing channel groups (e.g. after an update of groups/members/clients).
+ * @param allChannelsGroup The all channels group.
+ * @param allChannelGroups All channel groups.
+ * @return The newly created groups, if any.
+ */
+ std::vector<std::shared_ptr<CPVRChannelGroup>> CreateMissingGroups(
+ const std::shared_ptr<CPVRChannelGroup>& allChannelsGroup,
+ const std::vector<std::shared_ptr<CPVRChannelGroup>>& allChannelGroups);
};
} // namespace PVR
diff --git a/xbmc/pvr/channels/PVRChannelGroups.cpp b/xbmc/pvr/channels/PVRChannelGroups.cpp
index 45008d81dd..97033d73fd 100644
--- a/xbmc/pvr/channels/PVRChannelGroups.cpp
+++ b/xbmc/pvr/channels/PVRChannelGroups.cpp
@@ -359,15 +359,15 @@ bool CPVRChannelGroups::UpdateFromClients(const std::vector<std::shared_ptr<CPVR
CLog::LogFC(LOGERROR, LOGPVR, "Failed to update channel group '{}'", group->GroupName());
bReturn = false;
}
- }
- if (bReturn && group->IsChannelsOwner() &&
- CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRChannelIconsAutoScan)
- {
- CServiceBroker::GetPVRManager().TriggerSearchMissingChannelIcons(group);
+ if (bReturn && group->IsChannelsOwner() &&
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_bPVRChannelIconsAutoScan)
+ CServiceBroker::GetPVRManager().TriggerSearchMissingChannelIcons(group);
}
}
+ UpdateSystemChannelGroups();
+
if (bChannelsOnly)
{
// changes in the all channels group may require resorting/renumbering of other groups.
@@ -381,6 +381,32 @@ bool CPVRChannelGroups::UpdateFromClients(const std::vector<std::shared_ptr<CPVR
return PersistAll() && bReturn;
}
+void CPVRChannelGroups::UpdateSystemChannelGroups()
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ // Update existing groups
+ for (const auto& group : m_groups)
+ {
+ group->UpdateGroupMembers(GetGroupAll(), m_groups);
+ }
+
+ // Determine new groups needed
+ const std::vector<std::shared_ptr<CPVRChannelGroup>> newGroups{
+ GetGroupFactory()->CreateMissingGroups(GetGroupAll(), m_groups)};
+
+ // Update new groups
+ for (const auto& group : newGroups)
+ {
+ group->UpdateGroupMembers(GetGroupAll(), m_groups);
+ }
+
+ if (!newGroups.empty())
+ m_groups.insert(m_groups.end(), newGroups.cbegin(), newGroups.cend());
+
+ SortGroups();
+}
+
bool CPVRChannelGroups::UpdateChannelNumbersFromAllChannelsGroup()
{
std::unique_lock<CCriticalSection> lock(m_critSection);
@@ -616,6 +642,7 @@ void CPVRChannelGroups::GroupStateChanged(const std::shared_ptr<CPVRChannelGroup
else
group->Persist();
+ UpdateSystemChannelGroups();
CServiceBroker::GetPVRManager().PublishEvent(PVREvent::ChannelGroupsInvalidated);
}
diff --git a/xbmc/pvr/channels/PVRChannelGroups.h b/xbmc/pvr/channels/PVRChannelGroups.h
index 8df9c5c525..b14a602611 100644
--- a/xbmc/pvr/channels/PVRChannelGroups.h
+++ b/xbmc/pvr/channels/PVRChannelGroups.h
@@ -294,6 +294,8 @@ private:
void GroupStateChanged(const std::shared_ptr<CPVRChannelGroup>& group,
GroupState state = GroupState::CHANGED);
+ void UpdateSystemChannelGroups();
+
bool m_bRadio{false};
std::vector<std::shared_ptr<CPVRChannelGroup>> m_groups;
mutable CCriticalSection m_critSection;