summaryrefslogtreecommitdiffstats
path: root/xbmc/pvr/providers/PVRProviders.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xbmc/pvr/providers/PVRProviders.cpp380
1 files changed, 380 insertions, 0 deletions
diff --git a/xbmc/pvr/providers/PVRProviders.cpp b/xbmc/pvr/providers/PVRProviders.cpp
new file mode 100644
index 0000000..6d751a2
--- /dev/null
+++ b/xbmc/pvr/providers/PVRProviders.cpp
@@ -0,0 +1,380 @@
+/*
+ * 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 "PVRProviders.h"
+
+#include "ServiceBroker.h"
+#include "pvr/PVRCachedImages.h"
+#include "pvr/PVRDatabase.h"
+#include "pvr/PVRManager.h"
+#include "pvr/addons/PVRClient.h"
+#include "pvr/addons/PVRClients.h"
+#include "pvr/providers/PVRProvider.h"
+#include "settings/Settings.h"
+#include "utils/log.h"
+
+#include <algorithm>
+#include <memory>
+#include <mutex>
+#include <numeric>
+#include <string>
+#include <vector>
+
+using namespace PVR;
+
+bool CPVRProvidersContainer::UpdateFromClient(const std::shared_ptr<CPVRProvider>& provider)
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ const std::shared_ptr<CPVRProvider> providerToUpdate =
+ GetByClient(provider->GetClientId(), provider->GetUniqueId());
+ if (providerToUpdate)
+ {
+ return providerToUpdate->UpdateEntry(provider, ProviderUpdateMode::BY_CLIENT);
+ }
+ else
+ {
+ provider->SetDatabaseId(++m_iLastId);
+ InsertEntry(provider, ProviderUpdateMode::BY_CLIENT);
+ }
+
+ return true;
+}
+
+std::shared_ptr<CPVRProvider> CPVRProvidersContainer::GetByClient(int iClientId,
+ int iUniqueId) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ const auto it = std::find_if(
+ m_providers.cbegin(), m_providers.cend(), [iClientId, iUniqueId](const auto& provider) {
+ return provider->GetClientId() == iClientId && provider->GetUniqueId() == iUniqueId;
+ });
+ return it != m_providers.cend() ? (*it) : std::shared_ptr<CPVRProvider>();
+}
+
+void CPVRProvidersContainer::InsertEntry(const std::shared_ptr<CPVRProvider>& newProvider,
+ ProviderUpdateMode updateMode)
+{
+ bool found = false;
+ for (auto& provider : m_providers)
+ {
+ if (provider->GetClientId() == newProvider->GetClientId() &&
+ provider->GetUniqueId() == newProvider->GetUniqueId())
+ {
+ found = true;
+ provider->UpdateEntry(newProvider, updateMode);
+ }
+ }
+
+ if (!found)
+ {
+ m_providers.emplace_back(newProvider);
+ }
+}
+
+std::vector<std::shared_ptr<CPVRProvider>> CPVRProvidersContainer::GetProvidersList() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return m_providers;
+}
+
+std::size_t CPVRProvidersContainer::GetNumProviders() const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ return m_providers.size();
+}
+
+bool CPVRProviders::Update(const std::vector<std::shared_ptr<CPVRClient>>& clients)
+{
+ return LoadFromDatabase(clients) && UpdateFromClients(clients);
+}
+
+void CPVRProviders::Unload()
+{
+ // remove all tags
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ m_providers.clear();
+}
+
+bool CPVRProviders::LoadFromDatabase(const std::vector<std::shared_ptr<CPVRClient>>& clients)
+{
+ const std::shared_ptr<CPVRDatabase> database = CServiceBroker::GetPVRManager().GetTVDatabase();
+ if (database)
+ {
+ m_iLastId = database->GetMaxProviderId();
+
+ CPVRProviders providers;
+ database->Get(providers, clients);
+
+ for (auto& provider : providers.GetProvidersList())
+ CheckAndAddEntry(provider, ProviderUpdateMode::BY_DATABASE);
+ }
+ return true;
+}
+
+bool CPVRProviders::UpdateFromClients(const std::vector<std::shared_ptr<CPVRClient>>& clients)
+{
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ if (m_bIsUpdating)
+ return false;
+ m_bIsUpdating = true;
+ }
+
+ // Default client providers are the add-ons themselves, we retrieve both enabled
+ // and disabled add-ons as we don't want them removed from the DB
+ CPVRProviders newAddonProviderList;
+ std::vector<int> disabledClients;
+ std::vector<CVariant> clientProviderInfos =
+ CServiceBroker::GetPVRManager().Clients()->GetClientProviderInfos();
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Adding default providers, found {} PVR add-ons",
+ clientProviderInfos.size());
+ for (const auto& clientInfo : clientProviderInfos)
+ {
+ auto addonProvider = std::make_shared<CPVRProvider>(
+ clientInfo["clientid"].asInteger32(), clientInfo["name"].asString(),
+ clientInfo["icon"].asString(), clientInfo["thumb"].asString());
+
+ newAddonProviderList.CheckAndAddEntry(addonProvider, ProviderUpdateMode::BY_CLIENT);
+
+ if (!clientInfo["enabled"].asBoolean())
+ disabledClients.emplace_back(clientInfo["clientid"].asInteger32());
+ }
+ UpdateDefaultEntries(newAddonProviderList);
+
+ // Client providers are retrieved from the clients
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Updating providers");
+ CPVRProvidersContainer newProviderList;
+ std::vector<int> failedClients;
+ CServiceBroker::GetPVRManager().Clients()->GetProviders(clients, &newProviderList, failedClients);
+ return UpdateClientEntries(newProviderList, failedClients, disabledClients);
+}
+
+bool CPVRProviders::UpdateDefaultEntries(const CPVRProvidersContainer& newProviders)
+{
+ bool bChanged = false;
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ // go through the provider list and check for updated or new providers
+ const auto newProviderList = newProviders.GetProvidersList();
+ bChanged = std::accumulate(
+ newProviderList.cbegin(), newProviderList.cend(), false,
+ [this](bool changed, const auto& newProvider) {
+ return (CheckAndPersistEntry(newProvider, ProviderUpdateMode::BY_CLIENT) != nullptr)
+ ? true
+ : changed;
+ });
+
+ // check for deleted providers
+ for (std::vector<std::shared_ptr<CPVRProvider>>::iterator it = m_providers.begin();
+ it != m_providers.end();)
+ {
+ const std::shared_ptr<CPVRProvider> provider = *it;
+ if (!newProviders.GetByClient(provider->GetClientId(), provider->GetUniqueId()))
+ {
+ // provider was not found
+ bool bIgnoreProvider = false;
+
+ // ignore add-on any providers that are no PVR Client addon providers
+ if (!provider->IsClientProvider())
+ bIgnoreProvider = true;
+
+ if (bIgnoreProvider)
+ {
+ ++it;
+ continue;
+ }
+
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Deleted provider {} on client {}", provider->GetUniqueId(),
+ provider->GetClientId());
+
+ (*it)->DeleteFromDatabase();
+ it = m_providers.erase(it);
+
+ bChanged |= true;
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ return bChanged;
+}
+
+bool CPVRProviders::UpdateClientEntries(const CPVRProvidersContainer& newProviders,
+ const std::vector<int>& failedClients,
+ const std::vector<int>& disabledClients)
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ // go through the provider list and check for updated or new providers
+ for (const auto& newProvider : newProviders.GetProvidersList())
+ {
+ CheckAndPersistEntry(newProvider, ProviderUpdateMode::BY_CLIENT);
+ }
+
+ // check for deleted providers
+ for (auto it = m_providers.begin(); it != m_providers.end();)
+ {
+ const std::shared_ptr<CPVRProvider> provider = *it;
+ if (!newProviders.GetByClient(provider->GetClientId(), provider->GetUniqueId()))
+ {
+ const bool bIgnoreProvider =
+ (provider->IsClientProvider() || // ignore add-on providers as they are a special case
+ std::any_of(failedClients.cbegin(), failedClients.cend(),
+ [&provider](const auto& failedClient) {
+ return failedClient == provider->GetClientId();
+ }) ||
+ std::any_of(disabledClients.cbegin(), disabledClients.cend(),
+ [&provider](const auto& disabledClient) {
+ return disabledClient == provider->GetClientId();
+ }));
+ if (bIgnoreProvider)
+ {
+ ++it;
+ continue;
+ }
+
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Deleted provider {} on client {}", provider->GetUniqueId(),
+ provider->GetClientId());
+
+ (*it)->DeleteFromDatabase();
+ it = m_providers.erase(it);
+ }
+ else
+ {
+ ++it;
+ }
+ }
+
+ m_bIsUpdating = false;
+
+ return true;
+}
+
+std::shared_ptr<CPVRProvider> CPVRProviders::CheckAndAddEntry(
+ const std::shared_ptr<CPVRProvider>& newProvider, ProviderUpdateMode updateMode)
+{
+ bool bChanged = false;
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ std::shared_ptr<CPVRProvider> provider =
+ GetByClient(newProvider->GetClientId(), newProvider->GetUniqueId());
+ if (provider)
+ {
+ bChanged = provider->UpdateEntry(newProvider, updateMode);
+ }
+ else
+ {
+ // We don't set an id as this came from the DB so it has one already
+ InsertEntry(newProvider, updateMode);
+
+ if (newProvider->GetDatabaseId() > m_iLastId)
+ m_iLastId = newProvider->GetDatabaseId();
+
+ provider = newProvider;
+ bChanged = true;
+ }
+
+ if (bChanged)
+ return provider;
+
+ return {};
+}
+
+std::shared_ptr<CPVRProvider> CPVRProviders::CheckAndPersistEntry(
+ const std::shared_ptr<CPVRProvider>& newProvider, ProviderUpdateMode updateMode)
+{
+ bool bChanged = false;
+
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ std::shared_ptr<CPVRProvider> provider =
+ GetByClient(newProvider->GetClientId(), newProvider->GetUniqueId());
+ if (provider)
+ {
+ bChanged = provider->UpdateEntry(newProvider, updateMode);
+
+ if (bChanged)
+ provider->Persist(true);
+
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Updated provider {} on client {}", newProvider->GetUniqueId(),
+ newProvider->GetClientId());
+ }
+ else
+ {
+ newProvider->SetDatabaseId(++m_iLastId);
+ InsertEntry(newProvider, updateMode);
+
+ newProvider->Persist();
+
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Added provider {} on client {}", newProvider->GetUniqueId(),
+ newProvider->GetClientId());
+
+ provider = newProvider;
+ bChanged = true;
+ }
+
+ if (bChanged)
+ return provider;
+
+ return {};
+}
+
+bool CPVRProviders::PersistUserChanges(const std::vector<std::shared_ptr<CPVRProvider>>& providers)
+{
+ for (const auto& provider : providers)
+ {
+ provider->Persist(true);
+
+ CLog::LogFC(LOGDEBUG, LOGPVR, "Updated provider {} on client {}", provider->GetUniqueId(),
+ provider->GetClientId());
+ }
+
+ return true;
+}
+
+std::shared_ptr<CPVRProvider> CPVRProviders::GetById(int iProviderId) const
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+ const auto it =
+ std::find_if(m_providers.cbegin(), m_providers.cend(), [iProviderId](const auto& provider) {
+ return provider->GetDatabaseId() == iProviderId;
+ });
+ return it != m_providers.cend() ? (*it) : std::shared_ptr<CPVRProvider>();
+}
+
+void CPVRProviders::RemoveEntry(const std::shared_ptr<CPVRProvider>& provider)
+{
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ m_providers.erase(
+ std::remove_if(m_providers.begin(), m_providers.end(),
+ [&provider](const std::shared_ptr<CPVRProvider>& providerToRemove) {
+ return provider->GetClientId() == providerToRemove->GetClientId() &&
+ provider->GetUniqueId() == providerToRemove->GetUniqueId();
+ }),
+ m_providers.end());
+}
+
+int CPVRProviders::CleanupCachedImages()
+{
+ std::vector<std::string> urlsToCheck;
+ {
+ std::unique_lock<CCriticalSection> lock(m_critSection);
+
+ for (const auto& provider : m_providers)
+ {
+ urlsToCheck.emplace_back(provider->GetClientIconPath());
+ urlsToCheck.emplace_back(provider->GetClientThumbPath());
+ }
+ }
+
+ static const std::vector<PVRImagePattern> urlPatterns = {{CPVRProvider::IMAGE_OWNER_PATTERN, ""}};
+ return CPVRCachedImages::Cleanup(urlPatterns, urlsToCheck);
+}