summaryrefslogtreecommitdiffstats
path: root/xbmc/interfaces/builtins/AddonBuiltins.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/interfaces/builtins/AddonBuiltins.cpp')
-rw-r--r--xbmc/interfaces/builtins/AddonBuiltins.cpp522
1 files changed, 522 insertions, 0 deletions
diff --git a/xbmc/interfaces/builtins/AddonBuiltins.cpp b/xbmc/interfaces/builtins/AddonBuiltins.cpp
new file mode 100644
index 0000000..056128d
--- /dev/null
+++ b/xbmc/interfaces/builtins/AddonBuiltins.cpp
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2005-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 "AddonBuiltins.h"
+
+#include "FileItem.h"
+#include "GUIPassword.h"
+#include "GUIUserMessages.h"
+#include "ServiceBroker.h"
+#include "addons/AddonInstaller.h"
+#include "addons/AddonManager.h"
+#include "addons/AddonSystemSettings.h"
+#include "addons/PluginSource.h"
+#include "addons/RepositoryUpdater.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/addoninfo/AddonType.h"
+#include "addons/gui/GUIDialogAddonSettings.h"
+#include "addons/gui/GUIWindowAddonBrowser.h"
+#include "application/Application.h"
+#include "filesystem/PluginDirectory.h"
+#include "games/tags/GameInfoTag.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "interfaces/generic/ScriptInvocationManager.h"
+#include "messaging/helpers/DialogHelper.h"
+#include "playlists/PlayListTypes.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+
+#include <memory>
+
+#if defined(TARGET_DARWIN)
+#include "filesystem/SpecialProtocol.h"
+#if defined(TARGET_DARWIN_OSX)
+#include "platform/darwin/osx/CocoaInterface.h"
+#endif
+#endif
+
+using namespace ADDON;
+using namespace KODI::MESSAGING;
+using KODI::MESSAGING::HELPERS::DialogResponse;
+
+/*! \brief Install an addon.
+ * \param params The parameters.
+ * \details params[0] = add-on id.
+ */
+static int InstallAddon(const std::vector<std::string>& params)
+{
+ const std::string& addonid = params[0];
+
+ AddonPtr addon;
+ CAddonInstaller::GetInstance().InstallModal(addonid, addon, InstallModalPrompt::CHOICE_YES);
+
+ return 0;
+}
+
+/*! \brief Enable an addon.
+ * \param params The parameters.
+ * \details params[0] = add-on id.
+ */
+static int EnableAddon(const std::vector<std::string>& params)
+{
+ const std::string& addonid = params[0];
+
+ if (!g_passwordManager.CheckMenuLock(WINDOW_ADDON_BROWSER))
+ return -1;
+
+ AddonPtr addon;
+ if (!CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, OnlyEnabled::CHOICE_NO))
+ return -1;
+
+ auto response = HELPERS::ShowYesNoDialogLines(CVariant{24076}, CVariant{24135}, CVariant{addon->Name()}, CVariant{24136});
+ if (response == DialogResponse::CHOICE_YES)
+ CServiceBroker::GetAddonMgr().EnableAddon(addonid);
+
+ return 0;
+}
+
+/*! \brief Run a plugin.
+ * \param params The parameters.
+ * \details params[0] = plugin:// URL to script.
+ */
+static int RunPlugin(const std::vector<std::string>& params)
+{
+ if (params.size())
+ {
+ CFileItem item(params[0]);
+ if (!item.m_bIsFolder)
+ {
+ item.SetPath(params[0]);
+ XFILE::CPluginDirectory::RunScriptWithParams(item.GetPath(), false);
+ }
+ }
+ else
+ CLog::Log(LOGERROR, "RunPlugin called with no arguments.");
+
+ return 0;
+}
+
+/*! \brief Run a script, plugin or game add-on.
+ * \param params The parameters.
+ * \details params[0] = add-on id.
+ * params[1] is blank for no add-on parameters
+ * or
+ * params[1] = add-on parameters in url format
+ * or
+ * params[1,...] = additional parameters in format param=value.
+ */
+static int RunAddon(const std::vector<std::string>& params)
+{
+ if (params.size())
+ {
+ const std::string& addonid = params[0];
+
+ AddonPtr addon;
+ if (CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, AddonType::PLUGIN,
+ OnlyEnabled::CHOICE_YES))
+ {
+ const auto plugin = std::dynamic_pointer_cast<CPluginSource>(addon);
+ std::string urlParameters;
+ std::vector<std::string> parameters;
+ if (params.size() == 2 &&
+ (StringUtils::StartsWith(params[1], "/") || StringUtils::StartsWith(params[1], "?")))
+ urlParameters = params[1];
+ else if (params.size() > 1)
+ {
+ parameters.insert(parameters.begin(), params.begin() + 1, params.end());
+ urlParameters = "?" + StringUtils::Join(parameters, "&");
+ }
+ else
+ {
+ // Add '/' if addon is run without params (will be removed later so it's safe)
+ // Otherwise there are 2 entries for the same plugin in ViewModesX.db
+ urlParameters = "/";
+ }
+
+ std::string cmd;
+ if (plugin->Provides(CPluginSource::VIDEO))
+ cmd = StringUtils::Format("ActivateWindow(Videos,plugin://{}{},return)", addonid,
+ urlParameters);
+ else if (plugin->Provides(CPluginSource::AUDIO))
+ cmd = StringUtils::Format("ActivateWindow(Music,plugin://{}{},return)", addonid,
+ urlParameters);
+ else if (plugin->Provides(CPluginSource::EXECUTABLE))
+ cmd = StringUtils::Format("ActivateWindow(Programs,plugin://{}{},return)", addonid,
+ urlParameters);
+ else if (plugin->Provides(CPluginSource::IMAGE))
+ cmd = StringUtils::Format("ActivateWindow(Pictures,plugin://{}{},return)", addonid,
+ urlParameters);
+ else if (plugin->Provides(CPluginSource::GAME))
+ cmd = StringUtils::Format("ActivateWindow(Games,plugin://{}{},return)", addonid,
+ urlParameters);
+ else
+ // Pass the script name (addonid) and all the parameters
+ // (params[1] ... params[x]) separated by a comma to RunPlugin
+ cmd = StringUtils::Format("RunPlugin({})", StringUtils::Join(params, ","));
+ CBuiltins::GetInstance().Execute(cmd);
+ }
+ else if (CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, AddonType::SCRIPT,
+ OnlyEnabled::CHOICE_YES) ||
+ CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, AddonType::SCRIPT_WEATHER,
+ OnlyEnabled::CHOICE_YES) ||
+ CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, AddonType::SCRIPT_LYRICS,
+ OnlyEnabled::CHOICE_YES) ||
+ CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, AddonType::SCRIPT_LIBRARY,
+ OnlyEnabled::CHOICE_YES))
+ {
+ // Pass the script name (addonid) and all the parameters
+ // (params[1] ... params[x]) separated by a comma to RunScript
+ CBuiltins::GetInstance().Execute(
+ StringUtils::Format("RunScript({})", StringUtils::Join(params, ",")));
+ }
+ else if (CServiceBroker::GetAddonMgr().GetAddon(addonid, addon, AddonType::GAMEDLL,
+ OnlyEnabled::CHOICE_YES))
+ {
+ CFileItem item;
+
+ if (params.size() >= 2)
+ {
+ item = CFileItem(params[1], false);
+ item.GetGameInfoTag()->SetGameClient(addonid);
+ }
+ else
+ item = CFileItem(addon);
+
+ if (!g_application.PlayMedia(item, "", PLAYLIST::TYPE_NONE))
+ {
+ CLog::Log(LOGERROR, "RunAddon could not start {}", addonid);
+ return false;
+ }
+ }
+ else
+ CLog::Log(
+ LOGERROR,
+ "RunAddon: unknown add-on id '{}', or unexpected add-on type (not a script or plugin).",
+ addonid);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "RunAddon called with no arguments.");
+ }
+
+ return 0;
+}
+
+/*! \brief Run a script add-on or an apple script.
+ * \param params The parameters.
+ * \details params[0] is the URL to the apple script
+ * or
+ * params[0] is the addon-ID to the script add-on
+ * or
+ * params[0] is the URL to the python script.
+ *
+ * Set the OnlyApple template parameter to true to only attempt
+ * execution of applescripts.
+ */
+template<bool OnlyApple=false>
+static int RunScript(const std::vector<std::string>& params)
+{
+#if defined(TARGET_DARWIN_OSX)
+ std::string execute;
+ std::string parameter = params.size() ? params[0] : "";
+ if (URIUtils::HasExtension(parameter, ".applescript|.scpt"))
+ {
+ std::string osxPath = CSpecialProtocol::TranslatePath(parameter);
+ Cocoa_DoAppleScriptFile(osxPath.c_str());
+ }
+ else if (OnlyApple)
+ return 1;
+ else
+#endif
+ {
+ AddonPtr addon;
+ std::string scriptpath;
+ // Test to see if the param is an addon ID
+ if (CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, OnlyEnabled::CHOICE_YES))
+ {
+ //Get the correct extension point to run
+ if (CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, AddonType::SCRIPT,
+ OnlyEnabled::CHOICE_YES) ||
+ CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, AddonType::SCRIPT_WEATHER,
+ OnlyEnabled::CHOICE_YES) ||
+ CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, AddonType::SCRIPT_LYRICS,
+ OnlyEnabled::CHOICE_YES) ||
+ CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, AddonType::SCRIPT_LIBRARY,
+ OnlyEnabled::CHOICE_YES))
+ {
+ scriptpath = addon->LibPath();
+ }
+ else
+ {
+ // Run a random extension point (old behaviour).
+ if (CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, OnlyEnabled::CHOICE_YES))
+ {
+ scriptpath = addon->LibPath();
+ CLog::Log(LOGWARNING,
+ "RunScript called for a non-script addon '{}'. This behaviour is deprecated.",
+ params[0]);
+ }
+ else
+ {
+ CLog::Log(LOGERROR, "{} - Could not get addon: {}", __FUNCTION__, params[0]);
+ }
+ }
+ }
+ else
+ scriptpath = params[0];
+
+ // split the path up to find the filename
+ std::vector<std::string> argv = params;
+ std::string filename = URIUtils::GetFileName(scriptpath);
+ if (!filename.empty())
+ argv[0] = filename;
+
+ CScriptInvocationManager::GetInstance().ExecuteAsync(scriptpath, addon, argv);
+ }
+
+ return 0;
+}
+
+/*! \brief Open the settings for the default add-on of a given type.
+ * \param params The parameters.
+ * \details params[0] = The add-on type.
+ */
+static int OpenDefaultSettings(const std::vector<std::string>& params)
+{
+ AddonPtr addon;
+ AddonType type = CAddonInfo::TranslateType(params[0]);
+ if (CAddonSystemSettings::GetInstance().GetActive(type, addon))
+ {
+ bool changed = CGUIDialogAddonSettings::ShowForAddon(addon);
+ if (type == AddonType::VISUALIZATION && changed)
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_VISUALISATION_RELOAD, 0, 0);
+ }
+
+ return 0;
+}
+
+/*! \brief Set the default add-on for a given type.
+ * \param params The parameters.
+ * \details params[0] = The add-on type
+ */
+static int SetDefaultAddon(const std::vector<std::string>& params)
+{
+ std::string addonID;
+ AddonType type = CAddonInfo::TranslateType(params[0]);
+ bool allowNone = false;
+ if (type == AddonType::VISUALIZATION)
+ allowNone = true;
+
+ if (type != AddonType::UNKNOWN && CGUIWindowAddonBrowser::SelectAddonID(type, addonID, allowNone))
+ {
+ CAddonSystemSettings::GetInstance().SetActive(type, addonID);
+ if (type == AddonType::VISUALIZATION)
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(GUI_MSG_VISUALISATION_RELOAD, 0, 0);
+ }
+
+ return 0;
+}
+
+/*! \brief Open the settings for a given add-on.
+ * \param params The parameters.
+ * \details params[0] = The add-on ID.
+ */
+static int AddonSettings(const std::vector<std::string>& params)
+{
+ AddonPtr addon;
+ if (CServiceBroker::GetAddonMgr().GetAddon(params[0], addon, OnlyEnabled::CHOICE_YES))
+ CGUIDialogAddonSettings::ShowForAddon(addon);
+
+ return 0;
+}
+
+/*! \brief Open the settings for a given add-on.
+* \param params The parameters.
+*/
+static int InstallFromZip(const std::vector<std::string>& params)
+{
+ CGUIWindowAddonBrowser::InstallFromZip();
+ return 0;
+}
+
+/*! \brief Stop a running script.
+ * \param params The parameters.
+ * \details params[0] = The add-on ID of the script to stop
+ * or
+ * params[0] = The URL of the script to stop.
+ */
+static int StopScript(const std::vector<std::string>& params)
+{
+ //! @todo FIXME: This does not work for addons with multiple extension points!
+ //! Are there any use for this? TODO: Fix hack in CScreenSaver::Destroy() and deprecate.
+ std::string scriptpath(params[0]);
+ // Test to see if the param is an addon ID
+ AddonPtr script;
+ if (CServiceBroker::GetAddonMgr().GetAddon(params[0], script, OnlyEnabled::CHOICE_YES))
+ scriptpath = script->LibPath();
+ CScriptInvocationManager::GetInstance().Stop(scriptpath);
+
+ return 0;
+}
+
+/*! \brief Check add-on repositories for updates.
+ * \param params (ignored)
+ */
+static int UpdateRepos(const std::vector<std::string>& params)
+{
+ CServiceBroker::GetRepositoryUpdater().CheckForUpdates();
+
+ return 0;
+}
+
+/*! \brief Check local add-on directories for updates.
+ * \param params (ignored)
+ */
+static int UpdateLocals(const std::vector<std::string>& params)
+{
+ CServiceBroker::GetAddonMgr().FindAddons();
+
+ return 0;
+}
+
+// Note: For new Texts with comma add a "\" before!!! Is used for table text.
+//
+/// \page page_List_of_built_in_functions List of built-in functions
+/// \section built_in_functions_1 Add-on built-in's
+///
+/// -----------------------------------------------------------------------------
+///
+/// \table_start
+/// \table_h2_l{
+/// Function,
+/// Description }
+/// \table_row2_l{
+/// <b>`Addon.Default.OpenSettings(extensionpoint)`</b>
+/// ,
+/// Open a settings dialog for the default addon of the given type
+/// (extensionpoint)
+/// @param[in] extensionpoint The add-on type
+/// }
+/// \table_row2_l{
+/// <b>`Addon.Default.Set(extensionpoint)`</b>
+/// ,
+/// Open a select dialog to allow choosing the default addon of the given type
+/// (extensionpoint)
+/// @param[in] extensionpoint The add-on type
+/// }
+/// \table_row2_l{
+/// <b>`Addon.OpenSettings(id)`</b>
+/// ,
+/// Open a settings dialog for the addon of the given id
+/// @param[in] id The add-on ID
+/// }
+/// \table_row2_l{
+/// <b>`EnableAddon(id)`</b>
+/// \anchor Builtin_EnableAddonId,
+/// Enable the specified plugin/script
+/// @param[in] id The add-on id
+/// <p><hr>
+/// @skinning_v19 **[New builtin]** \link Builtin_EnableAddonId `EnableAddon(id)`\endlink
+/// <p>
+/// }
+/// \table_row2_l{
+/// <b>`InstallAddon(id)`</b>
+/// ,
+/// Install the specified plugin/script
+/// @param[in] id The add-on id
+/// }
+/// \table_row2_l{
+/// <b>`InstallFromZip`</b>
+/// ,
+/// Opens the "Install from zip" dialog if "Unknown sources" is enabled. Prompts the warning message if not.
+/// }
+/// \table_row2_l{
+/// <b>`RunAddon(id[\,opt])`</b>
+/// ,
+/// Runs the specified plugin/script
+/// @param[in] id The add-on id.
+/// @param[in] opt is blank for no add-on parameters\n
+/// or
+/// @param[in] opt Add-on parameters in url format\n
+/// or
+/// @param[in] opt[\,...] Additional parameters in format param=value.
+/// }
+/// \table_row2_l{
+/// <b>`RunAppleScript(script[\,args]*)`</b>
+/// ,
+/// Run the specified AppleScript command
+/// @param[in] script Is the URL to the apple script\n
+/// or
+/// @param[in] script Is the addon-ID to the script add-on\n
+/// or
+/// @param[in] script Is the URL to the python script.
+///
+/// @note Set the OnlyApple template parameter to true to only attempt
+/// execution of applescripts.
+/// }
+/// \table_row2_l{
+/// <b>`RunPlugin(plugin)`</b>
+/// ,
+/// Runs the plugin. Full path must be specified. Does not work for folder
+/// plugins
+/// @param[in] plugin plugin:// URL to script.
+/// }
+/// \table_row2_l{
+/// <b>`RunScript(script[\,args]*)`</b>
+/// ,
+/// Runs the python script. You must specify the full path to the script. If
+/// the script is an add-on\, you can also execute it using its add-on id. As
+/// of 2007/02/24\, all extra parameters are passed to the script as arguments
+/// and can be accessed by python using sys.argv
+/// @param[in] script Is the addon-ID to the script add-on\n
+/// or
+/// @param[in] script Is the URL to the python script.
+/// }
+/// \table_row2_l{
+/// <b>`StopScript(id)`</b>
+/// ,
+/// Stop the script by ID or path\, if running
+/// @param[in] id The add-on ID of the script to stop\n
+/// or
+/// @param[in] id The URL of the script to stop.
+/// }
+/// \table_row2_l{
+/// <b>`UpdateAddonRepos`</b>
+/// ,
+/// Triggers a forced update of enabled add-on repositories.
+/// }
+/// \table_row2_l{
+/// <b>`UpdateLocalAddons`</b>
+/// ,
+/// Triggers a scan of local add-on directories.
+/// }
+/// \table_end
+///
+
+CBuiltins::CommandMap CAddonBuiltins::GetOperations() const
+{
+ return {
+ {"addon.default.opensettings", {"Open a settings dialog for the default addon of the given type", 1, OpenDefaultSettings}},
+ {"addon.default.set", {"Open a select dialog to allow choosing the default addon of the given type", 1, SetDefaultAddon}},
+ {"addon.opensettings", {"Open a settings dialog for the addon of the given id", 1, AddonSettings}},
+ {"enableaddon", {"Enables the specified plugin/script", 1, EnableAddon}},
+ {"installaddon", {"Install the specified plugin/script", 1, InstallAddon}},
+ {"installfromzip", { "Open the install from zip dialog", 0, InstallFromZip}},
+ {"runaddon", {"Run the specified plugin/script", 1, RunAddon}},
+#ifdef TARGET_DARWIN
+ {"runapplescript", {"Run the specified AppleScript command", 1, RunScript<true>}},
+#endif
+ {"runplugin", {"Run the specified plugin", 1, RunPlugin}},
+ {"runscript", {"Run the specified script", 1, RunScript}},
+ {"stopscript", {"Stop the script by ID or path, if running", 1, StopScript}},
+ {"updateaddonrepos", {"Check add-on repositories for updates", 0, UpdateRepos}},
+ {"updatelocaladdons", {"Check for local add-on changes", 0, UpdateLocals}}
+ };
+}