summaryrefslogtreecommitdiffstats
path: root/xbmc/interfaces/json-rpc/AddonsOperations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/interfaces/json-rpc/AddonsOperations.cpp')
-rw-r--r--xbmc/interfaces/json-rpc/AddonsOperations.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/xbmc/interfaces/json-rpc/AddonsOperations.cpp b/xbmc/interfaces/json-rpc/AddonsOperations.cpp
new file mode 100644
index 0000000..db6c90a
--- /dev/null
+++ b/xbmc/interfaces/json-rpc/AddonsOperations.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2011-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 "AddonsOperations.h"
+
+#include "JSONUtils.h"
+#include "ServiceBroker.h"
+#include "TextureCache.h"
+#include "addons/AddonDatabase.h"
+#include "addons/AddonManager.h"
+#include "addons/PluginSource.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/addoninfo/AddonType.h"
+#include "messaging/ApplicationMessenger.h"
+#include "utils/FileUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+
+using namespace JSONRPC;
+using namespace ADDON;
+
+JSONRPC_STATUS CAddonsOperations::GetAddons(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::vector<AddonType> addonTypes;
+ AddonType addonType = CAddonInfo::TranslateType(parameterObject["type"].asString());
+ CPluginSource::Content content = CPluginSource::Translate(parameterObject["content"].asString());
+ CVariant enabled = parameterObject["enabled"];
+ CVariant installed = parameterObject["installed"];
+
+ // ignore the "content" parameter if the type is specified but not a plugin or script
+ if (addonType != AddonType::UNKNOWN && addonType != AddonType::PLUGIN &&
+ addonType != AddonType::SCRIPT)
+ content = CPluginSource::UNKNOWN;
+
+ if (addonType >= AddonType::VIDEO && addonType <= AddonType::EXECUTABLE)
+ {
+ addonTypes.push_back(AddonType::PLUGIN);
+ addonTypes.push_back(AddonType::SCRIPT);
+
+ switch (addonType)
+ {
+ case AddonType::VIDEO:
+ content = CPluginSource::VIDEO;
+ break;
+ case AddonType::AUDIO:
+ content = CPluginSource::AUDIO;
+ break;
+ case AddonType::IMAGE:
+ content = CPluginSource::IMAGE;
+ break;
+ case AddonType::GAME:
+ content = CPluginSource::GAME;
+ break;
+ case AddonType::EXECUTABLE:
+ content = CPluginSource::EXECUTABLE;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ addonTypes.push_back(addonType);
+
+ VECADDONS addons;
+ for (const auto& typeIt : addonTypes)
+ {
+ VECADDONS typeAddons;
+ if (typeIt == AddonType::UNKNOWN)
+ {
+ if (!enabled.isBoolean()) //All
+ {
+ if (!installed.isBoolean() || installed.asBoolean())
+ CServiceBroker::GetAddonMgr().GetInstalledAddons(typeAddons);
+ if (!installed.isBoolean() || (installed.isBoolean() && !installed.asBoolean()))
+ CServiceBroker::GetAddonMgr().GetInstallableAddons(typeAddons);
+ }
+ else if (enabled.asBoolean() && (!installed.isBoolean() || installed.asBoolean())) //Enabled
+ CServiceBroker::GetAddonMgr().GetAddons(typeAddons);
+ else if (!installed.isBoolean() || installed.asBoolean())
+ CServiceBroker::GetAddonMgr().GetDisabledAddons(typeAddons);
+ }
+ else
+ {
+ if (!enabled.isBoolean()) //All
+ {
+ if (!installed.isBoolean() || installed.asBoolean())
+ CServiceBroker::GetAddonMgr().GetInstalledAddons(typeAddons, typeIt);
+ if (!installed.isBoolean() || (installed.isBoolean() && !installed.asBoolean()))
+ CServiceBroker::GetAddonMgr().GetInstallableAddons(typeAddons, typeIt);
+ }
+ else if (enabled.asBoolean() && (!installed.isBoolean() || installed.asBoolean())) //Enabled
+ CServiceBroker::GetAddonMgr().GetAddons(typeAddons, typeIt);
+ else if (!installed.isBoolean() || installed.asBoolean())
+ CServiceBroker::GetAddonMgr().GetDisabledAddons(typeAddons, typeIt);
+ }
+
+ addons.insert(addons.end(), typeAddons.begin(), typeAddons.end());
+ }
+
+ // remove library addons
+ for (int index = 0; index < (int)addons.size(); index++)
+ {
+ std::shared_ptr<CPluginSource> plugin;
+ if (content != CPluginSource::UNKNOWN)
+ plugin = std::dynamic_pointer_cast<CPluginSource>(addons.at(index));
+
+ if ((addons.at(index)->Type() <= AddonType::UNKNOWN ||
+ addons.at(index)->Type() >= AddonType::MAX_TYPES) ||
+ ((content != CPluginSource::UNKNOWN && plugin == NULL) ||
+ (plugin != NULL && !plugin->Provides(content))))
+ {
+ addons.erase(addons.begin() + index);
+ index--;
+ }
+ }
+
+ int start, end;
+ HandleLimits(parameterObject, result, addons.size(), start, end);
+
+ CAddonDatabase addondb;
+ for (int index = start; index < end; index++)
+ FillDetails(addons.at(index), parameterObject["properties"], result["addons"], addondb, true);
+
+ return OK;
+}
+
+JSONRPC_STATUS CAddonsOperations::GetAddonDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string id = parameterObject["addonid"].asString();
+ AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(id, addon, OnlyEnabled::CHOICE_NO) ||
+ addon.get() == NULL || addon->Type() <= AddonType::UNKNOWN ||
+ addon->Type() >= AddonType::MAX_TYPES)
+ return InvalidParams;
+
+ CAddonDatabase addondb;
+ FillDetails(addon, parameterObject["properties"], result["addon"], addondb);
+
+ return OK;
+}
+
+JSONRPC_STATUS CAddonsOperations::SetAddonEnabled(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string id = parameterObject["addonid"].asString();
+ AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(id, addon, OnlyEnabled::CHOICE_NO) ||
+ addon == nullptr || addon->Type() <= AddonType::UNKNOWN ||
+ addon->Type() >= AddonType::MAX_TYPES)
+ return InvalidParams;
+
+ bool disabled = false;
+ if (parameterObject["enabled"].isBoolean())
+ {
+ disabled = !parameterObject["enabled"].asBoolean();
+ }
+ // we need to toggle the current disabled state of the addon
+ else if (parameterObject["enabled"].isString())
+ {
+ disabled = !CServiceBroker::GetAddonMgr().IsAddonDisabled(id);
+ }
+ else
+ {
+ return InvalidParams;
+ }
+
+ bool success = disabled
+ ? CServiceBroker::GetAddonMgr().DisableAddon(id, AddonDisabledReason::USER)
+ : CServiceBroker::GetAddonMgr().EnableAddon(id);
+
+ return success ? ACK : InvalidParams;
+}
+
+JSONRPC_STATUS CAddonsOperations::ExecuteAddon(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
+{
+ std::string id = parameterObject["addonid"].asString();
+ AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(id, addon, OnlyEnabled::CHOICE_YES) ||
+ addon.get() == NULL || addon->Type() < AddonType::VISUALIZATION ||
+ addon->Type() >= AddonType::MAX_TYPES)
+ return InvalidParams;
+
+ std::string argv;
+ CVariant params = parameterObject["params"];
+ if (params.isObject())
+ {
+ for (CVariant::const_iterator_map it = params.begin_map(); it != params.end_map(); ++it)
+ {
+ if (it != params.begin_map())
+ argv += ",";
+ argv += it->first + "=" + it->second.asString();
+ }
+ }
+ else if (params.isArray())
+ {
+ for (CVariant::const_iterator_array it = params.begin_array(); it != params.end_array(); ++it)
+ {
+ if (it != params.begin_array())
+ argv += ",";
+ argv += StringUtils::Paramify(it->asString());
+ }
+ }
+ else if (params.isString())
+ {
+ if (!params.empty())
+ argv = StringUtils::Paramify(params.asString());
+ }
+
+ std::string cmd;
+ if (params.empty())
+ cmd = StringUtils::Format("RunAddon({})", id);
+ else
+ cmd = StringUtils::Format("RunAddon({}, {})", id, argv);
+
+ if (params["wait"].asBoolean())
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);
+ else
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);
+
+ return ACK;
+}
+
+static CVariant Serialize(const AddonPtr& addon)
+{
+ CVariant variant;
+ variant["addonid"] = addon->ID();
+ variant["type"] = CAddonInfo::TranslateType(addon->Type(), false);
+ variant["name"] = addon->Name();
+ variant["version"] = addon->Version().asString();
+ variant["summary"] = addon->Summary();
+ variant["description"] = addon->Description();
+ variant["path"] = addon->Path();
+ variant["author"] = addon->Author();
+ variant["thumbnail"] = addon->Icon();
+ variant["disclaimer"] = addon->Disclaimer();
+ variant["fanart"] = addon->FanArt();
+
+ variant["dependencies"] = CVariant(CVariant::VariantTypeArray);
+ for (const auto& dep : addon->GetDependencies())
+ {
+ CVariant info(CVariant::VariantTypeObject);
+ info["addonid"] = dep.id;
+ info["minversion"] = dep.versionMin.asString();
+ info["version"] = dep.version.asString();
+ info["optional"] = dep.optional;
+ variant["dependencies"].push_back(std::move(info));
+ }
+ if (addon->LifecycleState() == AddonLifecycleState::BROKEN)
+ variant["broken"] = addon->LifecycleStateDescription();
+ else
+ variant["broken"] = false;
+ if (addon->LifecycleState() == AddonLifecycleState::DEPRECATED)
+ variant["deprecated"] = addon->LifecycleStateDescription();
+ else
+ variant["deprecated"] = false;
+ variant["extrainfo"] = CVariant(CVariant::VariantTypeArray);
+ for (const auto& kv : addon->ExtraInfo())
+ {
+ CVariant info(CVariant::VariantTypeObject);
+ info["key"] = kv.first;
+ info["value"] = kv.second;
+ variant["extrainfo"].push_back(std::move(info));
+ }
+ variant["rating"] = -1;
+ return variant;
+}
+
+void CAddonsOperations::FillDetails(const std::shared_ptr<ADDON::IAddon>& addon,
+ const CVariant& fields,
+ CVariant& result,
+ CAddonDatabase& addondb,
+ bool append /* = false */)
+{
+ if (addon.get() == NULL)
+ return;
+
+ CVariant addonInfo = Serialize(addon);
+
+ CVariant object;
+ object["addonid"] = addonInfo["addonid"];
+ object["type"] = addonInfo["type"];
+
+ for (unsigned int index = 0; index < fields.size(); index++)
+ {
+ std::string field = fields[index].asString();
+
+ // we need to manually retrieve the enabled / installed state of every addon
+ // from the addon database because it can't be read from addon.xml
+ if (field == "enabled")
+ {
+ object[field] = !CServiceBroker::GetAddonMgr().IsAddonDisabled(addon->ID());
+ }
+ else if (field == "installed")
+ {
+ object[field] = CServiceBroker::GetAddonMgr().IsAddonInstalled(addon->ID());
+ }
+ else if (field == "fanart" || field == "thumbnail")
+ {
+ std::string url = addonInfo[field].asString();
+ // We need to check the existence of fanart and thumbnails as the addon simply
+ // holds where the art will be, not whether it exists.
+ bool needsRecaching;
+ std::string image = CServiceBroker::GetTextureCache()->CheckCachedImage(url, needsRecaching);
+ if (!image.empty() || CFileUtils::Exists(url))
+ object[field] = CTextureUtils::GetWrappedImageURL(url);
+ else
+ object[field] = "";
+ }
+ else if (addonInfo.isMember(field))
+ object[field] = addonInfo[field];
+ }
+
+ if (append)
+ result.append(object);
+ else
+ result = object;
+}