summaryrefslogtreecommitdiffstats
path: root/xbmc/interfaces/legacy
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/interfaces/legacy')
-rw-r--r--xbmc/interfaces/legacy/Addon.cpp243
-rw-r--r--xbmc/interfaces/legacy/Addon.h483
-rw-r--r--xbmc/interfaces/legacy/AddonCallback.cpp26
-rw-r--r--xbmc/interfaces/legacy/AddonCallback.h43
-rw-r--r--xbmc/interfaces/legacy/AddonClass.cpp90
-rw-r--r--xbmc/interfaces/legacy/AddonClass.h209
-rw-r--r--xbmc/interfaces/legacy/AddonString.h21
-rw-r--r--xbmc/interfaces/legacy/AddonUtils.cpp123
-rw-r--r--xbmc/interfaces/legacy/AddonUtils.h95
-rw-r--r--xbmc/interfaces/legacy/Alternative.h70
-rw-r--r--xbmc/interfaces/legacy/CMakeLists.txt76
-rw-r--r--xbmc/interfaces/legacy/CallbackFunction.cpp14
-rw-r--r--xbmc/interfaces/legacy/CallbackFunction.h171
-rw-r--r--xbmc/interfaces/legacy/CallbackHandler.cpp148
-rw-r--r--xbmc/interfaces/legacy/CallbackHandler.h58
-rw-r--r--xbmc/interfaces/legacy/Control.cpp1435
-rw-r--r--xbmc/interfaces/legacy/Control.h2960
-rw-r--r--xbmc/interfaces/legacy/Dialog.cpp622
-rw-r--r--xbmc/interfaces/legacy/Dialog.h965
-rw-r--r--xbmc/interfaces/legacy/Dictionary.h34
-rw-r--r--xbmc/interfaces/legacy/DrmCryptoSession.cpp108
-rw-r--r--xbmc/interfaces/legacy/DrmCryptoSession.h342
-rw-r--r--xbmc/interfaces/legacy/Exception.h55
-rw-r--r--xbmc/interfaces/legacy/File.cpp61
-rw-r--r--xbmc/interfaces/legacy/File.h326
-rw-r--r--xbmc/interfaces/legacy/InfoTagGame.cpp172
-rw-r--r--xbmc/interfaces/legacy/InfoTagGame.h383
-rw-r--r--xbmc/interfaces/legacy/InfoTagMusic.cpp468
-rw-r--r--xbmc/interfaces/legacy/InfoTagMusic.h1034
-rw-r--r--xbmc/interfaces/legacy/InfoTagPicture.cpp98
-rw-r--r--xbmc/interfaces/legacy/InfoTagPicture.h180
-rw-r--r--xbmc/interfaces/legacy/InfoTagRadioRDS.cpp234
-rw-r--r--xbmc/interfaces/legacy/InfoTagRadioRDS.h443
-rw-r--r--xbmc/interfaces/legacy/InfoTagVideo.cpp1063
-rw-r--r--xbmc/interfaces/legacy/InfoTagVideo.h2772
-rw-r--r--xbmc/interfaces/legacy/Keyboard.cpp66
-rw-r--r--xbmc/interfaces/legacy/Keyboard.h215
-rw-r--r--xbmc/interfaces/legacy/LanguageHook.cpp41
-rw-r--r--xbmc/interfaces/legacy/LanguageHook.h151
-rw-r--r--xbmc/interfaces/legacy/List.h20
-rw-r--r--xbmc/interfaces/legacy/ListItem.cpp1056
-rw-r--r--xbmc/interfaces/legacy/ListItem.h1291
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmc.cpp600
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmc.h898
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmcgui.cpp58
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmcgui.h149
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmcplugin.cpp125
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmcplugin.h489
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmcvfs.cpp137
-rw-r--r--xbmc/interfaces/legacy/ModuleXbmcvfs.h334
-rw-r--r--xbmc/interfaces/legacy/Monitor.cpp82
-rw-r--r--xbmc/interfaces/legacy/Monitor.h311
-rw-r--r--xbmc/interfaces/legacy/PlayList.cpp144
-rw-r--r--xbmc/interfaces/legacy/PlayList.h212
-rw-r--r--xbmc/interfaces/legacy/Player.cpp607
-rw-r--r--xbmc/interfaces/legacy/Player.h824
-rw-r--r--xbmc/interfaces/legacy/RenderCapture.h206
-rw-r--r--xbmc/interfaces/legacy/Settings.cpp232
-rw-r--r--xbmc/interfaces/legacy/Settings.h500
-rw-r--r--xbmc/interfaces/legacy/Stat.h195
-rw-r--r--xbmc/interfaces/legacy/String.cpp14
-rw-r--r--xbmc/interfaces/legacy/Tuple.h98
-rw-r--r--xbmc/interfaces/legacy/Window.cpp767
-rw-r--r--xbmc/interfaces/legacy/Window.h878
-rw-r--r--xbmc/interfaces/legacy/WindowDialog.cpp76
-rw-r--r--xbmc/interfaces/legacy/WindowDialog.h88
-rw-r--r--xbmc/interfaces/legacy/WindowDialogMixin.cpp75
-rw-r--r--xbmc/interfaces/legacy/WindowDialogMixin.h43
-rw-r--r--xbmc/interfaces/legacy/WindowException.h21
-rw-r--r--xbmc/interfaces/legacy/WindowInterceptor.h210
-rw-r--r--xbmc/interfaces/legacy/WindowXML.cpp527
-rw-r--r--xbmc/interfaces/legacy/WindowXML.h559
-rw-r--r--xbmc/interfaces/legacy/aojsonrpc.h30
-rw-r--r--xbmc/interfaces/legacy/swighelper.h100
-rw-r--r--xbmc/interfaces/legacy/wsgi/CMakeLists.txt13
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp63
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h92
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp166
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiInputStream.h120
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp92
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponse.h77
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp29
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h50
83 files changed, 28756 insertions, 0 deletions
diff --git a/xbmc/interfaces/legacy/Addon.cpp b/xbmc/interfaces/legacy/Addon.cpp
new file mode 100644
index 0000000..4b4db1e
--- /dev/null
+++ b/xbmc/interfaces/legacy/Addon.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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 "Addon.h"
+
+#include "GUIUserMessages.h"
+#include "LanguageHook.h"
+#include "ServiceBroker.h"
+#include "addons/AddonManager.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/gui/GUIDialogAddonSettings.h"
+#include "addons/settings/AddonSettings.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "utils/StringUtils.h"
+
+using namespace ADDON;
+
+namespace XBMCAddon
+{
+ namespace xbmcaddon
+ {
+ String Addon::getDefaultId() { return languageHook == NULL ? emptyString : languageHook->GetAddonId(); }
+
+ String Addon::getAddonVersion() { return languageHook == NULL ? emptyString : languageHook->GetAddonVersion(); }
+
+ bool Addon::UpdateSettingInActiveDialog(const char* id, const String& value)
+ {
+ ADDON::AddonPtr addon(pAddon);
+ if (!CServiceBroker::GetGUI()->GetWindowManager().IsWindowActive(WINDOW_DIALOG_ADDON_SETTINGS))
+ return false;
+
+ CGUIDialogAddonSettings* dialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogAddonSettings>(WINDOW_DIALOG_ADDON_SETTINGS);
+ if (dialog->GetCurrentAddonID() != addon->ID())
+ return false;
+
+ CGUIMessage message(GUI_MSG_SETTING_UPDATED, 0, 0);
+ std::vector<std::string> params;
+ params.emplace_back(id);
+ params.push_back(value);
+ message.SetStringParams(params);
+ message.SetParam1(ADDON_SETTINGS_ID);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(message, WINDOW_DIALOG_ADDON_SETTINGS);
+
+ return true;
+ }
+
+ Addon::Addon(const char* cid)
+ {
+ String id(cid ? cid : emptyString);
+
+ // if the id wasn't passed then get the id from
+ // the global dictionary
+ if (id.empty())
+ id = getDefaultId();
+
+ // if we still don't have an id then bail
+ if (id.empty())
+ throw AddonException("No valid addon id could be obtained. None was passed and the script "
+ "wasn't executed in a normal Kodi manner.");
+
+ if (!CServiceBroker::GetAddonMgr().GetAddon(id, pAddon, OnlyEnabled::CHOICE_YES))
+ throw AddonException("Unknown addon id '%s'.", id.c_str());
+
+ CServiceBroker::GetAddonMgr().AddToUpdateableAddons(pAddon);
+ }
+
+ Addon::~Addon()
+ {
+ CServiceBroker::GetAddonMgr().RemoveFromUpdateableAddons(pAddon);
+ }
+
+ String Addon::getLocalizedString(int id)
+ {
+ return g_localizeStrings.GetAddonString(pAddon->ID(), id);
+ }
+
+ Settings* Addon::getSettings()
+ {
+ return new Settings(pAddon->GetSettings());
+ }
+
+ String Addon::getSetting(const char* id)
+ {
+ return pAddon->GetSetting(id);
+ }
+
+ bool Addon::getSettingBool(const char* id)
+ {
+ bool value = false;
+ if (!pAddon->GetSettingBool(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ return value;
+ }
+
+ int Addon::getSettingInt(const char* id)
+ {
+ int value = 0;
+ if (!pAddon->GetSettingInt(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ return value;
+ }
+
+ double Addon::getSettingNumber(const char* id)
+ {
+ double value = 0.0;
+ if (!pAddon->GetSettingNumber(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ return value;
+ }
+
+ String Addon::getSettingString(const char* id)
+ {
+ std::string value;
+ if (!pAddon->GetSettingString(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ return value;
+ }
+
+ void Addon::setSetting(const char* id, const String& value)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ ADDON::AddonPtr addon(pAddon);
+ if (!UpdateSettingInActiveDialog(id, value))
+ {
+ addon->UpdateSetting(id, value);
+ addon->SaveSettings();
+ }
+ }
+
+ bool Addon::setSettingBool(const char* id, bool value)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ ADDON::AddonPtr addon(pAddon);
+ if (UpdateSettingInActiveDialog(id, value ? "true" : "false"))
+ return true;
+
+ if (!addon->UpdateSettingBool(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ addon->SaveSettings();
+
+ return true;
+ }
+
+ bool Addon::setSettingInt(const char* id, int value)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ ADDON::AddonPtr addon(pAddon);
+ if (UpdateSettingInActiveDialog(id, std::to_string(value)))
+ return true;
+
+ if (!addon->UpdateSettingInt(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ addon->SaveSettings();
+
+ return true;
+ }
+
+ bool Addon::setSettingNumber(const char* id, double value)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ ADDON::AddonPtr addon(pAddon);
+ if (UpdateSettingInActiveDialog(id, StringUtils::Format("{:f}", value)))
+ return true;
+
+ if (!addon->UpdateSettingNumber(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ addon->SaveSettings();
+
+ return true;
+ }
+
+ bool Addon::setSettingString(const char* id, const String& value)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ ADDON::AddonPtr addon(pAddon);
+ if (UpdateSettingInActiveDialog(id, value))
+ return true;
+
+ if (!addon->UpdateSettingString(id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type");
+
+ addon->SaveSettings();
+
+ return true;
+ }
+
+ void Addon::openSettings()
+ {
+ DelayedCallGuard dcguard(languageHook);
+ // show settings dialog
+ ADDON::AddonPtr addon(pAddon);
+ CGUIDialogAddonSettings::ShowForAddon(addon);
+ }
+
+ String Addon::getAddonInfo(const char* id)
+ {
+ if (StringUtils::CompareNoCase(id, "author") == 0)
+ return pAddon->Author();
+ else if (StringUtils::CompareNoCase(id, "changelog") == 0)
+ return pAddon->ChangeLog();
+ else if (StringUtils::CompareNoCase(id, "description") == 0)
+ return pAddon->Description();
+ else if (StringUtils::CompareNoCase(id, "disclaimer") == 0)
+ return pAddon->Disclaimer();
+ else if (StringUtils::CompareNoCase(id, "fanart") == 0)
+ return pAddon->FanArt();
+ else if (StringUtils::CompareNoCase(id, "icon") == 0)
+ return pAddon->Icon();
+ else if (StringUtils::CompareNoCase(id, "id") == 0)
+ return pAddon->ID();
+ else if (StringUtils::CompareNoCase(id, "name") == 0)
+ return pAddon->Name();
+ else if (StringUtils::CompareNoCase(id, "path") == 0)
+ return pAddon->Path();
+ else if (StringUtils::CompareNoCase(id, "profile") == 0)
+ return pAddon->Profile();
+ else if (StringUtils::CompareNoCase(id, "stars") == 0)
+ return StringUtils::Format("-1");
+ else if (StringUtils::CompareNoCase(id, "summary") == 0)
+ return pAddon->Summary();
+ else if (StringUtils::CompareNoCase(id, "type") == 0)
+ return ADDON::CAddonInfo::TranslateType(pAddon->Type());
+ else if (StringUtils::CompareNoCase(id, "version") == 0)
+ return pAddon->Version().asString();
+ else
+ throw AddonException("'%s' is an invalid Id", id);
+ }
+ }
+}
diff --git a/xbmc/interfaces/legacy/Addon.h b/xbmc/interfaces/legacy/Addon.h
new file mode 100644
index 0000000..97c598f
--- /dev/null
+++ b/xbmc/interfaces/legacy/Addon.h
@@ -0,0 +1,483 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "AddonString.h"
+#include "Exception.h"
+#include "Settings.h"
+#include "addons/IAddon.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcaddon
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(AddonException);
+
+ ///
+ /// \addtogroup python_xbmcaddon
+ /// @{
+ /// @brief **Kodi's addon class.**
+ ///
+ /// Offers classes and functions that manipulate the add-on settings,
+ /// information and localization.
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// \python_class{ xbmcaddon.Addon([id]) }
+ ///
+ /// Creates a new AddOn class.
+ ///
+ /// @param id [opt] string - id of the addon as
+ /// specified in [addon.xml](http://kodi.wiki/view/Addon.xml)
+ ///
+ /// @note Specifying the addon id is not needed.\n
+ /// Important however is that the addon folder has the same name as the AddOn
+ /// id provided in [addon.xml](http://kodi.wiki/view/Addon.xml).\n
+ /// You can optionally specify the addon id from another installed addon to
+ /// retrieve settings from it.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v13
+ /// **id** is optional as it will be auto detected for this add-on instance.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon = xbmcaddon.Addon()
+ /// self.Addon = xbmcaddon.Addon('script.foo.bar')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ class Addon : public AddonClass
+ {
+ ADDON::AddonPtr pAddon;
+
+ String getDefaultId();
+
+ String getAddonVersion();
+
+ bool UpdateSettingInActiveDialog(const char* id, const String& value);
+
+ public:
+ explicit Addon(const char* id = NULL);
+ ~Addon() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getLocalizedString(id) }
+ /// Returns an addon's localized 'string'.
+ ///
+ /// @param id integer - id# for string you want to
+ /// localize.
+ /// @return Localized 'string'
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13
+ /// **id** is optional as it will be auto detected for this add-on instance.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// locstr = self.Addon.getLocalizedString(32000)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getLocalizedString(...);
+#else
+ String getLocalizedString(int id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getSettings() }
+ /// Returns a wrapper around the addon's settings.
+ ///
+ /// @return @ref python_settings wrapper
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings = self.Addon.getSettings()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSettings(...);
+#else
+ Settings* getSettings();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getSetting(id) }
+ /// Returns the value of a setting as string.
+ ///
+ /// @param id string - id of the setting that the module
+ /// needs to access.
+ /// @return Setting as a string
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13
+ /// **id** is optional as it will be auto detected for this add-on instance.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// apikey = self.Addon.getSetting('apikey')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSetting(...);
+#else
+ String getSetting(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getSettingBool(id) }
+ /// Returns the value of a setting as a boolean.
+ ///
+ /// @param id string - id of the setting that the module
+ /// needs to access.
+ /// @return Setting as a boolean
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.getBool()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// enabled = self.Addon.getSettingBool('enabled')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSettingBool(...);
+#else
+ bool getSettingBool(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getSettingInt(id) }
+ /// Returns the value of a setting as an integer.
+ ///
+ /// @param id string - id of the setting that the module
+ /// needs to access.
+ /// @return Setting as an integer
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.getInt()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// max = self.Addon.getSettingInt('max')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSettingInt(...);
+#else
+ int getSettingInt(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getSettingNumber(id) }
+ /// Returns the value of a setting as a floating point number.
+ ///
+ /// @param id string - id of the setting that the module
+ /// needs to access.
+ /// @return Setting as a floating point number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.getNumber()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// max = self.Addon.getSettingNumber('max')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSettingNumber(...);
+#else
+ double getSettingNumber(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getSettingString(id) }
+ /// Returns the value of a setting as a string.
+ ///
+ /// @param id string - id of the setting that the module
+ /// needs to access.
+ /// @return Setting as a string
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.getString()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// apikey = self.Addon.getSettingString('apikey')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSettingString(...);
+#else
+ String getSettingString(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).setSetting(id, value) }
+ /// Sets a script setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value string - value of the setting.
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13
+ /// **id** is optional as it will be auto detected for this add-on instance.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon.setSetting(id='username', value='teamkodi')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setSetting(...);
+#else
+ void setSetting(const char* id, const String& value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).setSettingBool(id, value) }
+ /// Sets a script setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value boolean - value of the setting.
+ /// @return True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.setBool()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon.setSettingBool(id='enabled', value=True)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setSettingBool(...);
+#else
+ bool setSettingBool(const char* id, bool value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).setSettingInt(id, value) }
+ /// Sets a script setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value integer - value of the setting.
+ /// @return True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.setInt()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon.setSettingInt(id='max', value=5)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setSettingInt(...);
+#else
+ bool setSettingInt(const char* id, int value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).setSettingNumber(id, value) }
+ /// Sets a script setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value float - value of the setting.
+ /// @return True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.setNumber()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon.setSettingNumber(id='max', value=5.5)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setSettingNumber(...);
+#else
+ bool setSettingNumber(const char* id, double value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).setSettingString(id, value) }
+ /// Sets a script setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value string or unicode - value of the setting.
+ /// @return True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18
+ /// New function added.
+ /// @python_v20 Deprecated. Use **Settings.setString()** instead.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon.setSettingString(id='username', value='teamkodi')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setSettingString(...);
+#else
+ bool setSettingString(const char* id, const String& value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).openSettings() }
+ /// Opens this scripts settings dialog.
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.Addon.openSettings()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ openSettings();
+#else
+ void openSettings();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcaddon
+ /// \anchor python_xbmcaddon_Addon
+ /// @brief \python_func{ xbmcaddon.Addon([id]).getAddonInfo(id) }
+ /// Returns the value of an addon property as a string.
+ ///
+ /// @param id string - id of the property that the
+ /// module needs to access.
+ /// @par Choices for the property are
+ /// | | | | |
+ /// |:-----------:|:-----------:|:-----------:|:-----------:|
+ /// | author | changelog | description | disclaimer |
+ /// | fanart | icon | id | name |
+ /// | path | profile | stars | summary |
+ /// | type | version | | |
+ /// @return AddOn property as a string
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// version = self.Addon.getAddonInfo('version')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getAddonInfo(...);
+#else
+ String getAddonInfo(const char* id);
+#endif
+ };
+ //@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/AddonCallback.cpp b/xbmc/interfaces/legacy/AddonCallback.cpp
new file mode 100644
index 0000000..c52ce80
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonCallback.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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 "AddonCallback.h"
+
+namespace XBMCAddon
+{
+ // need a place to put the vtab
+ AddonCallback::~AddonCallback() = default;
+
+ void AddonCallback::invokeCallback(Callback* callback)
+ {
+ if (callback)
+ {
+ if (hasHandler())
+ handler->invokeCallback(callback);
+ else
+ callback->executeCallback();
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/AddonCallback.h b/xbmc/interfaces/legacy/AddonCallback.h
new file mode 100644
index 0000000..dee5074
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonCallback.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "CallbackFunction.h"
+#include "CallbackHandler.h"
+#include "LanguageHook.h"
+
+namespace XBMCAddon
+{
+
+ /**
+ * This class is the superclass for all API classes that are expected
+ * to be able to handle cross-language polymorphism.
+ */
+ class AddonCallback : public AddonClass
+ {
+ protected:
+ AddonClass::Ref<CallbackHandler> handler;
+
+ bool hasHandler() { return handler.isNotNull(); }
+
+ inline AddonCallback() : handler(NULL)
+ {
+ // if there is a LanguageHook, it should be set already.
+ if (languageHook != NULL)
+ setHandler(languageHook->GetCallbackHandler());
+ }
+ public:
+
+ ~AddonCallback() override;
+
+ inline void setHandler(CallbackHandler* _handler) { handler = _handler; }
+ void invokeCallback(Callback* callback);
+ };
+}
diff --git a/xbmc/interfaces/legacy/AddonClass.cpp b/xbmc/interfaces/legacy/AddonClass.cpp
new file mode 100644
index 0000000..ffdf3d4
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonClass.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "AddonClass.h"
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+#include "utils/log.h"
+#endif
+#include "LanguageHook.h"
+#include "AddonUtils.h"
+
+using namespace XBMCAddonUtils;
+
+namespace XBMCAddon
+{
+ // need a place to put the vtab
+ AddonClass::~AddonClass()
+ {
+ m_isDeallocating= true;
+
+ if (languageHook != NULL)
+ languageHook->Release();
+
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+ isDeleted = false;
+#endif
+ }
+
+ AddonClass::AddonClass() : refs(0L),
+ languageHook(NULL)
+ {
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+ isDeleted = false;
+#endif
+
+ // check to see if we have a language hook that was prepared for this instantiation
+ languageHook = LanguageHook::GetLanguageHook();
+ if (languageHook != NULL)
+ {
+ languageHook->Acquire();
+
+ // here we assume the language hook was set for the single instantiation of
+ // this AddonClass (actually - its subclass - but whatever). So we
+ // will now reset the Tls. This avoids issues if the constructor of the
+ // subclass throws an exception.
+ LanguageHook::ClearLanguageHook();
+ }
+ }
+
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+ void AddonClass::Release() const
+ {
+ if (isDeleted)
+ CLog::Log(LOGERROR, "NEWADDON REFCNT Releasing dead class {} 0x{:x}", GetClassname(),
+ (long)(((void*)this)));
+
+ long ct = --refs;
+#ifdef LOG_LIFECYCLE_EVENTS
+ CLog::Log(LOGDEBUG, "NEWADDON REFCNT decrementing to {} on {} 0x{:x}", refs.load(),
+ GetClassname(), (long)(((void*)this)));
+#endif
+ if(ct == 0)
+ {
+ const_cast<AddonClass*>(this)->isDeleted = true;
+ // we're faking a delete but not doing it so call the destructor explicitly
+ this->~AddonClass();
+ }
+ }
+
+ void AddonClass::Acquire() const
+ {
+ if (isDeleted)
+ CLog::Log(LOGERROR, "NEWADDON REFCNT Acquiring dead class {} 0x{:x}", GetClassname(),
+ (long)(((void*)this)));
+
+#ifdef LOG_LIFECYCLE_EVENTS
+ CLog::Log(LOGDEBUG, "NEWADDON REFCNT incrementing to {} on {} 0x{:x}", ++refs, GetClassname(),
+ (long)(((void*)this)));
+#else
+ ++refs;
+#endif
+ }
+#endif
+}
+
+
diff --git a/xbmc/interfaces/legacy/AddonClass.h b/xbmc/interfaces/legacy/AddonClass.h
new file mode 100644
index 0000000..f5de375
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonClass.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/**
+ * Defining LOG_LIFECYCLE_EVENTS will log all instantiations, deletions
+ * and also reference countings (increments and decrements) that take
+ * place on any Addon* class.
+ *
+ * Comment out (or uncomment out) to change the setting.
+ */
+//#define LOG_LIFECYCLE_EVENTS
+
+/**
+ * Defining XBMC_ADDON_DEBUG_MEMORY will make the Acquire and Release
+ * methods virtual allow the developer to overload them in a sub-class
+ * and set breakpoints to aid in debugging. It will also cause the
+ * reference counting mechanism to never actually delete any AddonClass
+ * instance allowing for the tracking of more references to (supposedly)
+ * deallocated classes.
+ *
+ * Comment out (or uncomment out) to change the setting.
+ */
+//#define XBMC_ADDON_DEBUG_MEMORY
+
+#include "AddonString.h"
+
+#include <mutex>
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+#include "utils/log.h"
+#endif
+#include "AddonUtils.h"
+
+#include <atomic>
+#include <typeindex>
+
+namespace XBMCAddon
+{
+ class LanguageHook;
+
+ /**
+ * This class is the superclass for all reference counted classes in the api.
+ * It provides a means for the bindings to handle all api objects generically.
+ *
+ * It also provides some means for debugging "lifecycle" events (see the above
+ * description of LOG_LIFECYCLE_EVENTS).
+ *
+ * If a scripting language bindings require specific handling there is a
+ * hook to add in these language specifics that can be set here.
+ */
+ class AddonClass : public CCriticalSection
+ {
+ private:
+ mutable std::atomic<long> refs;
+ bool m_isDeallocating = false;
+
+ // no copying
+ inline AddonClass(const AddonClass&) = delete;
+
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+ bool isDeleted;
+#endif
+
+ protected:
+ LanguageHook* languageHook;
+
+ /**
+ * This method is meant to be called from the destructor of the
+ * lowest level class.
+ *
+ * It's virtual because it's a convenient place to receive messages that
+ * we're about to go be deleted but prior to any real tear-down.
+ *
+ * Any overloading classes need to remember to pass the call up the chain.
+ */
+ virtual void deallocating()
+ {
+ std::unique_lock<CCriticalSection> lock(*this);
+ m_isDeallocating = true;
+ }
+
+ /**
+ * This is meant to be called during static initialization and so isn't
+ * synchronized.
+ */
+ static short getNextClassIndex();
+
+ public:
+ AddonClass();
+ virtual ~AddonClass();
+
+ inline const char* GetClassname() const { return typeid(*this).name(); }
+ inline LanguageHook* GetLanguageHook() { return languageHook; }
+
+ /**
+ * This method should be called while holding a Synchronize
+ * on the object. It will prevent the deallocation during
+ * the time it's held.
+ */
+ bool isDeallocating() { XBMC_TRACE; return m_isDeallocating; }
+
+ static short getNumAddonClasses();
+
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+ virtual
+#else
+ inline
+#endif
+ void Release() const
+#ifndef XBMC_ADDON_DEBUG_MEMORY
+ {
+ long ct = --refs;
+#ifdef LOG_LIFECYCLE_EVENTS
+ CLog::Log(LOGDEBUG, "NEWADDON REFCNT decrementing to {} on {} 0x{:x}", ct, GetClassname(),
+ (long)(((void*)this)));
+#endif
+ if(ct == 0)
+ delete this;
+ }
+#else
+ ;
+#endif
+
+
+#ifdef XBMC_ADDON_DEBUG_MEMORY
+ virtual
+#else
+ inline
+#endif
+ void Acquire() const
+#ifndef XBMC_ADDON_DEBUG_MEMORY
+ {
+#ifdef LOG_LIFECYCLE_EVENTS
+ CLog::Log(LOGDEBUG, "NEWADDON REFCNT incrementing to {} on {} 0x{:x}", ++refs, GetClassname(),
+ (long)(((void*)this)));
+#else
+ ++refs;
+#endif
+ }
+#else
+ ;
+#endif
+
+#define refcheck
+ /**
+ * This class is a smart pointer for a Referenced class.
+ */
+ template <class T> class Ref
+ {
+ T * ac;
+ public:
+ inline Ref() : ac(NULL) {}
+ inline Ref(const T* _ac) : ac(const_cast<T*>(_ac)) { if (ac) ac->Acquire(); refcheck; }
+
+ // copy semantics
+ inline Ref(Ref<T> const & oref) : ac(const_cast<T*>(oref.get())) { if (ac) ac->Acquire(); refcheck; }
+ template<class O> inline Ref(Ref<O> const & oref) : ac(static_cast<T*>(oref.get())) { if (ac) ac->Acquire(); refcheck; }
+
+ /**
+ * operator= should work with either another smart pointer or a pointer since it will
+ * be able to convert a pointer to a smart pointer using one of the above constructors.
+ *
+ * Note: There is a trick here. The temporary variable is necessary because otherwise the
+ * following code will fail:
+ *
+ * Ref<T> ptr = new T;
+ * ptr = ptr;
+ *
+ * What happens without the tmp is the dereference is called first so the object ends up
+ * deleted and then the reference happens on a deleted object. The order is reversed
+ * in the following.
+ *
+ * Note: Operator= is ambiguous if you define both an operator=(Ref<T>&) and an operator=(T*). I'm
+ * opting for the route the boost took here figuring it has more history behind it.
+ */
+ inline Ref<T>& operator=(Ref<T> const & oref)
+ { T* tmp = ac; ac = const_cast<T*>(oref.get()); if (ac) ac->Acquire(); if (tmp) tmp->Release(); refcheck; return *this; }
+
+ inline T* operator->() const { refcheck; return ac; }
+
+ /**
+ * This operator doubles as the value in a boolean expression.
+ */
+ inline operator T*() const { refcheck; return ac; }
+ inline T* get() const { refcheck; return ac; }
+ inline T& getRef() const { refcheck; return *ac; }
+
+ inline ~Ref() { refcheck; if (ac) ac->Release(); }
+ inline bool isNull() const { refcheck; return ac == NULL; }
+ inline bool isNotNull() const { refcheck; return ac != NULL; }
+ inline bool isSet() const { refcheck; return ac != NULL; }
+ inline bool operator!() const { refcheck; return ac == NULL; }
+ inline bool operator==(const AddonClass::Ref<T>& oref) const { refcheck; return ac == oref.ac; }
+ inline bool operator<(const AddonClass::Ref<T>& oref) const { refcheck; return ac < oref.ac; } // std::set semantics
+
+ // This is there only for boost compatibility
+ template<class O> inline void reset(Ref<O> const & oref) { refcheck; (*this) = static_cast<T*>(oref.get()); refcheck; }
+ template<class O> inline void reset(O * oref) { refcheck; (*this) = static_cast<T*>(oref); refcheck; }
+ inline void reset() { refcheck; if (ac) ac->Release(); ac = NULL; }
+ };
+
+ };
+}
diff --git a/xbmc/interfaces/legacy/AddonString.h b/xbmc/interfaces/legacy/AddonString.h
new file mode 100644
index 0000000..7b1ef41
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonString.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace XBMCAddon
+{
+ typedef std::string String;
+
+ extern String emptyString;
+}
+
+
+
diff --git a/xbmc/interfaces/legacy/AddonUtils.cpp b/xbmc/interfaces/legacy/AddonUtils.cpp
new file mode 100644
index 0000000..ad0f0e0
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonUtils.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 "AddonUtils.h"
+
+#include "LanguageHook.h"
+#include "addons/Skin.h"
+#include "application/Application.h"
+#include "utils/XBMCTinyXML.h"
+#ifdef ENABLE_XBMC_TRACE_API
+#include "utils/log.h"
+#endif
+
+namespace XBMCAddonUtils
+{
+ GuiLock::GuiLock(XBMCAddon::LanguageHook* languageHook, bool offScreen)
+ : m_languageHook(languageHook), m_offScreen(offScreen)
+ {
+ if (!m_languageHook)
+ m_languageHook = XBMCAddon::LanguageHook::GetLanguageHook();
+ if (m_languageHook)
+ m_languageHook->DelayedCallOpen();
+
+ if (!m_offScreen)
+ g_application.LockFrameMoveGuard();
+ }
+
+ GuiLock::~GuiLock()
+ {
+ if (!m_offScreen)
+ g_application.UnlockFrameMoveGuard();
+
+ if (m_languageHook)
+ m_languageHook->DelayedCallClose();
+ }
+
+ static char defaultImage[1024];
+
+ const char *getDefaultImage(const char* cControlType, const char* cTextureType)
+ {
+ // create an xml block so that we can resolve our defaults
+ // <control type="type">
+ // <description />
+ // </control>
+ TiXmlElement control("control");
+ control.SetAttribute("type", cControlType);
+ TiXmlElement filler("description");
+ control.InsertEndChild(filler);
+ g_SkinInfo->ResolveIncludes(&control);
+
+ // ok, now check for our texture type
+ TiXmlElement *pTexture = control.FirstChildElement(cTextureType);
+ if (pTexture)
+ {
+ // found our textureType
+ TiXmlNode *pNode = pTexture->FirstChild();
+ if (pNode && pNode->Value()[0] != '-')
+ {
+ strncpy(defaultImage, pNode->Value(), sizeof(defaultImage));
+ defaultImage[sizeof(defaultImage) - 1] = '\0';
+ return defaultImage;
+ }
+ }
+ return "";
+ }
+
+#ifdef ENABLE_XBMC_TRACE_API
+ static thread_local TraceGuard* tlParent;
+
+ static char** getSpacesArray(int size)
+ {
+ char** ret = new char*[size];
+ for (int i = 0; i < size; i++)
+ {
+ ret[i] = new char[i + 1];
+
+ int j;
+ for (j = 0; j < i; j++)
+ ret[i][j] = ' ';
+ ret[i][j] = 0;
+ }
+ return ret;
+ }
+
+ static char** spaces = getSpacesArray(256);
+
+ const char* TraceGuard::getSpaces() { return spaces[depth]; }
+
+ TraceGuard::TraceGuard(const char* _function) :function(_function)
+ {
+ parent = tlParent;
+ depth = parent == NULL ? 0 : parent->depth + 1;
+
+ tlParent = this;
+
+ CLog::Log(LOGDEBUG, "{}NEWADDON Entering {}", spaces[depth], function);
+ }
+
+ TraceGuard::TraceGuard() :function(NULL)
+ {
+ parent = tlParent;
+ depth = parent == NULL ? 0 : parent->depth + 1;
+ tlParent = this;
+ // silent
+ }
+
+ TraceGuard::~TraceGuard()
+ {
+ if (function)
+ CLog::Log(LOGDEBUG, "{}NEWADDON Leaving {}", spaces[depth], function);
+
+ // need to pop the stack
+ tlParent = this->parent;
+ }
+#endif
+
+
+}
diff --git a/xbmc/interfaces/legacy/AddonUtils.h b/xbmc/interfaces/legacy/AddonUtils.h
new file mode 100644
index 0000000..2bf7de5
--- /dev/null
+++ b/xbmc/interfaces/legacy/AddonUtils.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/*
+ * addon.h
+ *
+ * Created on: Aug 21, 2010
+ * Author: jim
+ */
+
+//#define ENABLE_XBMC_TRACE_API
+
+#include "threads/CriticalSection.h"
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#ifdef TARGET_WINDOWS
+#define __PRETTY_FUNCTION__ __FUNCTION__
+#endif
+
+/**
+ * This file contains the public definitions for the Addon api. It's meant to be used
+ * by those writing language bindings.
+ */
+
+namespace XBMCAddon
+{
+class LanguageHook;
+}
+
+namespace XBMCAddonUtils
+{
+ class GuiLock
+ {
+ public:
+ GuiLock(XBMCAddon::LanguageHook* languageHook, bool offScreen);
+ ~GuiLock();
+
+ protected:
+ XBMCAddon::LanguageHook* m_languageHook = nullptr;
+ bool m_offScreen = false;
+ };
+
+ class InvertSingleLockGuard
+ {
+ std::unique_lock<CCriticalSection>& lock;
+
+ public:
+ explicit InvertSingleLockGuard(std::unique_lock<CCriticalSection>& _lock) : lock(_lock)
+ {
+ lock.unlock();
+ }
+ ~InvertSingleLockGuard() { lock.lock(); }
+ };
+
+
+ /*
+ * Looks in references.xml for image name
+ * If none exist return default image name
+ */
+ const char *getDefaultImage(const char* cControlType, const char* cTextureType);
+
+#ifdef ENABLE_XBMC_TRACE_API
+ class TraceGuard
+ {
+ const char* function;
+ public:
+ TraceGuard* parent;
+ int depth;
+
+ const char* getSpaces();
+
+ explicit TraceGuard(const char* _function);
+ TraceGuard();
+ ~TraceGuard();
+ };
+#endif
+}
+
+#ifdef ENABLE_XBMC_TRACE_API
+#define XBMC_TRACE XBMCAddonUtils::TraceGuard _tg(__PRETTY_FUNCTION__)
+#else
+#define XBMC_TRACE
+#endif
+
+
diff --git a/xbmc/interfaces/legacy/Alternative.h b/xbmc/interfaces/legacy/Alternative.h
new file mode 100644
index 0000000..a715688
--- /dev/null
+++ b/xbmc/interfaces/legacy/Alternative.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Exception.h"
+
+namespace XBMCAddon
+{
+ enum WhichAlternative { none, first, second };
+
+ template<typename T1, typename T2> class Alternative
+ {
+ public:
+ private:
+ WhichAlternative pos = none;
+ T1 d1;
+ T2 d2;
+
+ public:
+ Alternative() = default;
+
+ inline WhichAlternative which() const { return pos; }
+
+ inline T1& former()
+ {
+ if (pos == second)// first and none is ok
+ throw WrongTypeException("Access of XBMCAddon::Alternative as incorrect type");
+ if (pos == none)
+ d1 = T1();
+ pos = first;
+ return d1;
+ }
+
+ inline const T1& former() const
+ {
+ if (pos != first)
+ throw WrongTypeException("Access of XBMCAddon::Alternative as incorrect type");
+ return d1;
+ }
+
+ inline T2& later()
+ {
+ if (pos == first)
+ throw WrongTypeException("Access of XBMCAddon::Alternative as incorrect type");
+ if (pos == none)
+ d2 = T2();
+ pos = second;
+ return d2;
+ }
+
+ inline const T2& later() const
+ {
+ if (pos != second)
+ throw WrongTypeException("Access of XBMCAddon::Alternative as incorrect type");
+ return d2;
+ }
+
+ inline operator T1& () { return former(); }
+ inline operator const T1& () const { return former(); }
+ inline operator T2& () { return later(); }
+ inline operator const T2& () const { return later(); }
+ };
+}
+
diff --git a/xbmc/interfaces/legacy/CMakeLists.txt b/xbmc/interfaces/legacy/CMakeLists.txt
new file mode 100644
index 0000000..d92fc78
--- /dev/null
+++ b/xbmc/interfaces/legacy/CMakeLists.txt
@@ -0,0 +1,76 @@
+set(SOURCES AddonCallback.cpp
+ AddonClass.cpp
+ Addon.cpp
+ AddonUtils.cpp
+ CallbackFunction.cpp
+ CallbackHandler.cpp
+ Control.cpp
+ Dialog.cpp
+ DrmCryptoSession.cpp
+ File.cpp
+ InfoTagGame.cpp
+ InfoTagMusic.cpp
+ InfoTagPicture.cpp
+ InfoTagRadioRDS.cpp
+ InfoTagVideo.cpp
+ Keyboard.cpp
+ LanguageHook.cpp
+ ListItem.cpp
+ ModuleXbmc.cpp
+ ModuleXbmcgui.cpp
+ ModuleXbmcplugin.cpp
+ ModuleXbmcvfs.cpp
+ Monitor.cpp
+ Player.cpp
+ PlayList.cpp
+ Settings.cpp
+ String.cpp
+ Window.cpp
+ WindowDialog.cpp
+ WindowDialogMixin.cpp
+ WindowXML.cpp)
+
+set(HEADERS Addon.h
+ AddonCallback.h
+ AddonClass.h
+ AddonString.h
+ AddonUtils.h
+ Alternative.h
+ aojsonrpc.h
+ CallbackFunction.h
+ CallbackHandler.h
+ Control.h
+ Dialog.h
+ Dictionary.h
+ DrmCryptoSession.h
+ Exception.h
+ File.h
+ InfoTagGame.h
+ InfoTagMusic.h
+ InfoTagPicture.h
+ InfoTagRadioRDS.h
+ InfoTagVideo.h
+ Keyboard.h
+ LanguageHook.h
+ List.h
+ ListItem.h
+ ModuleXbmc.h
+ ModuleXbmcgui.h
+ ModuleXbmcplugin.h
+ ModuleXbmcvfs.h
+ Monitor.h
+ Player.h
+ PlayList.h
+ RenderCapture.h
+ Settings.h
+ Stat.h
+ swighelper.h
+ Tuple.h
+ Window.h
+ WindowDialog.h
+ WindowDialogMixin.h
+ WindowException.h
+ WindowInterceptor.h
+ WindowXML.h)
+
+core_add_library(legacy_interface)
diff --git a/xbmc/interfaces/legacy/CallbackFunction.cpp b/xbmc/interfaces/legacy/CallbackFunction.cpp
new file mode 100644
index 0000000..fdd6cf8
--- /dev/null
+++ b/xbmc/interfaces/legacy/CallbackFunction.cpp
@@ -0,0 +1,14 @@
+/*
+ * 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 "CallbackFunction.h"
+
+namespace XBMCAddon
+{
+ Callback::~Callback() { XBMC_TRACE; deallocating(); }
+}
diff --git a/xbmc/interfaces/legacy/CallbackFunction.h b/xbmc/interfaces/legacy/CallbackFunction.h
new file mode 100644
index 0000000..90360d5
--- /dev/null
+++ b/xbmc/interfaces/legacy/CallbackFunction.h
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+
+namespace XBMCAddon
+{
+ /**
+ * <p>This is the parent class for the class templates that hold
+ * a callback. A callback is essentially a templatized
+ * functor (functoid?) for a call to a member function.</p>
+ *
+ * <p>This class combined with the attending CallbackHandlers should make
+ * sure that the AddonClass isn't in the midst of deallocating when
+ * the callback executes. In this way the Callback class acts as
+ * a weak reference.</p>
+ */
+ class Callback : public AddonClass
+ {
+ protected:
+ AddonClass* addonClassObject;
+ explicit Callback(AddonClass* _object) : addonClassObject(_object) { XBMC_TRACE; }
+
+ public:
+ virtual void executeCallback() = 0;
+ ~Callback() override;
+
+ AddonClass* getObject() { XBMC_TRACE; return addonClassObject; }
+ };
+
+ struct cb_null_type {};
+
+ // stub type template to be partial specialized
+ template<typename M = cb_null_type, typename T1 = cb_null_type,
+ typename T2 = cb_null_type, typename T3 = cb_null_type,
+ typename T4 = cb_null_type, typename Extraneous = cb_null_type>
+ class CallbackFunction {};
+
+ /**
+ * This is the template to carry a callback to a member function
+ * that returns 'void' (has no return) and takes no parameters.
+ */
+ template<class M> class CallbackFunction<M, cb_null_type, cb_null_type, cb_null_type, cb_null_type, cb_null_type> : public Callback
+ {
+ public:
+ typedef void (M::*MemberFunction)();
+
+ protected:
+ MemberFunction meth;
+ M* obj;
+
+ public:
+ CallbackFunction(M* object, MemberFunction method) :
+ Callback(object), meth(method), obj(object) { XBMC_TRACE; }
+
+ ~CallbackFunction() override { XBMC_TRACE; deallocating(); }
+
+ void executeCallback() override { XBMC_TRACE; ((*obj).*(meth))(); }
+ };
+
+ /**
+ * This is the template to carry a callback to a member function
+ * that returns 'void' (has no return) and takes one parameter.
+ */
+ template<class M, typename P1> class CallbackFunction<M,P1, cb_null_type, cb_null_type, cb_null_type, cb_null_type> : public Callback
+ {
+ public:
+ typedef void (M::*MemberFunction)(P1);
+
+ protected:
+ MemberFunction meth;
+ M* obj;
+ P1 param;
+
+ public:
+ CallbackFunction(M* object, MemberFunction method, P1 parameter) :
+ Callback(object), meth(method), obj(object),
+ param(parameter) { XBMC_TRACE; }
+
+ ~CallbackFunction() override { XBMC_TRACE; deallocating(); }
+
+ void executeCallback() override { XBMC_TRACE; ((*obj).*(meth))(param); }
+ };
+
+ /**
+ * This is the template to carry a callback to a member function
+ * that returns 'void' (has no return) and takes one parameter
+ * that can be held in an AddonClass::Ref
+ */
+ template<class M, typename P1> class CallbackFunction<M,AddonClass::Ref<P1>, cb_null_type, cb_null_type, cb_null_type, cb_null_type> : public Callback
+ {
+ public:
+ typedef void (M::*MemberFunction)(P1*);
+
+ protected:
+ MemberFunction meth;
+ M* obj;
+ AddonClass::Ref<P1> param;
+
+ public:
+ CallbackFunction(M* object, MemberFunction method, P1* parameter) :
+ Callback(object), meth(method), obj(object),
+ param(parameter) { XBMC_TRACE; }
+
+ ~CallbackFunction() override { XBMC_TRACE; deallocating(); }
+
+ void executeCallback() override { XBMC_TRACE; ((*obj).*(meth))(param); }
+ };
+
+
+ /**
+ * This is the template to carry a callback to a member function
+ * that returns 'void' (has no return) and takes two parameters.
+ */
+ template<class M, typename P1, typename P2> class CallbackFunction<M,P1,P2, cb_null_type, cb_null_type, cb_null_type> : public Callback
+ {
+ public:
+ typedef void (M::*MemberFunction)(P1,P2);
+
+ protected:
+ MemberFunction meth;
+ M* obj;
+ P1 param1;
+ P2 param2;
+
+ public:
+ CallbackFunction(M* object, MemberFunction method, P1 parameter, P2 parameter2) :
+ Callback(object), meth(method), obj(object),
+ param1(parameter), param2(parameter2) { XBMC_TRACE; }
+
+ ~CallbackFunction() override { XBMC_TRACE; deallocating(); }
+
+ void executeCallback() override { XBMC_TRACE; ((*obj).*(meth))(param1,param2); }
+ };
+
+
+ /**
+ * This is the template to carry a callback to a member function
+ * that returns 'void' (has no return) and takes three parameters.
+ */
+ template<class M, typename P1, typename P2, typename P3> class CallbackFunction<M,P1,P2,P3, cb_null_type, cb_null_type> : public Callback
+ {
+ public:
+ typedef void (M::*MemberFunction)(P1,P2,P3);
+
+ protected:
+ MemberFunction meth;
+ M* obj;
+ P1 param1;
+ P2 param2;
+ P3 param3;
+
+ public:
+ CallbackFunction(M* object, MemberFunction method, P1 parameter, P2 parameter2, P3 parameter3) :
+ Callback(object), meth(method), obj(object),
+ param1(parameter), param2(parameter2), param3(parameter3) { XBMC_TRACE; }
+
+ ~CallbackFunction() override { XBMC_TRACE; deallocating(); }
+
+ void executeCallback() override { XBMC_TRACE; ((*obj).*(meth))(param1,param2,param3); }
+ };
+}
+
+
diff --git a/xbmc/interfaces/legacy/CallbackHandler.cpp b/xbmc/interfaces/legacy/CallbackHandler.cpp
new file mode 100644
index 0000000..f567168
--- /dev/null
+++ b/xbmc/interfaces/legacy/CallbackHandler.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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 "CallbackHandler.h"
+
+#include "AddonUtils.h"
+#include "commons/Exception.h"
+#include "utils/log.h"
+
+#include <mutex>
+#include <vector>
+
+namespace XBMCAddon
+{
+ class AsyncCallbackMessage : public AddonClass
+ {
+ public:
+ AddonClass::Ref<Callback> cb;
+ AddonClass::Ref<RetardedAsyncCallbackHandler> handler;
+ AsyncCallbackMessage(Callback* _cb, RetardedAsyncCallbackHandler* _handler) :
+ cb(_cb), handler(_handler) { XBMC_TRACE; }
+ };
+
+ //********************************************************************
+ // This holds the callback messages which will be executed. It doesn't
+ // seem to work correctly with the Ref object so we'll go with Ref*'s
+ typedef std::vector<AddonClass::Ref<AsyncCallbackMessage> > CallbackQueue;
+ //********************************************************************
+
+ static CCriticalSection critSection;
+ static CallbackQueue g_callQueue;
+
+ void RetardedAsyncCallbackHandler::invokeCallback(Callback* cb)
+ {
+ XBMC_TRACE;
+ std::unique_lock<CCriticalSection> lock(critSection);
+ g_callQueue.push_back(new AsyncCallbackMessage(cb,this));
+ }
+
+ RetardedAsyncCallbackHandler::~RetardedAsyncCallbackHandler()
+ {
+ XBMC_TRACE;
+ std::unique_lock<CCriticalSection> lock(critSection);
+
+ // find any messages that might be there because of me ... and remove them
+ CallbackQueue::iterator iter = g_callQueue.begin();
+ while (iter != g_callQueue.end())
+ {
+ if ((*iter)->handler.get() == this) // then this message is because of me
+ {
+ g_callQueue.erase(iter);
+ iter = g_callQueue.begin();
+ }
+ else
+ ++iter;
+ }
+ }
+
+ void RetardedAsyncCallbackHandler::makePendingCalls()
+ {
+ XBMC_TRACE;
+ std::unique_lock<CCriticalSection> lock(critSection);
+ CallbackQueue::iterator iter = g_callQueue.begin();
+ while (iter != g_callQueue.end())
+ {
+ AddonClass::Ref<AsyncCallbackMessage> p(*iter);
+
+ // only call when we are in the right thread state
+ if(p->handler->isStateOk(p->cb->getObject()))
+ {
+ // remove it from the queue. No matter what we're done with
+ // this. Even if it doesn't execute for some reason.
+ g_callQueue.erase(iter);
+
+ // we need to release the critSection lock prior to grabbing the
+ // lock on the object. Not doing so results in deadlocks. We no
+ // longer are accessing the g_callQueue so it's fine to do this now
+ {
+ XBMCAddonUtils::InvertSingleLockGuard unlock(lock);
+
+ // make sure the object is not deallocating
+
+ // we need to grab the object lock to see if the object of the call
+ // is deallocating. holding this lock should prevent it from
+ // deallocating during the execution of this call.
+#ifdef ENABLE_XBMC_TRACE_API
+ CLog::Log(LOGDEBUG, "{}NEWADDON executing callback 0x{:x}", _tg.getSpaces(),
+ (long)(p->cb.get()));
+#endif
+ AddonClass* obj = (p->cb->getObject());
+ AddonClass::Ref<AddonClass> ref(obj);
+ std::unique_lock<CCriticalSection> lock2(*obj);
+ if (!p->cb->getObject()->isDeallocating())
+ {
+ try
+ {
+ // need to make the call
+ p->cb->executeCallback();
+ }
+ catch (XbmcCommons::Exception& e) { e.LogThrowMessage(); }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "Unknown exception while executing callback {:#x}",
+ reinterpret_cast<int64_t>(p->cb.get()));
+ }
+ }
+ }
+
+ // since the state of the iterator may have been corrupted by
+ // the changing state of the list from another thread during
+ // the releasing fo the lock in the immediately preceeding
+ // codeblock, we need to reset it before continuing the loop
+ iter = g_callQueue.begin();
+ }
+ else // if we're not in the right thread for this callback...
+ ++iter;
+ }
+ }
+
+ void RetardedAsyncCallbackHandler::clearPendingCalls(void* userData)
+ {
+ XBMC_TRACE;
+ std::unique_lock<CCriticalSection> lock(critSection);
+ CallbackQueue::iterator iter = g_callQueue.begin();
+ while (iter != g_callQueue.end())
+ {
+ AddonClass::Ref<AsyncCallbackMessage> p(*iter);
+
+ if(p->handler->shouldRemoveCallback(p->cb->getObject(),userData))
+ {
+#ifdef ENABLE_XBMC_TRACE_API
+ CLog::Log(LOGDEBUG,
+ "{}NEWADDON removing callback 0x{:x} for PyThreadState 0x{:x} from queue",
+ _tg.getSpaces(), (long)(p->cb.get()), (long)userData);
+#endif
+ iter = g_callQueue.erase(iter);
+ }
+ else
+ ++iter;
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/CallbackHandler.h b/xbmc/interfaces/legacy/CallbackHandler.h
new file mode 100644
index 0000000..223c74a
--- /dev/null
+++ b/xbmc/interfaces/legacy/CallbackHandler.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "CallbackFunction.h"
+
+namespace XBMCAddon
+{
+ /**
+ * This is the abstraction representing different ways to handle
+ * the execution of callbacks. Different language bindings may
+ * have different requirements.
+ */
+ class CallbackHandler : public AddonClass
+ {
+ protected:
+ inline CallbackHandler() = default;
+
+ public:
+ virtual void invokeCallback(Callback* cb) = 0;
+ };
+
+ /**
+ * This class is primarily for Python support (hence the "Retarded"
+ * prefix). Python (et. al. Retarded languages) require that
+ * the context within which a callback executes is under the control
+ * of the language. Therefore, this handler is used to queue
+ * messages over to a language controlled thread for eventual
+ * execution.
+ *
+ * @todo Allow a cross thread synchronous execution.
+ * Fix the stupid means of calling the clearPendingCalls by passing
+ * userData which is specific to the handler/language type.
+ */
+ class RetardedAsyncCallbackHandler : public CallbackHandler
+ {
+ protected:
+ inline RetardedAsyncCallbackHandler() = default;
+ public:
+
+ ~RetardedAsyncCallbackHandler() override;
+
+ void invokeCallback(Callback* cb) override;
+ static void makePendingCalls();
+ static void clearPendingCalls(void* userData);
+
+ virtual bool isStateOk(AddonClass* obj) = 0;
+ virtual bool shouldRemoveCallback(AddonClass* obj, void* userData) = 0;
+ };
+
+}
diff --git a/xbmc/interfaces/legacy/Control.cpp b/xbmc/interfaces/legacy/Control.cpp
new file mode 100644
index 0000000..62dbac6
--- /dev/null
+++ b/xbmc/interfaces/legacy/Control.cpp
@@ -0,0 +1,1435 @@
+/*
+ * 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 "Control.h"
+
+#include "AddonUtils.h"
+#include "LanguageHook.h"
+#include "ServiceBroker.h"
+#include "WindowException.h"
+#include "guilib/GUIButtonControl.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIControlFactory.h"
+#include "guilib/GUIEditControl.h"
+#include "guilib/GUIFadeLabelControl.h"
+#include "guilib/GUIFontManager.h"
+#include "guilib/GUIImage.h"
+#include "guilib/GUILabel.h"
+#include "guilib/GUILabelControl.h"
+#include "guilib/GUIListContainer.h"
+#include "guilib/GUIProgressControl.h"
+#include "guilib/GUIRadioButtonControl.h"
+#include "guilib/GUISliderControl.h"
+#include "guilib/GUITextBox.h"
+#include "guilib/GUIWindowManager.h"
+#include "listproviders/StaticProvider.h"
+#include "utils/StringUtils.h"
+#include "utils/XBMCTinyXML.h"
+
+using namespace KODI;
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlFadeLabel::ControlFadeLabel(long x, long y, long width, long height,
+ const char* font, const char* _textColor,
+ long _alignment) :
+ strFont("font13"), textColor(0xffffffff), align(_alignment)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ if (font)
+ strFont = font;
+
+ if (_textColor)
+ sscanf(_textColor, "%x", &textColor);
+
+ pGUIControl = NULL;
+ }
+
+ void ControlFadeLabel::addLabel(const String& label)
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_ADD, iParentId, iControlId);
+ msg.SetLabel(label);
+
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ void ControlFadeLabel::reset()
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, iParentId, iControlId);
+
+ vecLabels.clear();
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ CGUIControl* ControlFadeLabel::Create()
+ {
+ CLabelInfo label;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = label.focusedColor = textColor;
+ label.align = align;
+ pGUIControl = new CGUIFadeLabelControl(
+ iParentId,
+ iControlId,
+ (float)dwPosX,
+ (float)dwPosY,
+ (float)dwWidth,
+ (float)dwHeight,
+ label,
+ true,
+ 0,
+ true,
+ false);
+ pGUIControl->SetVisible(m_visible);
+
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, iParentId, iControlId);
+ pGUIControl->OnMessage(msg);
+
+ return pGUIControl;
+ }
+
+ void ControlFadeLabel::setScrolling(bool scroll)
+ {
+ static_cast<CGUIFadeLabelControl*>(pGUIControl)->SetScrolling(scroll);
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlTextBox::ControlTextBox(long x, long y, long width, long height,
+ const char* font, const char* _textColor) :
+ strFont("font13"), textColor(0xffffffff)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ if (font)
+ strFont = font;
+
+ if (_textColor)
+ sscanf(_textColor, "%x", &textColor);
+ }
+
+ void ControlTextBox::setText(const String& text)
+ {
+ if (pGUIControl)
+ {
+ // create message
+ CGUIMessage msg(GUI_MSG_LABEL_SET, iParentId, iControlId);
+ msg.SetLabel(text);
+
+ // send message
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+ else
+ {
+ m_label = text;
+ }
+ }
+
+ String ControlTextBox::getText()
+ {
+ if (pGUIControl == nullptr)
+ return m_label;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ return static_cast<CGUITextBox*>(pGUIControl)->GetDescription();
+ }
+
+ void ControlTextBox::reset()
+ {
+ if (pGUIControl)
+ {
+ // create message
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, iParentId, iControlId);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+ m_label.clear();
+ }
+
+ void ControlTextBox::scroll(long position)
+ {
+ if (pGUIControl)
+ static_cast<CGUITextBox*>(pGUIControl)->Scroll((int)position);
+ }
+
+ void ControlTextBox::autoScroll(int delay, int time, int repeat)
+ {
+ if (pGUIControl)
+ static_cast<CGUITextBox*>(pGUIControl)->SetAutoScrolling(delay, time, repeat);
+ }
+
+ CGUIControl* ControlTextBox::Create()
+ {
+ // create textbox
+ CLabelInfo label;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = label.focusedColor = textColor;
+
+ pGUIControl = new CGUITextBox(iParentId, iControlId,
+ (float)dwPosX, (float)dwPosY, (float)dwWidth, (float)dwHeight,
+ label);
+ pGUIControl->SetVisible(m_visible);
+
+ // set label
+ CGUIMessage msg(GUI_MSG_LABEL_SET, iParentId, iControlId);
+ msg.SetLabel(m_label);
+ pGUIControl->OnMessage(msg);
+
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlButton::ControlButton(long x,
+ long y,
+ long width,
+ long height,
+ const String& label,
+ const char* focusTexture,
+ const char* noFocusTexture,
+ long _textOffsetX,
+ long _textOffsetY,
+ long alignment,
+ const char* font,
+ const char* _textColor,
+ const char* _disabledColor,
+ long angle,
+ const char* _shadowColor,
+ const char* _focusedColor)
+ : textOffsetX(_textOffsetX),
+ textOffsetY(_textOffsetY),
+ align(alignment),
+ strFont("font13"),
+ textColor(0xffffffff),
+ disabledColor(0x60ffffff),
+ iAngle(angle),
+ focusedColor(0xffffffff),
+ strText(label)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ // if texture is supplied use it, else get default ones
+ strTextureFocus = focusTexture ? focusTexture :
+ XBMCAddonUtils::getDefaultImage("button", "texturefocus");
+ strTextureNoFocus = noFocusTexture ? noFocusTexture :
+ XBMCAddonUtils::getDefaultImage("button", "texturenofocus");
+
+ if (font) strFont = font;
+ if (_textColor) sscanf( _textColor, "%x", &textColor );
+ if (_disabledColor) sscanf( _disabledColor, "%x", &disabledColor );
+ if (_shadowColor) sscanf( _shadowColor, "%x", &shadowColor );
+ if (_focusedColor) sscanf( _focusedColor, "%x", &focusedColor );
+ }
+
+ void ControlButton::setLabel(const String& label,
+ const char* font,
+ const char* _textColor,
+ const char* _disabledColor,
+ const char* _shadowColor,
+ const char* _focusedColor,
+ const String& label2)
+ {
+ if (!label.empty()) strText = label;
+ if (!label2.empty()) strText2 = label2;
+ if (font) strFont = font;
+ if (_textColor) sscanf(_textColor, "%x", &textColor);
+ if (_disabledColor) sscanf( _disabledColor, "%x", &disabledColor );
+ if (_shadowColor) sscanf(_shadowColor, "%x", &shadowColor);
+ if (_focusedColor) sscanf(_focusedColor, "%x", &focusedColor);
+
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ static_cast<CGUIButtonControl*>(pGUIControl)->PythonSetLabel(strFont, strText, textColor, shadowColor, focusedColor);
+ static_cast<CGUIButtonControl*>(pGUIControl)->SetLabel2(strText2);
+ static_cast<CGUIButtonControl*>(pGUIControl)->PythonSetDisabledColor(disabledColor);
+ }
+ }
+
+ void ControlButton::setDisabledColor(const char* color)
+ {
+ if (color) sscanf(color, "%x", &disabledColor);
+
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ static_cast<CGUIButtonControl*>(pGUIControl)->PythonSetDisabledColor(disabledColor);
+ }
+ }
+
+ String ControlButton::getLabel()
+ {
+ if (pGUIControl == nullptr)
+ return strText;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ return static_cast<CGUIButtonControl*>(pGUIControl)->GetLabel();
+ }
+
+ String ControlButton::getLabel2()
+ {
+ if (pGUIControl == nullptr)
+ return strText2;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ return static_cast<CGUIButtonControl*>(pGUIControl)->GetLabel2();
+ }
+
+ CGUIControl* ControlButton::Create()
+ {
+ CLabelInfo label;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = textColor;
+ label.disabledColor = disabledColor;
+ label.shadowColor = shadowColor;
+ label.focusedColor = focusedColor;
+ label.align = align;
+ label.offsetX = (float)textOffsetX;
+ label.offsetY = (float)textOffsetY;
+ label.angle = (float)-iAngle;
+ pGUIControl = new CGUIButtonControl(
+ iParentId,
+ iControlId,
+ (float)dwPosX,
+ (float)dwPosY,
+ (float)dwWidth,
+ (float)dwHeight,
+ CTextureInfo(strTextureFocus),
+ CTextureInfo(strTextureNoFocus),
+ label);
+ pGUIControl->SetVisible(m_visible);
+
+ CGUIButtonControl* pGuiButtonControl =
+ static_cast<CGUIButtonControl*>(pGUIControl);
+
+ pGuiButtonControl->SetLabel(strText);
+ pGuiButtonControl->SetLabel2(strText2);
+
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlImage::ControlImage(long x, long y, long width, long height,
+ const char* filename, long aRatio,
+ const char* _colorDiffuse):
+ aspectRatio(aRatio), colorDiffuse(0)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ // check if filename exists
+ strFileName = filename;
+ if (_colorDiffuse)
+ sscanf(_colorDiffuse, "%x", &colorDiffuse);
+ }
+
+ void ControlImage::setImage(const char* imageFilename, const bool useCache)
+ {
+ strFileName = imageFilename;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ static_cast<CGUIImage*>(pGUIControl)->SetFileName(strFileName, false, useCache);
+ }
+
+ void ControlImage::setColorDiffuse(const char* cColorDiffuse)
+ {
+ if (cColorDiffuse) sscanf(cColorDiffuse, "%x", &colorDiffuse);
+ else colorDiffuse = 0;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ static_cast<CGUIImage*>(pGUIControl)->SetColorDiffuse(GUILIB::GUIINFO::CGUIInfoColor(colorDiffuse));
+ }
+
+ CGUIControl* ControlImage::Create()
+ {
+ pGUIControl = new CGUIImage(iParentId, iControlId,
+ (float)dwPosX, (float)dwPosY, (float)dwWidth, (float)dwHeight,
+ CTextureInfo(strFileName));
+ pGUIControl->SetVisible(m_visible);
+
+ if (pGUIControl && aspectRatio <= CAspectRatio::AR_KEEP)
+ static_cast<CGUIImage*>(pGUIControl)->SetAspectRatio((CAspectRatio::ASPECT_RATIO)aspectRatio);
+
+ if (pGUIControl && colorDiffuse)
+ static_cast<CGUIImage*>(pGUIControl)->SetColorDiffuse(GUILIB::GUIINFO::CGUIInfoColor(colorDiffuse));
+
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlProgress::ControlProgress(long x, long y, long width, long height,
+ const char* texturebg,
+ const char* textureleft,
+ const char* texturemid,
+ const char* textureright,
+ const char* textureoverlay)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ // if texture is supplied use it, else get default ones
+ strTextureBg = texturebg ? texturebg :
+ XBMCAddonUtils::getDefaultImage("progress", "texturebg");
+ strTextureLeft = textureleft ? textureleft :
+ XBMCAddonUtils::getDefaultImage("progress", "lefttexture");
+ strTextureMid = texturemid ? texturemid :
+ XBMCAddonUtils::getDefaultImage("progress", "midtexture");
+ strTextureRight = textureright ? textureright :
+ XBMCAddonUtils::getDefaultImage("progress", "righttexture");
+ strTextureOverlay = textureoverlay ? textureoverlay :
+ XBMCAddonUtils::getDefaultImage("progress", "overlaytexture");
+ }
+
+ void ControlProgress::setPercent(float pct)
+ {
+ if (pGUIControl)
+ static_cast<CGUIProgressControl*>(pGUIControl)->SetPercentage(pct);
+ }
+
+ float ControlProgress::getPercent()
+ {
+ return pGUIControl ? static_cast<CGUIProgressControl*>(pGUIControl)->GetPercentage() : 0.0f;
+ }
+
+ CGUIControl* ControlProgress::Create()
+ {
+ pGUIControl = new CGUIProgressControl(iParentId, iControlId,
+ (float)dwPosX, (float)dwPosY,
+ (float)dwWidth,(float)dwHeight,
+ CTextureInfo(strTextureBg), CTextureInfo(strTextureLeft),
+ CTextureInfo(strTextureMid), CTextureInfo(strTextureRight),
+ CTextureInfo(strTextureOverlay));
+ pGUIControl->SetVisible(m_visible);
+
+ if (pGUIControl && colorDiffuse)
+ static_cast<CGUIProgressControl*>(pGUIControl)->SetColorDiffuse(GUILIB::GUIINFO::CGUIInfoColor(colorDiffuse));
+
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlSlider::ControlSlider(long x, long y, long width, long height,
+ const char* textureback,
+ const char* texture,
+ const char* texturefocus, int orientation)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+ iOrientation = orientation;
+
+ // if texture is supplied use it, else get default ones
+ strTextureBack = textureback ? textureback :
+ XBMCAddonUtils::getDefaultImage("slider", "texturesliderbar");
+ strTexture = texture ? texture :
+ XBMCAddonUtils::getDefaultImage("slider", "textureslidernib");
+ strTextureFoc = texturefocus ? texturefocus :
+ XBMCAddonUtils::getDefaultImage("slider", "textureslidernibfocus");
+ }
+
+ float ControlSlider::getPercent()
+ {
+ return pGUIControl ? static_cast<CGUISliderControl*>(pGUIControl)->GetPercentage() : 0.0f;
+ }
+
+ void ControlSlider::setPercent(float pct)
+ {
+ if (pGUIControl)
+ static_cast<CGUISliderControl*>(pGUIControl)->SetPercentage(pct);
+ }
+
+ int ControlSlider::getInt()
+ {
+ return (pGUIControl) ? static_cast<CGUISliderControl*>(pGUIControl)->GetIntValue() : 0;
+ }
+
+ void ControlSlider::setInt(int value, int min, int delta, int max)
+ {
+ if (pGUIControl)
+ {
+ static_cast<CGUISliderControl*>(pGUIControl)->SetType(SLIDER_CONTROL_TYPE_INT);
+ static_cast<CGUISliderControl*>(pGUIControl)->SetRange(min, max);
+ static_cast<CGUISliderControl*>(pGUIControl)->SetIntInterval(delta);
+ static_cast<CGUISliderControl*>(pGUIControl)->SetIntValue(value);
+ }
+ }
+
+ float ControlSlider::getFloat()
+ {
+ return (pGUIControl) ? static_cast<CGUISliderControl*>(pGUIControl)->GetFloatValue() : 0.0f;
+ }
+
+ void ControlSlider::setFloat(float value, float min, float delta, float max)
+ {
+ if (pGUIControl)
+ {
+ static_cast<CGUISliderControl*>(pGUIControl)->SetType(SLIDER_CONTROL_TYPE_FLOAT);
+ static_cast<CGUISliderControl*>(pGUIControl)->SetFloatRange(min, max);
+ static_cast<CGUISliderControl*>(pGUIControl)->SetFloatInterval(delta);
+ static_cast<CGUISliderControl*>(pGUIControl)->SetFloatValue(value);
+ }
+ }
+
+ CGUIControl* ControlSlider::Create ()
+ {
+ pGUIControl = new CGUISliderControl(iParentId, iControlId,(float)dwPosX, (float)dwPosY,
+ (float)dwWidth,(float)dwHeight,
+ CTextureInfo(strTextureBack),CTextureInfo(strTexture),
+ CTextureInfo(strTextureFoc), 0, ORIENTATION(iOrientation));
+
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlGroup::ControlGroup(long x, long y, long width, long height)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+ }
+
+ CGUIControl* ControlGroup::Create()
+ {
+ pGUIControl = new CGUIControlGroup(iParentId,
+ iControlId,
+ (float) dwPosX,
+ (float) dwPosY,
+ (float) dwWidth,
+ (float) dwHeight);
+ pGUIControl->SetVisible(m_visible);
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ ControlRadioButton::ControlRadioButton(long x, long y, long width, long height, const String& label,
+ const char* focusOnTexture, const char* noFocusOnTexture,
+ const char* focusOffTexture, const char* noFocusOffTexture,
+ const char* focusTexture, const char* noFocusTexture,
+ long _textOffsetX, long _textOffsetY,
+ long alignment, const char* font, const char* _textColor,
+ const char* _disabledColor, long angle,
+ const char* _shadowColor, const char* _focusedColor,
+ const char* disabledOnTexture, const char* disabledOffTexture) :
+ strFont("font13"), textColor(0xffffffff), disabledColor(0x60ffffff),
+ textOffsetX(_textOffsetX), textOffsetY(_textOffsetY), align(alignment), iAngle(angle),
+ shadowColor(0), focusedColor(0xffffffff)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ strText = label;
+
+ // if texture is supplied use it, else get default ones
+ strTextureFocus = focusTexture ? focusTexture :
+ XBMCAddonUtils::getDefaultImage("button", "texturefocus");
+ strTextureNoFocus = noFocusTexture ? noFocusTexture :
+ XBMCAddonUtils::getDefaultImage("button", "texturenofocus");
+
+ if (focusOnTexture && noFocusOnTexture)
+ {
+ strTextureRadioOnFocus = focusOnTexture;
+ strTextureRadioOnNoFocus = noFocusOnTexture;
+ }
+ else
+ {
+ strTextureRadioOnFocus =
+ XBMCAddonUtils::getDefaultImage("radiobutton", "textureradioonfocus");
+ strTextureRadioOnNoFocus =
+ XBMCAddonUtils::getDefaultImage("radiobutton", "textureradioonnofocus");
+ }
+
+ if (focusOffTexture && noFocusOffTexture)
+ {
+ strTextureRadioOffFocus = focusOffTexture;
+ strTextureRadioOffNoFocus = noFocusOffTexture;
+ }
+ else
+ {
+ strTextureRadioOffFocus =
+ XBMCAddonUtils::getDefaultImage("radiobutton", "textureradioofffocus");
+ strTextureRadioOffNoFocus =
+ XBMCAddonUtils::getDefaultImage("radiobutton", "textureradiooffnofocus");
+ }
+
+ if (font) strFont = font;
+ if (_textColor) sscanf( _textColor, "%x", &textColor );
+ if (_disabledColor) sscanf( _disabledColor, "%x", &disabledColor );
+ if (_shadowColor) sscanf( _shadowColor, "%x", &shadowColor );
+ if (_focusedColor) sscanf( _focusedColor, "%x", &focusedColor );
+ }
+
+ void ControlRadioButton::setSelected(bool selected)
+ {
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ static_cast<CGUIRadioButtonControl*>(pGUIControl)->SetSelected(selected);
+ }
+ }
+
+ bool ControlRadioButton::isSelected()
+ {
+ bool isSelected = false;
+
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ isSelected = static_cast<CGUIRadioButtonControl*>(pGUIControl)->IsSelected();
+ }
+ return isSelected;
+ }
+
+ void ControlRadioButton::setLabel(const String& label,
+ const char* font,
+ const char* _textColor,
+ const char* _disabledColor,
+ const char* _shadowColor,
+ const char* _focusedColor,
+ const String& label2)
+ {
+ if (!label.empty()) strText = label;
+ if (font) strFont = font;
+ if (_textColor) sscanf(_textColor, "%x", &textColor);
+ if (_disabledColor) sscanf( _disabledColor, "%x", &disabledColor );
+ if (_shadowColor) sscanf(_shadowColor, "%x", &shadowColor);
+ if (_focusedColor) sscanf(_focusedColor, "%x", &focusedColor);
+
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ static_cast<CGUIRadioButtonControl*>(pGUIControl)->PythonSetLabel(strFont, strText, textColor, shadowColor, focusedColor);
+ static_cast<CGUIRadioButtonControl*>(pGUIControl)->PythonSetDisabledColor(disabledColor);
+ }
+ }
+
+ void ControlRadioButton::setRadioDimension(long x, long y, long width, long height)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ static_cast<CGUIRadioButtonControl*>(pGUIControl)->SetRadioDimensions((float)dwPosX, (float)dwPosY, (float)dwWidth, (float)dwHeight);
+ }
+ }
+
+ CGUIControl* ControlRadioButton::Create()
+ {
+ CLabelInfo label;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = textColor;
+ label.disabledColor = disabledColor;
+ label.shadowColor = shadowColor;
+ label.focusedColor = focusedColor;
+ label.align = align;
+ label.offsetX = (float)textOffsetX;
+ label.offsetY = (float)textOffsetY;
+ label.angle = (float)-iAngle;
+ pGUIControl = new CGUIRadioButtonControl(
+ iParentId,
+ iControlId,
+ (float)dwPosX,
+ (float)dwPosY,
+ (float)dwWidth,
+ (float)dwHeight,
+ CTextureInfo(strTextureFocus),
+ CTextureInfo(strTextureNoFocus),
+ label,
+ CTextureInfo(strTextureRadioOnFocus),
+ CTextureInfo(strTextureRadioOnNoFocus),
+ CTextureInfo(strTextureRadioOffFocus),
+ CTextureInfo(strTextureRadioOffNoFocus),
+ CTextureInfo(strTextureRadioOnDisabled),
+ CTextureInfo(strTextureRadioOffDisabled));
+ pGUIControl->SetVisible(m_visible);
+
+ CGUIRadioButtonControl* pGuiButtonControl =
+ static_cast<CGUIRadioButtonControl*>(pGUIControl);
+
+ pGuiButtonControl->SetLabel(strText);
+
+ return pGUIControl;
+ }
+
+ // ============================================================
+
+ // ============================================================
+ // ============================================================
+ Control::~Control() { deallocating(); }
+
+ CGUIControl* Control::Create()
+ {
+ throw WindowException("Object is a Control, but can't be added to a window");
+ }
+
+ std::vector<int> Control::getPosition()
+ {
+ std::vector<int> ret(2);
+ ret[0] = dwPosX;
+ ret[1] = dwPosY;
+ return ret;
+ }
+
+ void Control::setEnabled(bool enabled)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ pGUIControl->SetEnabled(enabled);
+ }
+
+ void Control::setVisible(bool visible)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl != nullptr)
+ {
+ pGUIControl->SetVisible(visible);
+ }
+ else
+ {
+ m_visible = visible;
+ }
+ }
+
+ bool Control::isVisible()
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock(languageHook, false);
+ if (pGUIControl)
+ return pGUIControl->IsVisible();
+ else
+ return false;
+ }
+
+ void Control::setVisibleCondition(const char* visible, bool allowHiddenFocus)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+
+ if (pGUIControl)
+ pGUIControl->SetVisibleCondition(visible, allowHiddenFocus ? "true" : "false");
+ }
+
+ void Control::setEnableCondition(const char* enable)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+
+ if (pGUIControl)
+ pGUIControl->SetEnableCondition(enable);
+ }
+
+ void Control::setAnimations(const std::vector< Tuple<String,String> >& eventAttr)
+ {
+ CXBMCTinyXML xmlDoc;
+ TiXmlElement xmlRootElement("control");
+ TiXmlNode *pRoot = xmlDoc.InsertEndChild(xmlRootElement);
+ if (!pRoot)
+ throw WindowException("TiXmlNode creation error");
+
+ std::vector<CAnimation> animations;
+
+ for (unsigned int anim = 0; anim < eventAttr.size(); anim++)
+ {
+ const Tuple<String,String>& pTuple = eventAttr[anim];
+
+ if (pTuple.GetNumValuesSet() != 2)
+ throw WindowException("Error unpacking tuple found in list");
+
+ const String& cEvent = pTuple.first();
+ const String& cAttr = pTuple.second();
+
+ TiXmlElement pNode("animation");
+ std::vector<std::string> attrs = StringUtils::Split(cAttr, " ");
+ for (const auto& i : attrs)
+ {
+ std::vector<std::string> attrs2 = StringUtils::Split(i, "=");
+ if (attrs2.size() == 2)
+ pNode.SetAttribute(attrs2[0], attrs2[1]);
+ }
+ TiXmlText value(cEvent.c_str());
+ pNode.InsertEndChild(value);
+ pRoot->InsertEndChild(pNode);
+ }
+
+ const CRect animRect((float)dwPosX, (float)dwPosY, (float)dwPosX + dwWidth, (float)dwPosY + dwHeight);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ {
+ CGUIControlFactory::GetAnimations(pRoot, animRect, iParentId, animations);
+ pGUIControl->SetAnimations(animations);
+ }
+ }
+
+ void Control::setPosition(long x, long y)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ dwPosX = x;
+ dwPosY = y;
+ if (pGUIControl)
+ pGUIControl->SetPosition((float)dwPosX, (float)dwPosY);
+ }
+
+ void Control::setWidth(long width)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ dwWidth = width;
+ if (pGUIControl)
+ pGUIControl->SetWidth((float)dwWidth);
+ }
+
+ void Control::setHeight(long height)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ dwHeight = height;
+ if (pGUIControl)
+ pGUIControl->SetHeight((float)dwHeight);
+ }
+
+ void Control::setNavigation(const Control* up, const Control* down,
+ const Control* left, const Control* right)
+ {
+ if(iControlId == 0)
+ throw WindowException("Control has to be added to a window first");
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ {
+ pGUIControl->SetAction(ACTION_MOVE_UP, CGUIAction(up->iControlId));
+ pGUIControl->SetAction(ACTION_MOVE_DOWN, CGUIAction(down->iControlId));
+ pGUIControl->SetAction(ACTION_MOVE_LEFT, CGUIAction(left->iControlId));
+ pGUIControl->SetAction(ACTION_MOVE_RIGHT, CGUIAction(right->iControlId));
+ }
+ }
+ }
+
+ void Control::controlUp(const Control* control)
+ {
+ if(iControlId == 0)
+ throw WindowException("Control has to be added to a window first");
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ pGUIControl->SetAction(ACTION_MOVE_UP, CGUIAction(control->iControlId));
+ }
+ }
+
+ void Control::controlDown(const Control* control)
+ {
+ if(iControlId == 0)
+ throw WindowException("Control has to be added to a window first");
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ pGUIControl->SetAction(ACTION_MOVE_DOWN, CGUIAction(control->iControlId));
+ }
+ }
+
+ void Control::controlLeft(const Control* control)
+ {
+ if(iControlId == 0)
+ throw WindowException("Control has to be added to a window first");
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ pGUIControl->SetAction(ACTION_MOVE_LEFT, CGUIAction(control->iControlId));
+ }
+ }
+
+ void Control::controlRight(const Control* control)
+ {
+ if(iControlId == 0)
+ throw WindowException("Control has to be added to a window first");
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ if (pGUIControl)
+ pGUIControl->SetAction(ACTION_MOVE_RIGHT, CGUIAction(control->iControlId));
+ }
+ }
+
+ // ============================================================
+ // ControlSpin
+ // ============================================================
+ ControlSpin::ControlSpin()
+ {
+ // default values for spin control
+ color = 0xffffffff;
+ dwPosX = 0;
+ dwPosY = 0;
+ dwWidth = 16;
+ dwHeight = 16;
+
+ // get default images
+ strTextureUp = XBMCAddonUtils::getDefaultImage("listcontrol", "textureup");
+ strTextureDown = XBMCAddonUtils::getDefaultImage("listcontrol", "texturedown");
+ strTextureUpFocus = XBMCAddonUtils::getDefaultImage("listcontrol", "textureupfocus");
+ strTextureDownFocus = XBMCAddonUtils::getDefaultImage("listcontrol", "texturedownfocus");
+ strTextureUpDisabled = XBMCAddonUtils::getDefaultImage("listcontrol", "textureupdisabled");
+ strTextureDownDisabled = XBMCAddonUtils::getDefaultImage("listcontrol", "texturedowndisabled");
+ }
+
+ void ControlSpin::setTextures(const char* up, const char* down,
+ const char* upFocus,
+ const char* downFocus,
+ const char* upDisabled,
+ const char* downDisabled)
+ {
+ strTextureUp = up;
+ strTextureDown = down;
+ strTextureUpFocus = upFocus;
+ strTextureDownFocus = downFocus;
+ strTextureUpDisabled = upDisabled;
+ strTextureDownDisabled = downDisabled;
+ /*
+ PyXBMCGUILock();
+ if (self->pGUIControl)
+ {
+ CGUISpinControl* pControl = (CGUISpinControl*)self->pGUIControl;
+ pControl->se
+ PyXBMCGUIUnlock();
+ */
+ }
+
+ ControlSpin::~ControlSpin() = default;
+ // ============================================================
+
+ // ============================================================
+ // ControlLabel
+ // ============================================================
+ ControlLabel::ControlLabel(long x, long y, long width, long height,
+ const String& label,
+ const char* font, const char* p_textColor,
+ const char* p_disabledColor,
+ long p_alignment,
+ bool hasPath, long angle) :
+ strFont("font13"),
+ textColor(0xffffffff), disabledColor(0x60ffffff),
+ align(p_alignment), bHasPath(hasPath), iAngle(angle)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ strText = label;
+ if (font)
+ strFont = font;
+
+ if (p_textColor)
+ sscanf(p_textColor, "%x", &textColor);
+
+ if (p_disabledColor)
+ sscanf( p_disabledColor, "%x", &disabledColor );
+ }
+
+ ControlLabel::~ControlLabel() = default;
+
+ CGUIControl* ControlLabel::Create()
+ {
+ CLabelInfo label;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = label.focusedColor = textColor;
+ label.disabledColor = disabledColor;
+ label.align = align;
+ label.angle = (float)-iAngle;
+ pGUIControl = new CGUILabelControl(
+ iParentId,
+ iControlId,
+ (float)dwPosX,
+ (float)dwPosY,
+ (float)dwWidth,
+ (float)dwHeight,
+ label,
+ false,
+ bHasPath);
+ pGUIControl->SetVisible(m_visible);
+ static_cast<CGUILabelControl*>(pGUIControl)->SetLabel(strText);
+ return pGUIControl;
+ }
+
+ void ControlLabel::setLabel(const String& label, const char* font,
+ const char* textColor, const char* disabledColor,
+ const char* shadowColor, const char* focusedColor,
+ const String& label2)
+ {
+ strText = label;
+ CGUIMessage msg(GUI_MSG_LABEL_SET, iParentId, iControlId);
+ msg.SetLabel(strText);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ String ControlLabel::getLabel()
+ {
+ return strText;
+ }
+ // ============================================================
+
+ // ============================================================
+ // ControlEdit
+ // ============================================================
+ ControlEdit::ControlEdit(long x, long y, long width, long height, const String& label,
+ const char* font, const char* _textColor,
+ const char* _disabledColor,
+ long _alignment, const char* focusTexture,
+ const char* noFocusTexture) :
+ strFont("font13"), textColor(0xffffffff), disabledColor(0x60ffffff),
+ align(_alignment)
+
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ strTextureFocus = focusTexture ? focusTexture :
+ XBMCAddonUtils::getDefaultImage("edit", "texturefocus");
+
+ strTextureNoFocus = noFocusTexture ? noFocusTexture :
+ XBMCAddonUtils::getDefaultImage("edit", "texturenofocus");
+
+ if (!label.empty())
+ {
+ strText = label;
+ }
+ if (font) strFont = font;
+ if (_textColor) sscanf( _textColor, "%x", &textColor );
+ if (_disabledColor) sscanf( _disabledColor, "%x", &disabledColor );
+ }
+
+ CGUIControl* ControlEdit::Create()
+ {
+ CLabelInfo label;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = label.focusedColor = textColor;
+ label.disabledColor = disabledColor;
+ label.align = align;
+ pGUIControl = new CGUIEditControl(
+ iParentId,
+ iControlId,
+ (float)dwPosX,
+ (float)dwPosY,
+ (float)dwWidth,
+ (float)dwHeight,
+ CTextureInfo(strTextureFocus),
+ CTextureInfo(strTextureNoFocus),
+ label,
+ strText);
+ pGUIControl->SetVisible(m_visible);
+
+ // set label
+ CGUIMessage msg(GUI_MSG_LABEL_SET, iParentId, iControlId);
+ msg.SetLabel(strText);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+
+ return pGUIControl;
+ }
+
+ void ControlEdit::setLabel(const String& label, const char* font,
+ const char* textColor, const char* disabledColor,
+ const char* shadowColor, const char* focusedColor,
+ const String& label2)
+ {
+ strText = label;
+ CGUIMessage msg(GUI_MSG_LABEL_SET, iParentId, iControlId);
+ msg.SetLabel(strText);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ String ControlEdit::getLabel()
+ {
+ return strText;
+ }
+
+ void ControlEdit::setText(const String& text)
+ {
+ // create message
+ CGUIMessage msg(GUI_MSG_LABEL2_SET, iParentId, iControlId);
+ msg.SetLabel(text);
+
+ // send message
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ String ControlEdit::getText()
+ {
+ CGUIMessage msg(GUI_MSG_ITEM_SELECTED, iParentId, iControlId);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg, iParentId);
+
+ return msg.GetLabel();
+ }
+
+ void ControlEdit::setType(int type, const String& heading)
+ {
+ if (pGUIControl)
+ {
+ XBMCAddonUtils::GuiLock(languageHook, false);
+ static_cast<CGUIEditControl*>(pGUIControl)->SetInputType(static_cast<CGUIEditControl::INPUT_TYPE>(type), CVariant{heading});
+ }
+ }
+
+ // ============================================================
+ // ControlList
+ // ============================================================
+ ControlList::ControlList(long x, long y, long width, long height, const char* font,
+ const char* ctextColor, const char* cbuttonTexture,
+ const char* cbuttonFocusTexture,
+ const char* cselectedColor,
+ long _imageWidth, long _imageHeight, long _itemTextXOffset,
+ long _itemTextYOffset, long _itemHeight, long _space, long _alignmentY) :
+ strFont("font13"),
+ textColor(0xe0f0f0f0), selectedColor(0xffffffff),
+ imageHeight(_imageHeight), imageWidth(_imageWidth),
+ itemHeight(_itemHeight), space(_space),
+ itemTextOffsetX(_itemTextXOffset),itemTextOffsetY(_itemTextYOffset),
+ alignmentY(_alignmentY)
+ {
+ dwPosX = x;
+ dwPosY = y;
+ dwWidth = width;
+ dwHeight = height;
+
+ // create a python spin control
+ pControlSpin = new ControlSpin();
+
+ // initialize default values
+ if (font)
+ strFont = font;
+
+ if (ctextColor)
+ sscanf( ctextColor, "%x", &textColor );
+
+ if (cselectedColor)
+ sscanf( cselectedColor, "%x", &selectedColor );
+
+ strTextureButton = cbuttonTexture ? cbuttonTexture :
+ XBMCAddonUtils::getDefaultImage("listcontrol", "texturenofocus");
+
+ strTextureButtonFocus = cbuttonFocusTexture ? cbuttonFocusTexture :
+ XBMCAddonUtils::getDefaultImage("listcontrol", "texturefocus");
+
+ // default values for spin control
+ pControlSpin->dwPosX = dwWidth - 35;
+ pControlSpin->dwPosY = dwHeight - 15;
+ }
+
+ ControlList::~ControlList() = default;
+
+ CGUIControl* ControlList::Create()
+ {
+ CLabelInfo label;
+ label.align = alignmentY;
+ label.font = g_fontManager.GetFont(strFont);
+ label.textColor = label.focusedColor = textColor;
+ //label.shadowColor = shadowColor;
+ label.selectedColor = selectedColor;
+ label.offsetX = (float)itemTextOffsetX;
+ label.offsetY = (float)itemTextOffsetY;
+ // Second label should have the same font, alignment, and colours as the first, but
+ // the offsets should be 0.
+ CLabelInfo label2 = label;
+ label2.offsetX = label2.offsetY = 0;
+ label2.align |= XBFONT_RIGHT;
+
+ pGUIControl = new CGUIListContainer(
+ iParentId,
+ iControlId,
+ (float)dwPosX,
+ (float)dwPosY,
+ (float)dwWidth,
+ (float)dwHeight - pControlSpin->dwHeight - 5,
+ label, label2,
+ CTextureInfo(strTextureButton),
+ CTextureInfo(strTextureButtonFocus),
+ (float)itemHeight,
+ (float)imageWidth, (float)imageHeight,
+ (float)space);
+ pGUIControl->SetVisible(m_visible);
+ return pGUIControl;
+ }
+
+ void ControlList::addItem(const Alternative<String, const XBMCAddon::xbmcgui::ListItem* > & item, bool sendMessage)
+ {
+ XBMC_TRACE;
+
+ if (item.which() == first)
+ internAddListItem(ListItem::fromString(item.former()),sendMessage);
+ else
+ internAddListItem(item.later(),sendMessage);
+ }
+
+ void ControlList::addItems(const std::vector<Alternative<String, const XBMCAddon::xbmcgui::ListItem* > > & items)
+ {
+ XBMC_TRACE;
+
+ for (const auto& iter : items)
+ addItem(iter, false);
+ sendLabelBind(vecItems.size());
+ }
+
+ void ControlList::internAddListItem(const AddonClass::Ref<ListItem>& pListItem,
+ bool sendMessage)
+ {
+ if (pListItem.isNull())
+ throw WindowException("NULL ListItem passed to ControlList::addListItem");
+
+ // add item to objects vector
+ vecItems.push_back(pListItem);
+
+ // send all of the items ... this is what it did before.
+ if (sendMessage)
+ sendLabelBind(vecItems.size());
+ }
+
+ void ControlList::sendLabelBind(int tail)
+ {
+ // construct a CFileItemList to pass 'em on to the list
+ CGUIListItemPtr items(new CFileItemList());
+ for (unsigned int i = vecItems.size() - tail; i < vecItems.size(); i++)
+ static_cast<CFileItemList*>(items.get())->Add(vecItems[i]->item);
+
+ CGUIMessage msg(GUI_MSG_LABEL_BIND, iParentId, iControlId, 0, 0, items);
+ msg.SetPointer(items.get());
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ void ControlList::selectItem(long item)
+ {
+ // create message
+ CGUIMessage msg(GUI_MSG_ITEM_SELECT, iParentId, iControlId, item);
+
+ // send message
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+ }
+
+ void ControlList::removeItem(int index)
+ {
+ if (index < 0 || index >= (int)vecItems.size())
+ throw WindowException("Index out of range");
+
+ vecItems.erase(vecItems.begin() + index);
+
+ sendLabelBind(vecItems.size());
+ }
+
+ void ControlList::reset()
+ {
+ CGUIMessage msg(GUI_MSG_LABEL_RESET, iParentId, iControlId);
+
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iParentId);
+
+ // delete all items from vector
+ // delete all ListItem from vector
+ vecItems.clear(); // this should delete all of the objects
+ }
+
+ Control* ControlList::getSpinControl()
+ {
+ return pControlSpin;
+ }
+
+ long ControlList::getSelectedPosition()
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+
+ // create message
+ CGUIMessage msg(GUI_MSG_ITEM_SELECTED, iParentId, iControlId);
+ long pos = -1;
+
+ // send message
+ if (!vecItems.empty() && pGUIControl)
+ {
+ pGUIControl->OnMessage(msg);
+ pos = msg.GetParam1();
+ }
+
+ return pos;
+ }
+
+ XBMCAddon::xbmcgui::ListItem* ControlList::getSelectedItem()
+ {
+ DelayedCallGuard dcguard(languageHook);
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+
+ // create message
+ CGUIMessage msg(GUI_MSG_ITEM_SELECTED, iParentId, iControlId);
+ AddonClass::Ref<ListItem> pListItem = NULL;
+
+ // send message
+ if (!vecItems.empty() && pGUIControl)
+ {
+ pGUIControl->OnMessage(msg);
+ if (msg.GetParam1() >= 0 && (size_t)msg.GetParam1() < vecItems.size())
+ pListItem = vecItems[msg.GetParam1()];
+ }
+
+ return pListItem.get();
+ }
+
+ void ControlList::setImageDimensions(long imageWidth,long imageHeight)
+ {
+ CLog::Log(LOGWARNING,"ControlList::setImageDimensions was called but ... it currently isn't defined to do anything.");
+ /*
+ PyXBMCGUILock();
+ if (self->pGUIControl)
+ {
+ CGUIListControl* pListControl = (CGUIListControl*) self->pGUIControl;
+ pListControl->SetImageDimensions((float)self->dwImageWidth, (float)self->dwImageHeight );
+ }
+ PyXBMCGUIUnlock();
+ */
+ }
+
+ void ControlList::setItemHeight(long height)
+ {
+ CLog::Log(LOGWARNING,"ControlList::setItemHeight was called but ... it currently isn't defined to do anything.");
+ /*
+ PyXBMCGUILock();
+ if (self->pGUIControl)
+ {
+ CGUIListControl* pListControl = (CGUIListControl*) self->pGUIControl;
+ pListControl->SetItemHeight((float)self->dwItemHeight);
+ }
+ PyXBMCGUIUnlock();
+ */
+ }
+
+ void ControlList::setSpace(int space)
+ {
+ CLog::Log(LOGWARNING,"ControlList::setSpace was called but ... it currently isn't defined to do anything.");
+ /*
+ PyXBMCGUILock();
+ if (self->pGUIControl)
+ {
+ CGUIListControl* pListControl = (CGUIListControl*) self->pGUIControl;
+ pListControl->SetSpaceBetweenItems((float)self->dwSpace);
+ }
+ PyXBMCGUIUnlock();
+ */
+ }
+
+ void ControlList::setPageControlVisible(bool visible)
+ {
+ CLog::Log(LOGWARNING,"ControlList::setPageControlVisible was called but ... it currently isn't defined to do anything.");
+
+ // char isOn = true;
+
+ /*
+ PyXBMCGUILock();
+ if (self->pGUIControl)
+ {
+ ((CGUIListControl*)self->pGUIControl)->SetPageControlVisible((bool)isOn );
+ }
+ PyXBMCGUIUnlock();
+ */
+ }
+
+ long ControlList::size()
+ {
+ return (long)vecItems.size();
+ }
+
+ long ControlList::getItemHeight()
+ {
+ return (long)itemHeight;
+ }
+
+ long ControlList::getSpace()
+ {
+ return (long)space;
+ }
+
+ XBMCAddon::xbmcgui::ListItem* ControlList::getListItem(int index)
+ {
+ if (index < 0 || index >= (int)vecItems.size())
+ throw WindowException("Index out of range");
+
+ AddonClass::Ref<ListItem> pListItem = vecItems[index];
+ return pListItem.get();
+ }
+
+ void ControlList::setStaticContent(const ListItemList* pitems)
+ {
+ const ListItemList& vecItems = *pitems;
+
+ std::vector<CGUIStaticItemPtr> items;
+
+ for (unsigned int item = 0; item < vecItems.size(); item++)
+ {
+ ListItem* pItem = vecItems[item];
+
+ // NOTE: This code has likely not worked fully correctly for some time
+ // In particular, the click behaviour won't be working.
+ CGUIStaticItemPtr newItem(new CGUIStaticItem(*pItem->item));
+ items.push_back(newItem);
+ }
+
+ // set static list
+ std::unique_ptr<IListProvider> provider = std::make_unique<CStaticListProvider>(items);
+ static_cast<CGUIBaseContainer*>(pGUIControl)->SetListProvider(std::move(provider));
+ }
+
+ // ============================================================
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/Control.h b/xbmc/interfaces/legacy/Control.h
new file mode 100644
index 0000000..7441310
--- /dev/null
+++ b/xbmc/interfaces/legacy/Control.h
@@ -0,0 +1,2960 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Alternative.h"
+#include "ListItem.h"
+#include "Tuple.h"
+#include "guilib/GUIControl.h"
+#include "guilib/GUIFont.h"
+#include "input/Key.h"
+#include "swighelper.h"
+#include "utils/ColorUtils.h"
+
+#include <vector>
+
+
+// hardcoded offsets for button controls (and controls that use button controls)
+// ideally they should be dynamically read in as with all the other properties.
+#define CONTROL_TEXT_OFFSET_X 10
+#define CONTROL_TEXT_OFFSET_Y 2
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+
+ /// \defgroup python_xbmcgui_control Control
+ /// \ingroup python_xbmcgui
+ /// @{
+ /// @brief **Code based skin access.**
+ ///
+ /// Offers classes and functions that manipulate the add-on gui controls.
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// \python_class{ Control() }
+ ///
+ /// **Code based skin access.**
+ ///
+ /// Kodi is noted as having a very flexible and robust framework for its
+ /// GUI, making theme-skinning and personal customization very accessible.
+ /// Users can create their own skin (or modify an existing skin) and share
+ /// it with others.
+ ///
+ /// Kodi includes a new GUI library written from scratch. This library
+ /// allows you to skin/change everything you see in Kodi, from the images,
+ /// the sizes and positions of all controls, colours, fonts, and text,
+ /// through to altering navigation and even adding new functionality. The
+ /// skin system is quite complex, and this portion of the manual is dedicated
+ /// to providing in depth information on how it all works, along with tips
+ /// to make the experience a little more pleasant.
+ ///
+ ///-------------------------------------------------------------------------
+ //
+ class Control : public AddonClass
+ {
+ protected:
+ Control() = default;
+
+ public:
+ ~Control() override;
+
+#ifndef SWIG
+ virtual CGUIControl* Create();
+#endif
+
+ // currently we only accept messages from a button or controllist with a select action
+ virtual bool canAcceptMessages(int actionId) { return false; }
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ getId() }
+ /// Returns the control's current id as an integer.
+ ///
+ /// @return int - Current id
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// id = self.button.getId()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getId()
+#else
+ virtual int getId() { return iControlId; }
+#endif
+
+ inline bool operator==(const Control& other) const { return iControlId == other.iControlId; }
+ inline bool operator>(const Control& other) const { return iControlId > other.iControlId; }
+ inline bool operator<(const Control& other) const { return iControlId < other.iControlId; }
+
+ // hack this because it returns a tuple
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ getPosition() }
+ /// Returns the control's current position as a x,y integer tuple.
+ ///
+ /// @return Current position as a x,y integer tuple
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// pos = self.button.getPosition()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getPosition();
+#else
+ virtual std::vector<int> getPosition();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ getX() }
+ /// Returns the control's current X position.
+ ///
+ /// @return int - Current X position
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// posX = self.button.getX()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getX();
+#else
+ int getX() { return dwPosX; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ getY() }
+ /// Returns the control's current Y position.
+ ///
+ /// @return int - Current Y position
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// posY = self.button.getY()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getY();
+#else
+ int getY() { return dwPosY; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ getHeight() }
+ /// Returns the control's current height as an integer.
+ ///
+ /// @return int - Current height
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// height = self.button.getHeight()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getHeight();
+#else
+ virtual int getHeight() { return dwHeight; }
+#endif
+
+ // getWidth() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ getWidth() }
+ /// Returns the control's current width as an integer.
+ ///
+ /// @return int - Current width
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// width = self.button.getWidth()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getWidth();
+#else
+ virtual int getWidth() { return dwWidth; }
+#endif
+
+ // setEnabled() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setEnabled(enabled) }
+ /// Sets the control's enabled/disabled state.
+ ///
+ /// @param enabled bool - True=enabled / False=disabled.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.setEnabled(False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setEnabled(...);
+#else
+ virtual void setEnabled(bool enabled);
+#endif
+
+ // setVisible() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setVisible(visible) }
+ /// Sets the control's visible/hidden state.
+ /// \anchor python_xbmcgui_control_setVisible
+ ///
+ /// @param visible bool - True=visible / False=hidden.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 You can now define the visible state of a control before it being
+ /// added to a window. This value will be taken into account when the control is later
+ /// added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.setVisible(False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setVisible(...);
+#else
+ virtual void setVisible(bool visible);
+#endif
+
+ // isVisible() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ isVisible() }
+ /// Get the control's visible/hidden state with respect to the container/window
+ ///
+ /// @note If a given control is set visible (c.f. \ref python_xbmcgui_control_setVisible "setVisible()"
+ /// but was not yet added to a window, this method will return `False` (the control is not visible yet since
+ /// it was not added to the window).
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// if self.button.isVisible():
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ isVisible(...);
+#else
+ virtual bool isVisible();
+#endif
+
+ // setVisibleCondition() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setVisibleCondition(visible[,allowHiddenFocus]) }
+ /// Sets the control's visible condition.
+ ///
+ /// Allows Kodi to control the visible status of the control.
+ ///
+ /// [List of Conditions](http://kodi.wiki/view/List_of_Boolean_Conditions)
+ ///
+ /// @param visible string - Visible condition
+ /// @param allowHiddenFocus [opt] bool - True=gains focus even if
+ /// hidden
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setVisibleCondition(visible[,allowHiddenFocus])
+ /// self.button.setVisibleCondition('[Control.IsVisible(41) + !Control.IsVisible(12)]', True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setVisibleCondition(...);
+#else
+ virtual void setVisibleCondition(const char* visible, bool allowHiddenFocus = false);
+#endif
+
+ // setEnableCondition() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setEnableCondition(enable) }
+ /// Sets the control's enabled condition.
+ ///
+ /// Allows Kodi to control the enabled status of the control.
+ ///
+ /// [List of Conditions](http://kodi.wiki/view/List_of_Boolean_Conditions)
+ ///
+ /// @param enable string - Enable condition.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setEnableCondition(enable)
+ /// self.button.setEnableCondition('System.InternetState')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setEnableCondition(...);
+#else
+ virtual void setEnableCondition(const char* enable);
+#endif
+
+ // setAnimations() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setAnimations([(event, attr,)*]) }
+ /// Sets the control's animations.
+ ///
+ /// <b>[(event,attr,)*]</b>: list - A list of tuples consisting of event
+ /// and attributes pairs.
+ ///
+ /// [Animating your skin](http://kodi.wiki/view/Animating_Your_Skin)
+ ///
+ /// @param event string - The event to animate.
+ /// @param attr string - The whole attribute string
+ /// separated by spaces.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setAnimations([(event, attr,)*])
+ /// self.button.setAnimations([('focus', 'effect=zoom end=90,247,220,56 time=0',)])
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setAnimations(...);
+#else
+ virtual void setAnimations(const std::vector< Tuple<String,String> >& eventAttr);
+#endif
+
+ // setPosition() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setPosition(x, y) }
+ /// Sets the controls position.
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ ///
+ /// @note You may use negative integers. (e.g sliding a control into view)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.setPosition(100, 250)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setPosition(...);
+#else
+ virtual void setPosition(long x, long y);
+#endif
+
+ // setWidth() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setWidth(width) }
+ /// Sets the controls width.
+ ///
+ /// @param width integer - width of control.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.image.setWidth(100)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setWidth(...);
+#else
+ virtual void setWidth(long width);
+#endif
+
+ // setHeight() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setHeight(height) }
+ /// Sets the controls height.
+ ///
+ /// @param height integer - height of control.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.image.setHeight(100)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setHeight(...);
+#else
+ virtual void setHeight(long height);
+#endif
+
+ // setNavigation() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ setNavigation(up, down, left, right) }
+ /// Sets the controls navigation.
+ ///
+ /// @param up control object - control to navigate to on up.
+ /// @param down control object - control to navigate to on down.
+ /// @param left control object - control to navigate to on left.
+ /// @param right control object - control to navigate to on right.
+ /// @throw TypeError if one of the supplied arguments is not a
+ /// control type.
+ /// @throw ReferenceError if one of the controls is not added to a
+ /// window.
+ ///
+ /// @note Same as controlUp(), controlDown(), controlLeft(), controlRight().
+ /// Set to self to disable navigation for that direction.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.setNavigation(self.button1, self.button2, self.button3, self.button4)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ //
+ setNavigation(...);
+#else
+ virtual void setNavigation(const Control* up, const Control* down,
+ const Control* left, const Control* right);
+#endif
+
+ // controlUp() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ controlUp(control) }
+ /// Sets the controls up navigation.
+ ///
+ /// @param control control object - control to navigate to on up.
+ /// @throw TypeError if one of the supplied arguments is not a
+ /// control type.
+ /// @throw ReferenceError if one of the controls is not added to a
+ /// window.
+ ///
+ ///
+ /// @note You can also use setNavigation(). Set to self to disable navigation.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.controlUp(self.button1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ controlUp(...);
+#else
+ virtual void controlUp(const Control* up);
+#endif
+
+ // controlDown() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ controlDown(control) }
+ /// Sets the controls down navigation.
+ ///
+ /// @param control control object - control to navigate to on down.
+ /// @throw TypeError if one of the supplied arguments is not a
+ /// control type.
+ /// @throw ReferenceError if one of the controls is not added to a
+ /// window.
+ ///
+ ///
+ /// @note You can also use setNavigation(). Set to self to disable navigation.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.controlDown(self.button1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ controlDown(...);
+#else
+ virtual void controlDown(const Control* control);
+#endif
+
+ // controlLeft() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ controlLeft(control) }
+ /// Sets the controls left navigation.
+ ///
+ /// @param control control object - control to navigate to on left.
+ /// @throw TypeError if one of the supplied arguments is not a
+ /// control type.
+ /// @throw ReferenceError if one of the controls is not added to a
+ /// window.
+ ///
+ ///
+ /// @note You can also use setNavigation(). Set to self to disable navigation.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.controlLeft(self.button1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ controlLeft(...);
+#else
+ virtual void controlLeft(const Control* control);
+#endif
+
+ // controlRight() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control
+ /// @brief \python_func{ controlRight(control) }
+ /// Sets the controls right navigation.
+ ///
+ /// @param control control object - control to navigate to on right.
+ /// @throw TypeError if one of the supplied arguments is not a
+ /// control type.
+ /// @throw ReferenceError if one of the controls is not added to a
+ /// window.
+ ///
+ ///
+ /// @note You can also use setNavigation(). Set to self to disable navigation.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.button.controlRight(self.button1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ controlRight(...);
+#else
+ virtual void controlRight(const Control* control);
+#endif
+
+#ifndef SWIG
+ int iControlId = 0;
+ int iParentId = 0;
+ int dwPosX = 0;
+ int dwPosY = 0;
+ int dwWidth = 0;
+ int dwHeight = 0;
+ int iControlUp = 0;
+ int iControlDown = 0;
+ int iControlLeft = 0;
+ int iControlRight = 0;
+ std::string m_label{};
+ bool m_visible{true};
+ CGUIControl* pGUIControl = nullptr;
+#endif
+
+ };
+ /// @}
+
+ /// \defgroup python_xbmcgui_control_spin Subclass - ControlSpin
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used for cycling up/down controls.**
+ ///
+ /// Offers classes and functions that manipulate the add-on gui controls.
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// \python_class{ ControlSpin() }
+ ///
+ /// **Code based skin access.**
+ ///
+ /// The spin control is used for when a list of options can be chosen (such
+ /// as a page up/down control). You can choose the position, size, and look
+ /// of the spin control.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @warning **Not working yet**.
+ /// You can't create this object, it is returned by objects like ControlTextBox and ControlList.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ ///
+ class ControlSpin : public Control
+ {
+ public:
+ ~ControlSpin() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_spin
+ /// @brief \python_func{ setTextures(up, down, upFocus, downFocus) }
+ /// Sets textures for this control.
+ ///
+ /// Texture are image files that are used for example in the skin
+ ///
+ /// @warning **Not working yet**.
+ ///
+ /// @param up label - for the up arrow
+ /// when it doesn't have focus.
+ /// @param down label - for the down button
+ /// when it is not focused.
+ /// @param upFocus label - for the up button
+ /// when it has focus.
+ /// @param downFocus label - for the down button
+ /// when it has focus.
+ /// @param upDisabled label - for the up arrow
+ /// when the button is disabled.
+ /// @param downDisabled label - for the up arrow
+ /// when the button is disabled.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setTextures(up, down, upFocus, downFocus, upDisabled, downDisabled)
+ ///
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setTextures(...);
+#else
+ virtual void setTextures(const char* up, const char* down,
+ const char* upFocus,
+ const char* downFocus,
+ const char* upDisabled, const char* downDisabled);
+#endif
+
+#ifndef SWIG
+ UTILS::COLOR::Color color;
+ std::string strTextureUp;
+ std::string strTextureDown;
+ std::string strTextureUpFocus;
+ std::string strTextureDownFocus;
+ std::string strTextureUpDisabled;
+ std::string strTextureDownDisabled;
+#endif
+
+ private:
+ ControlSpin();
+
+ friend class Window;
+ friend class ControlList;
+
+ };
+ /// @}
+
+ /// \defgroup python_xbmcgui_control_label Subclass - ControlLabel
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used to show some lines of text.**
+ ///
+ /// \python_class{ ControlLabel(x, y, width, height, label[, font, textColor,
+ /// disabledColor, alignment, hasPath, angle]) }
+ ///
+ /// The label control is used for displaying text in Kodi. You can choose
+ /// the font, size, colour, location and contents of the text to be
+ /// displayed.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param label string or unicode - text string.
+ /// @param font [opt] string - font used for label
+ /// text. (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled
+ /// label's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled
+ /// label's label. (e.g. '0xFFFF3300')
+ /// @param alignment [opt] integer - alignment of label
+ /// - \ref kodi_gui_font_alignment "Flags for alignment" used as bits to have several together:
+ /// | Definition name | Bitflag | Description |
+ /// |-------------------|:----------:|:------------------------------------|
+ /// | XBFONT_LEFT | 0x00000000 | Align X left
+ /// | XBFONT_RIGHT | 0x00000001 | Align X right
+ /// | XBFONT_CENTER_X | 0x00000002 | Align X center
+ /// | XBFONT_CENTER_Y | 0x00000004 | Align Y center
+ /// | XBFONT_TRUNCATED | 0x00000008 | Truncated text
+ /// | XBFONT_JUSTIFIED | 0x00000010 | Justify text
+ /// @param hasPath [opt] bool - True=stores a
+ /// path / False=no path
+ /// @param angle [opt] integer - angle of control.
+ /// (<b>+</b> rotates CCW, <b>-</b> rotates C)
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # ControlLabel(x, y, width, height, label[, font, textColor,
+ /// # disabledColor, alignment, hasPath, angle])
+ /// self.label = xbmcgui.ControlLabel(100, 250, 125, 75, 'Status', angle=45)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlLabel : public Control
+ {
+ public:
+ ControlLabel(long x, long y, long width, long height, const String& label,
+ const char* font = NULL, const char* textColor = NULL,
+ const char* disabledColor = NULL,
+ long alignment = XBFONT_LEFT,
+ bool hasPath = false, long angle = 0);
+
+ ~ControlLabel() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_label
+ /// @brief \python_func{ getLabel() }
+ /// Returns the text value for this label.
+ ///
+ /// @return This label
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// label = self.label.getLabel()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getLabel();
+#else
+ virtual String getLabel();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_label
+ /// @brief \python_func{ setLabel(label[, font, textColor, disabledColor, shadowColor, focusedColor, label2]) }
+ /// Sets text for this label.
+ ///
+ /// @param label string or unicode - text string.
+ /// @param font [opt] string - font used for label text.
+ /// (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled
+ /// label's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled
+ /// label's label. (e.g. '0xFFFF3300')
+ /// @param shadowColor [opt] hexstring - color of button's
+ /// label's shadow. (e.g. '0xFF000000')
+ /// @param focusedColor [opt] hexstring - color of focused
+ /// button's label. (e.g. '0xFF00FFFF')
+ /// @param label2 [opt] string or unicode - text string.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.label.setLabel('Status')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setLabel(...);
+#else
+ virtual void setLabel(const String& label = emptyString,
+ const char* font = NULL,
+ const char* textColor = NULL,
+ const char* disabledColor = NULL,
+ const char* shadowColor = NULL,
+ const char* focusedColor = NULL,
+ const String& label2 = emptyString);
+#endif
+
+#ifndef SWIG
+ ControlLabel() = default;
+
+ std::string strFont;
+ std::string strText;
+ UTILS::COLOR::Color textColor;
+ UTILS::COLOR::Color disabledColor;
+ uint32_t align;
+ bool bHasPath = false;
+ int iAngle = 0;
+
+ CGUIControl* Create() override;
+
+#endif
+ };
+ /// @}
+
+ // ControlEdit class
+ /// \defgroup python_xbmcgui_control_edit Subclass - ControlEdit
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// **Used as an input control for the osd keyboard and other input fields.**
+ ///
+ /// \python_class{ ControlEdit(x, y, width, height, label[, font, textColor,
+ /// disabledColor, alignment, focusTexture, noFocusTexture]) }
+ ///
+ /// The edit control allows a user to input text in Kodi. You can choose the
+ /// font, size, colour, location and header of the text to be displayed.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param label string or unicode - text string.
+ /// @param font [opt] string - font used for label text.
+ /// (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled
+ /// label's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled
+ /// label's label. (e.g. '0xFFFF3300')
+ /// @param alignment [opt] integer - alignment of label
+ /// - \ref kodi_gui_font_alignment "Flags for alignment" used as bits to have several together:
+ /// | Definition name | Bitflag | Description |
+ /// |-------------------|:----------:|:------------------------------------|
+ /// | XBFONT_LEFT | 0x00000000 | Align X left
+ /// | XBFONT_RIGHT | 0x00000001 | Align X right
+ /// | XBFONT_CENTER_X | 0x00000002 | Align X center
+ /// | XBFONT_CENTER_Y | 0x00000004 | Align Y center
+ /// | XBFONT_TRUNCATED | 0x00000008 | Truncated text
+ /// | XBFONT_JUSTIFIED | 0x00000010 | Justify text
+ /// @param focusTexture [opt] string - filename for focus texture.
+ /// @param noFocusTexture [opt] string - filename for no focus texture.
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.\n
+ /// After you create the control, you need to add it to the window with
+ /// addControl().\n
+ ///
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v18 Deprecated **isPassword**
+ /// @python_v19 Removed **isPassword**
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.edit = xbmcgui.ControlEdit(100, 250, 125, 75, 'Status')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlEdit : public Control
+ {
+ public:
+ ControlEdit(long x, long y, long width, long height, const String& label,
+ const char* font = NULL, const char* textColor = NULL,
+ const char* disabledColor = NULL,
+ long _alignment = XBFONT_LEFT, const char* focusTexture = NULL,
+ const char* noFocusTexture = NULL);
+
+
+ // setLabel() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_edit
+ /// @brief \python_func{ setLabel(label[, font, textColor, disabledColor, shadowColor, focusedColor, label2]) }
+ /// Sets text heading for this edit control.
+ ///
+ /// @param label string or unicode - text string.
+ /// @param font [opt] string - font used for label text.
+ /// (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled
+ /// label's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled
+ /// label's label. (e.g. '0xFFFF3300')
+ /// @param shadowColor [opt] hexstring - color of button's
+ /// label's shadow. (e.g. '0xFF000000')
+ /// @param focusedColor [opt] hexstring - color of focused
+ /// button's label. (e.g. '0xFF00FFFF')
+ /// @param label2 [opt] string or unicode - text string.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.edit.setLabel('Status')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setLabel(...);
+#else
+ virtual void setLabel(const String& label = emptyString,
+ const char* font = NULL,
+ const char* textColor = NULL,
+ const char* disabledColor = NULL,
+ const char* shadowColor = NULL,
+ const char* focusedColor = NULL,
+ const String& label2 = emptyString);
+#endif
+
+ // getLabel() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_edit
+ /// @brief \python_func{ getLabel() }
+ /// Returns the text heading for this edit control.
+ ///
+ /// @return Heading text
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// label = self.edit.getLabel()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getLabel();
+#else
+ virtual String getLabel();
+#endif
+
+ // setText() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_edit
+ /// @brief \python_func{ setText(value) }
+ /// Sets text value for this edit control.
+ ///
+ /// @param value string or unicode - text string.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.edit.setText('online')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setText(...);
+#else
+ virtual void setText(const String& text);
+#endif
+
+ // getText() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_edit
+ /// @brief \python_func{ getText() }
+ /// Returns the text value for this edit control.
+ ///
+ /// @return Text value of control
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// value = self.edit.getText()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getText();
+#else
+ virtual String getText();
+#endif
+
+#ifndef SWIG
+ ControlEdit() = default;
+
+ std::string strFont;
+ std::string strText;
+ std::string strTextureFocus;
+ std::string strTextureNoFocus;
+ UTILS::COLOR::Color textColor;
+ UTILS::COLOR::Color disabledColor;
+ uint32_t align;
+
+ CGUIControl* Create() override;
+#endif
+
+ // setType() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_edit
+ /// @brief \python_func{ setType(type, heading) }
+ /// Sets the type of this edit control.
+ ///
+ /// @param type integer - type of the edit control.
+ /// | Param | Definition |
+ /// |-----------------------------------------------|:--------------------------------------------|
+ /// | xbmcgui.INPUT_TYPE_TEXT | (standard keyboard)
+ /// | xbmcgui.INPUT_TYPE_NUMBER | (format: #)
+ /// | xbmcgui.INPUT_TYPE_DATE | (format: DD/MM/YYYY)
+ /// | xbmcgui.INPUT_TYPE_TIME | (format: HH:MM)
+ /// | xbmcgui.INPUT_TYPE_IPADDRESS | (format: #.#.#.#)
+ /// | xbmcgui.INPUT_TYPE_PASSWORD | (input is masked)
+ /// | xbmcgui.INPUT_TYPE_PASSWORD_MD5 | (input is masked, return md5 hash of input)
+ /// | xbmcgui.INPUT_TYPE_SECONDS | (format: SS or MM:SS or HH:MM:SS or MM min)
+ /// | xbmcgui.INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW | (numeric input is masked)
+ /// @param heading string or unicode - heading that will be used for to numeric or
+ /// keyboard dialog when the edit control is clicked.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 New option added to mask numeric input.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.edit.setType(xbmcgui.INPUT_TYPE_TIME, 'Please enter the time')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setType(...);
+#else
+ virtual void setType(int type, const String& heading);
+#endif
+ };
+ /// @}
+
+ // ControlList class
+ /// \defgroup python_xbmcgui_control_list Subclass - ControlList
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used for a scrolling lists of items. Replaces the list control.**
+ ///
+ /// \python_class{ ControlList(x, y, width, height[, font, textColor, buttonTexture, buttonFocusTexture,
+ /// selectedColor, imageWidth, imageHeight, itemTextXOffset, itemTextYOffset,
+ /// itemHeight, space, alignmentY, shadowColor]) }
+ ///
+ /// The list container is one of several containers used to display items
+ /// from file lists in various ways. The list container is very
+ /// flexible - it's only restriction is that it is a list - i.e. a single
+ /// column or row of items. The layout of the items is very flexible and
+ /// is up to the skinner.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param font [opt] string - font used for items label. (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of items label. (e.g. '0xFFFFFFFF')
+ /// @param buttonTexture [opt] string - filename for focus texture.
+ /// @param buttonFocusTexture [opt] string - filename for no focus texture.
+ /// @param selectedColor [opt] integer - x offset of label.
+ /// @param imageWidth [opt] integer - width of items icon or thumbnail.
+ /// @param imageHeight [opt] integer - height of items icon or thumbnail.
+ /// @param itemTextXOffset [opt] integer - x offset of items label.
+ /// @param itemTextYOffset [opt] integer - y offset of items label.
+ /// @param itemHeight [opt] integer - height of items.
+ /// @param space [opt] integer - space between items.
+ /// @param alignmentY [opt] integer - Y-axis alignment of items label
+ /// - \ref kodi_gui_font_alignment "Flags for alignment" used as bits to have several together:
+ /// | Definition name | Bitflag | Description |
+ /// |-------------------|:----------:|:------------------------------------|
+ /// | XBFONT_LEFT | 0x00000000 | Align X left
+ /// | XBFONT_RIGHT | 0x00000001 | Align X right
+ /// | XBFONT_CENTER_X | 0x00000002 | Align X center
+ /// | XBFONT_CENTER_Y | 0x00000004 | Align Y center
+ /// | XBFONT_TRUNCATED | 0x00000008 | Truncated text
+ /// | XBFONT_JUSTIFIED | 0x00000010 | Justify text
+ /// @param shadowColor [opt] hexstring - color of items
+ /// label's shadow. (e.g. '0xFF000000')
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.\n
+ /// After you create the control, you need to add it to the window
+ /// with addControl().
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.cList = xbmcgui.ControlList(100, 250, 200, 250, 'font14', space=5)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlList : public Control
+ {
+ void internAddListItem(const AddonClass::Ref<ListItem>& listitem, bool sendMessage);
+
+ public:
+ ControlList(long x, long y, long width, long height, const char* font = NULL,
+ const char* textColor = NULL, const char* buttonTexture = NULL,
+ const char* buttonFocusTexture = NULL,
+ const char* selectedColor = NULL,
+ long _imageWidth=10, long _imageHeight=10, long _itemTextXOffset = CONTROL_TEXT_OFFSET_X,
+ long _itemTextYOffset = CONTROL_TEXT_OFFSET_Y, long _itemHeight = 27, long _space = 2,
+ long _alignmentY = XBFONT_CENTER_Y);
+
+ ~ControlList() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ addItem(item) }
+ /// Add a new item to this list control.
+ ///
+ /// @param item string, unicode or ListItem - item to add.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.addItem('Reboot Kodi')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addItem(...);
+#else
+ virtual void addItem(const Alternative<String, const XBMCAddon::xbmcgui::ListItem* > & item, bool sendMessage = true);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ addItems(items) }
+ /// Adds a list of listitems or strings to this list control.
+ ///
+ /// @param items List - list of strings, unicode objects or ListItems to add.
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ /// Large lists benefit considerably, than using the standard addItem()
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.addItems(items=listitems)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addItems(...);
+#else
+ virtual void addItems(const std::vector<Alternative<String, const XBMCAddon::xbmcgui::ListItem* > > & items);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ selectItem(item) }
+ /// Select an item by index number.
+ ///
+ /// @param item integer - index number of the item to select.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.selectItem(12)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ selectItem(...);
+#else
+ virtual void selectItem(long item);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ removeItem(index) }
+ /// Remove an item by index number.
+ ///
+ /// @param index integer - index number of the item to remove.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.removeItem(12)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ removeItem(...);
+#else
+ virtual void removeItem(int index);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ reset() }
+ /// Clear all ListItems in this control list.
+ ///
+ /// @warning Calling `reset()` will destroy any `ListItem` objects in the
+ /// `ControlList` if not hold by any other class. Make sure you
+ /// you don't call `addItems()` with the previous `ListItem` references
+ /// after calling `reset()`. If you need to preserve the `ListItem` objects after
+ /// `reset()` make sure you store them as members of your `WindowXML` class (see examples).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Examples:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.reset()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ /// The below example shows you how you can reset the `ControlList` but this time avoiding `ListItem` object
+ /// destruction. The example assumes `self` as a `WindowXMLDialog` instance containing a `ControlList`
+ /// with id = 800. The class preserves the `ListItem` objects in a class member variable.
+ ///
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # Get all the ListItem objects in the control
+ /// self.list_control = self.getControl(800) # ControlList object
+ /// self.listitems = [self.list_control.getListItem(item) for item in range(0, self.list_control.size())]
+ /// # Reset the ControlList control
+ /// self.list_control.reset()
+ /// #
+ /// # do something with your ListItem objects here (e.g. sorting.)
+ /// # ...
+ /// #
+ /// # Add them again to the ControlList
+ /// self.list_control.addItems(self.listitems)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ reset();
+#else
+ virtual void reset();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ getSpinControl() }
+ /// Returns the associated ControlSpin object.
+ ///
+ /// @warning Not working completely yet\n
+ /// After adding this control list to a window it is not possible to change
+ /// the settings of this spin control.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// ctl = cList.getSpinControl()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getSpinControl();
+#else
+ virtual Control* getSpinControl();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ getSelectedPosition() }
+ /// Returns the position of the selected item as an integer.
+ ///
+ /// @note Returns -1 for empty lists.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// pos = cList.getSelectedPosition()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getSelectedPosition();
+#else
+ virtual long getSelectedPosition();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ getSelectedItem() }
+ /// Returns the selected item as a ListItem object.
+ ///
+ /// @return The selected item
+ ///
+ ///
+ /// @note Same as getSelectedPosition(), but instead of an integer a ListItem object
+ /// is returned. Returns None for empty lists.\n
+ /// See windowexample.py on how to use this.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// item = cList.getSelectedItem()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getSelectedItem();
+#else
+ virtual XBMCAddon::xbmcgui::ListItem* getSelectedItem();
+#endif
+
+ // setImageDimensions() method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ setImageDimensions(imageWidth, imageHeight) }
+ /// Sets the width/height of items icon or thumbnail.
+ ///
+ /// @param imageWidth [opt] integer - width of items icon or thumbnail.
+ /// @param imageHeight [opt] integer - height of items icon or thumbnail.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.setImageDimensions(18, 18)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setImageDimensions(...);
+#else
+ virtual void setImageDimensions(long imageWidth,long imageHeight);
+#endif
+
+ // setItemHeight() method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @brief \python_func{ setItemHeight(itemHeight) }
+ /// Sets the height of items.
+ ///
+ /// @param itemHeight integer - height of items.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.setItemHeight(25)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setItemHeight(...);
+#else
+ virtual void setItemHeight(long height);
+#endif
+
+ // setSpace() method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ setSpace(space) }
+ /// Sets the space between items.
+ ///
+ /// @param space [opt] integer - space between items.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.setSpace(5)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setSpace(...);
+#else
+ virtual void setSpace(int space);
+#endif
+
+ // setPageControlVisible() method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ setPageControlVisible(visible) }
+ /// Sets the spin control's visible/hidden state.
+ ///
+ /// @param visible boolean - True=visible / False=hidden.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.setPageControlVisible(True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setPageControlVisible(...);
+#else
+ virtual void setPageControlVisible(bool visible);
+#endif
+
+ // size() method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ size() }
+ /// Returns the total number of items in this list control as an integer.
+ ///
+ /// @return Total number of items
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cnt = cList.size()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ size();
+#else
+ virtual long size();
+#endif
+
+ // getItemHeight() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ getItemHeight() }
+ /// Returns the control's current item height as an integer.
+ ///
+ /// @return Current item heigh
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// item_height = self.cList.getItemHeight()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getItemHeight();
+#else
+ virtual long getItemHeight();
+#endif
+
+ // getSpace() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ getSpace() }
+ /// Returns the control's space between items as an integer.
+ ///
+ /// @return Space between items
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// gap = self.cList.getSpace()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getSpace();
+#else
+ virtual long getSpace();
+#endif
+
+ // getListItem() method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ getListItem(index) }
+ /// Returns a given ListItem in this List.
+ ///
+ /// @param index integer - index number of item to return.
+ /// @return List item
+ /// @throw ValueError if index is out of range.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem = cList.getListItem(6)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getListItem(...);
+#else
+ virtual XBMCAddon::xbmcgui::ListItem* getListItem(int index);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_list
+ /// @brief \python_func{ setStaticContent(items) }
+ /// Fills a static list with a list of listitems.
+ ///
+ /// @param items List - list of listitems to add.
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// cList.setStaticContent(items=listitems)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setStaticContent(...);
+#else
+ virtual void setStaticContent(const ListItemList* items);
+#endif
+
+#ifndef SWIG
+ void sendLabelBind(int tail);
+
+ bool canAcceptMessages(int actionId) override
+ { return ((actionId == ACTION_SELECT_ITEM) | (actionId == ACTION_MOUSE_LEFT_CLICK)); }
+
+ // This is called from AddonWindow.cpp but shouldn't be available
+ // to the scripting languages.
+ ControlList() = default;
+
+ std::vector<AddonClass::Ref<ListItem> > vecItems;
+ std::string strFont;
+ AddonClass::Ref<ControlSpin> pControlSpin;
+
+ UTILS::COLOR::Color textColor;
+ UTILS::COLOR::Color selectedColor;
+ std::string strTextureButton;
+ std::string strTextureButtonFocus;
+
+ int imageHeight = 0;
+ int imageWidth = 0;
+ int itemHeight = 0;
+ int space = 0;
+
+ int itemTextOffsetX = 0;
+ int itemTextOffsetY = 0;
+ uint32_t alignmentY;
+
+ CGUIControl* Create() override;
+#endif
+ };
+ /// @}
+
+ // ControlFadeLabel class
+ ///
+ /// \defgroup python_xbmcgui_control_fadelabel Subclass - ControlFadeLabel
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used to show multiple pieces of text in the same position, by
+ /// fading from one to the other.**
+ ///
+ /// \python_class{ ControlFadeLabel(x, y, width, height[, font, textColor, alignment]) }
+ ///
+ /// The fade label control is used for displaying multiple pieces of text
+ /// in the same space in Kodi. You can choose the font, size, colour,
+ /// location and contents of the text to be displayed. The first piece of
+ /// information to display fades in over 50 frames, then scrolls off to
+ /// the left. Once it is finished scrolling off screen, the second piece
+ /// of information fades in and the process repeats. A fade label control
+ /// is not supported in a list container.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param font [opt] string - font used for label text. (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of fadelabel's labels. (e.g. '0xFFFFFFFF')
+ /// @param alignment [opt] integer - alignment of label
+ /// - \ref kodi_gui_font_alignment "Flags for alignment" used as bits to have several together:
+ /// | Definition name | Bitflag | Description |
+ /// |-------------------|:----------:|:------------------------------------|
+ /// | XBFONT_LEFT | 0x00000000 | Align X left
+ /// | XBFONT_RIGHT | 0x00000001 | Align X right
+ /// | XBFONT_CENTER_X | 0x00000002 | Align X center
+ /// | XBFONT_CENTER_Y | 0x00000004 | Align Y center
+ /// | XBFONT_TRUNCATED | 0x00000008 | Truncated text
+ /// | XBFONT_JUSTIFIED | 0x00000010 | Justify text
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.\n
+ /// After you create the control, you need to add it to the window
+ /// with addControl().
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.fadelabel = xbmcgui.ControlFadeLabel(100, 250, 200, 50, textColor='0xFFFFFFFF')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlFadeLabel : public Control
+ {
+ public:
+ ControlFadeLabel(long x, long y, long width, long height,
+ const char* font = NULL,
+ const char* textColor = NULL,
+ long _alignment = XBFONT_LEFT);
+
+ // addLabel() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcgui_control_fadelabel
+ /// @brief \python_func{ addLabel(label) }
+ /// Add a label to this control for scrolling.
+ ///
+ /// @param label string or unicode - text string to add.
+ ///
+ /// @note To remove added text use `reset()` for them.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.fadelabel.addLabel('This is a line of text that can scroll.')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addLabel(...);
+#else
+ virtual void addLabel(const String& label);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_fadelabel
+ /// @brief \python_func{ setScrolling(scroll) }
+ /// Set scrolling. If set to false, the labels won't scroll.
+ /// Defaults to true.
+ ///
+ /// @param scroll boolean - True = enabled / False = disabled
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.fadelabel.setScrolling(False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setScrolling(...);
+#else
+ virtual void setScrolling(bool scroll);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_label
+ /// @brief \python_func{ reset() }
+ /// Clear this fade label.
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.fadelabel.reset()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ reset();
+#else
+ virtual void reset();
+#endif
+
+#ifndef SWIG
+ std::string strFont;
+ UTILS::COLOR::Color textColor;
+ std::vector<std::string> vecLabels;
+ uint32_t align;
+
+ CGUIControl* Create() override;
+
+ ControlFadeLabel() = default;
+#endif
+ };
+ /// @}
+
+ // ControlTextBox class
+ ///
+ /// \defgroup python_xbmcgui_control_textbox Subclass - ControlTextBox
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used to show a multi-page piece of text.**
+ ///
+ /// \python_class{ ControlTextBox(x, y, width, height[, font, textColor]) }
+ ///
+ /// The text box is used for showing a large multipage piece of text in Kodi.
+ /// You can choose the position, size, and look of the text.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param font [opt] string - font used for text. (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of textbox's text. (e.g. '0xFFFFFFFF')
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.\n
+ /// After you create the control, you need to add it to the window with addControl().
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # ControlTextBox(x, y, width, height[, font, textColor])
+ /// self.textbox = xbmcgui.ControlTextBox(100, 250, 300, 300, textColor='0xFFFFFFFF')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ /// As stated above, the GUI control is only created once added to a window. The example
+ /// below shows how a ControlTextBox can be created, added to the current window and
+ /// have some of its properties changed.
+ ///
+ /// **Extended example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// textbox = xbmcgui.ControlTextBox(100, 250, 300, 300, textColor='0xFFFFFFFF')
+ /// window = xbmcgui.Window(xbmcgui.getCurrentWindowId())
+ /// window.addControl(textbox)
+ /// textbox.setText("My Text Box")
+ /// textbox.scroll()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlTextBox : public Control
+ {
+ public:
+ ControlTextBox(long x, long y, long width, long height,
+ const char* font = NULL,
+ const char* textColor = NULL);
+
+ // SetText() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_textbox
+ /// @brief \python_func{ setText(text) }
+ /// Sets the text for this textbox.
+ /// \anchor python_xbmcgui_control_textbox_settext
+ ///
+ /// @param text string - text string.
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v19 setText can now be used before adding the control to the window (the defined
+ /// value is taken into consideration when the control is created)
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setText(text)
+ /// self.textbox.setText('This is a line of text that can wrap.')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setText(...);
+#else
+ virtual void setText(const String& text);
+#endif
+
+ // getText() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_textbox
+ /// @brief \python_func{ getText() }
+ /// Returns the text value for this textbox.
+ ///
+ /// @return To get text from box
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v19 getText() can now be used before adding the control to the window
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getText()
+ /// text = self.text.getText()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getText();
+#else
+ virtual String getText();
+#endif
+
+ // reset() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_textbox
+ /// @brief \python_func{ reset() }
+ /// Clear's this textbox.
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 reset() will reset any text defined for this control even before you add the control to the window
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # reset()
+ /// self.textbox.reset()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ reset();
+#else
+ virtual void reset();
+#endif
+
+ // scroll() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_textbox
+ /// @brief \python_func{ scroll(id) }
+ /// Scrolls to the given position.
+ ///
+ /// @param id integer - position to scroll to.
+ ///
+ /// @note scroll() only works after the control is added to a window.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # scroll(position)
+ /// self.textbox.scroll(10)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ scroll(...);
+#else
+ virtual void scroll(long id);
+#endif
+
+ // autoScroll() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_textbox
+ /// @brief \python_func{ autoScroll(delay, time, repeat) }
+ /// Set autoscrolling times.
+ ///
+ /// @param delay integer - Scroll delay (in ms)
+ /// @param time integer - Scroll time (in ms)
+ /// @param repeat integer - Repeat time
+ ///
+ /// @note autoScroll only works after you add the control to a window.
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v15 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.textbox.autoScroll(1, 2, 1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ autoScroll(...);
+#else
+ virtual void autoScroll(int delay, int time, int repeat);
+#endif
+
+#ifndef SWIG
+ std::string strFont;
+ UTILS::COLOR::Color textColor;
+
+ CGUIControl* Create() override;
+
+ ControlTextBox() = default;
+#endif
+ };
+ /// @}
+
+ // ControlImage class
+ ///
+ /// \defgroup python_xbmcgui_control_image Subclass - ControlImage
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used to show an image.**
+ ///
+ /// \python_class{ ControlImage(x, y, width, height, filename[, aspectRatio, colorDiffuse]) }
+ ///
+ /// The image control is used for displaying images in Kodi. You can choose
+ /// the position, size, transparency and contents of the image to be
+ /// displayed.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param filename string - image filename.
+ /// @param aspectRatio [opt] integer - (values 0 = stretch
+ /// (default), 1 = scale up (crops),
+ /// 2 = scale down (black bar)
+ /// @param colorDiffuse hexString - (example, '0xC0FF0000' (red tint))
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.\n
+ /// After you create the control, you need to add it to the window with
+ /// addControl().
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # ControlImage(x, y, width, height, filename[, aspectRatio, colorDiffuse])
+ /// self.image = xbmcgui.ControlImage(100, 250, 125, 75, aspectRatio=2)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlImage : public Control
+ {
+ public:
+ ControlImage(long x, long y, long width, long height,
+ const char* filename, long aspectRatio = 0,
+ const char* colorDiffuse = NULL);
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_image
+ /// @brief \python_func{ setImage(filename[, useCache]) }
+ /// Changes the image.
+ ///
+ /// @param filename string - image filename.
+ /// @param useCache [opt] bool - True=use cache (default) /
+ /// False=don't use cache.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13 Added new option **useCache**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setImage(filename[, useCache])
+ /// self.image.setImage('special://home/scripts/test.png')
+ /// self.image.setImage('special://home/scripts/test.png', False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setImage(...);
+#else
+ virtual void setImage(const char* imageFilename, const bool useCache = true);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_image
+ /// @brief \python_func{ setColorDiffuse(colorDiffuse) }
+ /// Changes the images color.
+ ///
+ /// @param colorDiffuse hexString - (example, '0xC0FF0000'
+ /// (red tint))
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setColorDiffuse(colorDiffuse)
+ /// self.image.setColorDiffuse('0xC0FF0000')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setColorDiffuse(...);
+#else
+ virtual void setColorDiffuse(const char* hexString);
+#endif
+
+#ifndef SWIG
+ ControlImage() = default;
+
+ std::string strFileName;
+ int aspectRatio = 0;
+ UTILS::COLOR::Color colorDiffuse;
+
+ CGUIControl* Create() override;
+#endif
+ };
+ /// @}
+
+ // ControlImage class
+ ///
+ /// \defgroup python_xbmcgui_control_progress Subclass - ControlProgress
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used to show the progress of a particular operation.**
+ ///
+ /// \python_class{ ControlProgress(x, y, width, height, filename[, texturebg, textureleft, texturemid, textureright, textureoverlay]) }
+ ///
+ /// The progress control is used to show the progress of an item that may
+ /// take a long time, or to show how far through a movie you are. You can
+ /// choose the position, size, and look of the progress control.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param filename string - image filename.
+ /// @param texturebg [opt] string - specifies the image file
+ /// whichshould be displayed in the
+ /// background of the progress control.
+ /// @param textureleft [opt] string - specifies the image file
+ /// whichshould be displayed for the left
+ /// side of the progress bar. This is
+ /// rendered on the left side of the bar.
+ /// @param texturemid [opt] string - specifies the image file
+ /// which should be displayed for the middl
+ /// portion of the progress bar. This is
+ /// the `fill` texture used to fill up the
+ /// bar. It's positioned on the right of
+ /// the `<lefttexture>` texture, and fills
+ /// the gap between the `<lefttexture>` and
+ /// `<righttexture>` textures, depending on
+ /// how far progressed the item is.
+ /// @param textureright [opt] string - specifies the image file
+ /// which should be displayed for the right
+ /// side of the progress bar. This is
+ /// rendered on the right side of the bar.
+ /// @param textureoverlay [opt] string - specifies the image file
+ /// which should be displayed over the top of
+ /// all other images in the progress bar. It
+ /// is centered vertically and horizontally
+ /// within the space taken up by the
+ /// background image.
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.\n
+ /// After you create the control, you need to add it to the window
+ /// with addControl().
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # ControlProgress(x, y, width, height, filename[, texturebg, textureleft, texturemid, textureright, textureoverlay])
+ /// self.image = xbmcgui.ControlProgress(100, 250, 250, 30, 'special://home/scripts/test.png')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlProgress : public Control
+ {
+ public:
+ ControlProgress(long x, long y, long width, long height,
+ const char* texturebg = NULL,
+ const char* textureleft = NULL,
+ const char* texturemid = NULL,
+ const char* textureright = NULL,
+ const char* textureoverlay = NULL);
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_progress
+ /// @brief \python_func{ setPercent(percent) }
+ /// Sets the percentage of the progressbar to show.
+ ///
+ /// @param percent float - percentage of the bar to show.
+ ///
+ ///
+ /// @note valid range for percent is 0-100
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setPercent(percent)
+ /// self.progress.setPercent(60)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setPercent(...);
+#else
+ virtual void setPercent(float pct);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_progress
+ /// @brief \python_func{ getPercent() }
+ /// Returns a float of the percent of the progress.
+ ///
+ /// @return Percent position
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getPercent()
+ /// print(self.progress.getPercent())
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getPercent();
+#else
+ virtual float getPercent();
+#endif
+
+#ifndef SWIG
+ std::string strTextureLeft;
+ std::string strTextureMid;
+ std::string strTextureRight;
+ std::string strTextureBg;
+ std::string strTextureOverlay;
+ int aspectRatio = 0;
+ UTILS::COLOR::Color colorDiffuse;
+
+ CGUIControl* Create() override;
+ ControlProgress() = default;
+#endif
+ };
+ /// @}
+
+ // ControlButton class
+ ///
+ /// \defgroup python_xbmcgui_control_button Subclass - ControlButton
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief <b>A standard push button control.</b>
+ ///
+ /// \python_class{ ControlButton(x, y, width, height, label[, focusTexture, noFocusTexture, textOffsetX, textOffsetY,
+ /// alignment, font, textColor, disabledColor, angle, shadowColor, focusedColor]) }
+ ///
+ /// The button control is used for creating push buttons in Kodi. You can
+ /// choose the position, size, and look of the button, as well as choosing
+ /// what action(s) should be performed when pushed.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param label string or unicode - text string.
+ /// @param focusTexture [opt] string - filename for focus
+ /// texture.
+ /// @param noFocusTexture [opt] string - filename for no focus
+ /// texture.
+ /// @param textOffsetX [opt] integer - x offset of label.
+ /// @param textOffsetY [opt] integer - y offset of label.
+ /// @param alignment [opt] integer - alignment of label
+ /// - \ref kodi_gui_font_alignment "Flags for alignment" used as bits to have several together:
+ /// | Definition name | Bitflag | Description |
+ /// |-------------------|:----------:|:------------------------------------|
+ /// | XBFONT_LEFT | 0x00000000 | Align X left
+ /// | XBFONT_RIGHT | 0x00000001 | Align X right
+ /// | XBFONT_CENTER_X | 0x00000002 | Align X center
+ /// | XBFONT_CENTER_Y | 0x00000004 | Align Y center
+ /// | XBFONT_TRUNCATED | 0x00000008 | Truncated text
+ /// | XBFONT_JUSTIFIED | 0x00000010 | Justify text
+ /// @param font [opt] string - font used for label text.
+ /// (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled
+ /// button's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled
+ /// button's label. (e.g. '0xFFFF3300')
+ /// @param angle [opt] integer - angle of control.
+ /// (+ rotates CCW, - rotates CW)
+ /// @param shadowColor [opt] hexstring - color of button's
+ /// label's shadow. (e.g. '0xFF000000')
+ /// @param focusedColor [opt] hexstring - color of focused
+ /// button's label. (e.g. '0xFF00FFFF')
+ ///
+ /// @note You can use the above as keywords for arguments and skip
+ /// certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require
+ /// the keyword.\n
+ /// After you create the control, you need to add it to the
+ /// window with addControl().
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # ControlButton(x, y, width, height, label[, focusTexture, noFocusTexture, textOffsetX, textOffsetY,
+ /// # alignment, font, textColor, disabledColor, angle, shadowColor, focusedColor])
+ /// self.button = xbmcgui.ControlButton(100, 250, 200, 50, 'Status', font='font14')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlButton : public Control
+ {
+ public:
+ ControlButton(long x, long y, long width, long height, const String& label,
+ const char* focusTexture = NULL, const char* noFocusTexture = NULL,
+ long textOffsetX = CONTROL_TEXT_OFFSET_X,
+ long textOffsetY = CONTROL_TEXT_OFFSET_Y,
+ long alignment = (XBFONT_LEFT | XBFONT_CENTER_Y),
+ const char* font = NULL, const char* textColor = NULL,
+ const char* disabledColor = NULL, long angle = 0,
+ const char* shadowColor = NULL, const char* focusedColor = NULL);
+
+ // setLabel() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_button
+ /// @brief \python_func{ setLabel([label, font, textColor, disabledColor, shadowColor, focusedColor, label2]) }
+ /// Sets this buttons text attributes.
+ ///
+ /// @param label [opt] string or unicode - text string.
+ /// @param font [opt] string - font used for label text. (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled button's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled button's label. (e.g. '0xFFFF3300')
+ /// @param shadowColor [opt] hexstring - color of button's label's shadow. (e.g. '0xFF000000')
+ /// @param focusedColor [opt] hexstring - color of focused button's label. (e.g. '0xFFFFFF00')
+ /// @param label2 [opt] string or unicode - text string.
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setLabel([label, font, textColor, disabledColor, shadowColor, focusedColor])
+ /// self.button.setLabel('Status', 'font14', '0xFFFFFFFF', '0xFFFF3300', '0xFF000000')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setLabel(...);
+#else
+ virtual void setLabel(const String& label = emptyString,
+ const char* font = NULL,
+ const char* textColor = NULL,
+ const char* disabledColor = NULL,
+ const char* shadowColor = NULL,
+ const char* focusedColor = NULL,
+ const String& label2 = emptyString);
+#endif
+
+ // setDisabledColor() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_button
+ /// @brief \python_func{ setDisabledColor(disabledColor) }
+ /// Sets this buttons disabled color.
+ ///
+ /// @param disabledColor hexstring - color of disabled button's label. (e.g. '0xFFFF3300')
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setDisabledColor(disabledColor)
+ /// self.button.setDisabledColor('0xFFFF3300')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setDisabledColor(...);
+#else
+ virtual void setDisabledColor(const char* color);
+#endif
+
+ // getLabel() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_button
+ /// @brief \python_func{ getLabel() }
+ /// Returns the buttons label as a unicode string.
+ ///
+ /// @return Unicode string
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getLabel()
+ /// label = self.button.getLabel()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getLabel();
+#else
+ virtual String getLabel();
+#endif
+
+ // getLabel2() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_button
+ /// @brief \python_func{ getLabel2() }
+ /// Returns the buttons label2 as a string.
+ ///
+ /// @return string of label 2
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getLabel2()
+ /// label = self.button.getLabel2()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getLabel2();
+#else
+ virtual String getLabel2();
+#endif
+
+#ifndef SWIG
+ bool canAcceptMessages(int actionId) override { return true; }
+
+ int textOffsetX = 0;
+ int textOffsetY = 0;
+ UTILS::COLOR::Color align;
+ std::string strFont;
+ UTILS::COLOR::Color textColor;
+ UTILS::COLOR::Color disabledColor;
+ int iAngle = 0;
+ int shadowColor = 0;
+ int focusedColor = 0;
+ std::string strText;
+ std::string strText2;
+ std::string strTextureFocus;
+ std::string strTextureNoFocus;
+
+ CGUIControl* Create() override;
+
+ ControlButton() = default;
+#endif
+ };
+ /// @}
+
+ // ControlGroup class
+ ///
+ /// \defgroup python_xbmcgui_control_group Subclass - ControlGroup
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used to group controls together..**
+ ///
+ /// \python_class{ ControlGroup(x, y, width, height) }
+ ///
+ /// The group control is one of the most important controls. It allows you
+ /// to group controls together, applying attributes to all of them at once.
+ /// It also remembers the last navigated button in the group, so you can set
+ /// the <b>`<onup>`</b> of a control to a group of controls to have it always
+ /// go back to the one you were at before. It also allows you to position
+ /// controls more accurately relative to each other, as any controls within
+ /// a group take their coordinates from the group's top left corner (or from
+ /// elsewhere if you use the <b>"r"</b> attribute). You can have as many
+ /// groups as you like within the skin, and groups within groups are handled
+ /// with no issues.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.group = xbmcgui.ControlGroup(100, 250, 125, 75)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlGroup : public Control
+ {
+ public:
+ ControlGroup(long x, long y, long width, long height);
+
+#ifndef SWIG
+ CGUIControl* Create() override;
+
+ inline ControlGroup() = default;
+#endif
+ };
+ /// @}
+
+ // ControlRadioButton class
+ ///
+ /// \defgroup python_xbmcgui_control_radiobutton Subclass - ControlRadioButton
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **A radio button control (as used for on/off settings).**
+ ///
+ /// \python_class{ ControlRadioButton(x, y, width, height, label[, focusOnTexture, noFocusOnTexture,
+ /// focusOffTexture, noFocusOffTexture, focusTexture, noFocusTexture,
+ /// textOffsetX, textOffsetY, alignment, font, textColor, disabledColor]) }
+ ///
+ /// The radio button control is used for creating push button on/off
+ /// settings in Kodi. You can choose the position, size, and look of the
+ /// button, as well as the focused and unfocused radio textures. Used
+ /// for settings controls.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control.
+ /// @param y integer - y coordinate of control.
+ /// @param width integer - width of control.
+ /// @param height integer - height of control.
+ /// @param label string or unicode - text string.
+ /// @param focusOnTexture [opt] string - filename for radio ON
+ /// focused texture.
+ /// @param noFocusOnTexture [opt] string - filename for radio ON not
+ /// focused texture.
+ /// @param focusOfTexture [opt] string - filename for radio OFF
+ /// focused texture.
+ /// @param noFocusOffTexture [opt] string - filename for radio OFF
+ /// not focused texture.
+ /// @param focusTexture [opt] string - filename for focused button
+ /// texture.
+ /// @param noFocusTexture [opt] string - filename for not focused button
+ /// texture.
+ /// @param textOffsetX [opt] integer - horizontal text offset
+ /// @param textOffsetY [opt] integer - vertical text offset
+ /// @param alignment [opt] integer - alignment of label
+ /// - \ref kodi_gui_font_alignment "Flags for alignment" used as bits to have several together:
+ /// | Definition name | Bitflag | Description |
+ /// |-------------------|:----------:|:------------------------------------|
+ /// | XBFONT_LEFT | 0x00000000 | Align X left
+ /// | XBFONT_RIGHT | 0x00000001 | Align X right
+ /// | XBFONT_CENTER_X | 0x00000002 | Align X center
+ /// | XBFONT_CENTER_Y | 0x00000004 | Align Y center
+ /// | XBFONT_TRUNCATED | 0x00000008 | Truncated text
+ /// | XBFONT_JUSTIFIED | 0x00000010 | Justify text
+ /// @param font [opt] string - font used for label text.
+ /// (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of label when control
+ /// is enabled.
+ /// radiobutton's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of label when control
+ /// is disabled. (e.g. '0xFFFF3300')
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.\n
+ /// After you create the control, you need to add it to the window with
+ /// addControl().
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ /// @python_v13 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.radiobutton = xbmcgui.ControlRadioButton(100, 250, 200, 50, 'Enable', font='font14')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class ControlRadioButton : public Control
+ {
+ public:
+ ControlRadioButton(long x, long y, long width, long height, const String& label,
+ const char* focusOnTexture = NULL, const char* noFocusOnTexture = NULL,
+ const char* focusOffTexture = NULL, const char* noFocusOffTexture = NULL,
+ const char* focusTexture = NULL, const char* noFocusTexture = NULL,
+ long textOffsetX = CONTROL_TEXT_OFFSET_X,
+ long textOffsetY = CONTROL_TEXT_OFFSET_Y,
+ long _alignment = (XBFONT_LEFT | XBFONT_CENTER_Y),
+ const char* font = NULL, const char* textColor = NULL,
+ const char* disabledColor = NULL, long angle = 0,
+ const char* shadowColor = NULL, const char* focusedColor = NULL,
+ const char* disabledOnTexture = NULL, const char* disabledOffTexture = NULL);
+
+ // setSelected() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_radiobutton
+ /// @brief \python_func{ setSelected(selected) }
+ /// **Sets the radio buttons's selected status.**
+ ///
+ /// @param selected bool - True=selected (on) / False=not
+ /// selected (off)
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.radiobutton.setSelected(True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setSelected(...);
+#else
+ virtual void setSelected(bool selected);
+#endif
+
+ // isSelected() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_radiobutton
+ /// @brief \python_func{ isSelected() }
+ /// Returns the radio buttons's selected status.
+ ///
+ /// @return True if selected on
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// is = self.radiobutton.isSelected()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ isSelected();
+#else
+ virtual bool isSelected();
+#endif
+
+ // setLabel() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_radiobutton
+ /// @brief \python_func{ setLabel(label[, font, textColor, disabledColor, shadowColor, focusedColor]) }
+ /// Sets the radio buttons text attributes.
+ ///
+ /// @param label string or unicode - text string.
+ /// @param font [opt] string - font used for label
+ /// text. (e.g. 'font13')
+ /// @param textColor [opt] hexstring - color of enabled radio
+ /// button's label. (e.g. '0xFFFFFFFF')
+ /// @param disabledColor [opt] hexstring - color of disabled
+ /// radio button's label. (e.g. '0xFFFF3300')
+ /// @param shadowColor [opt] hexstring - color of radio
+ /// button's label's shadow.
+ /// (e.g. '0xFF000000')
+ /// @param focusedColor [opt] hexstring - color of focused radio
+ /// button's label. (e.g. '0xFFFFFF00')
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setLabel(label[, font, textColor, disabledColor, shadowColor, focusedColor])
+ /// self.radiobutton.setLabel('Status', 'font14', '0xFFFFFFFF', '0xFFFF3300', '0xFF000000')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setLabel(...);
+#else
+ virtual void setLabel(const String& label = emptyString,
+ const char* font = NULL,
+ const char* textColor = NULL,
+ const char* disabledColor = NULL,
+ const char* shadowColor = NULL,
+ const char* focusedColor = NULL,
+ const String& label2 = emptyString);
+#endif
+
+ // setRadioDimension() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_radiobutton
+ /// @brief \python_func{ setRadioDimension(x, y, width, height) }
+ /// Sets the radio buttons's radio texture's position and size.
+ ///
+ /// @param x integer - x coordinate of radio texture.
+ /// @param y integer - y coordinate of radio texture.
+ /// @param width integer - width of radio texture.
+ /// @param height integer - height of radio texture.
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.radiobutton.setRadioDimension(x=100, y=5, width=20, height=20)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setRadioDimension(...);
+#else
+ virtual void setRadioDimension(long x, long y, long width, long height);
+#endif
+
+#ifndef SWIG
+ bool canAcceptMessages(int actionId) override { return true; }
+
+ std::string strFont;
+ std::string strText;
+ std::string strTextureFocus;
+ std::string strTextureNoFocus;
+ std::string strTextureRadioOnFocus;
+ std::string strTextureRadioOnNoFocus;
+ std::string strTextureRadioOffFocus;
+ std::string strTextureRadioOffNoFocus;
+ std::string strTextureRadioOnDisabled;
+ std::string strTextureRadioOffDisabled;
+ UTILS::COLOR::Color textColor;
+ UTILS::COLOR::Color disabledColor;
+ int textOffsetX = 0;
+ int textOffsetY = 0;
+ uint32_t align;
+ int iAngle = 0;
+ UTILS::COLOR::Color shadowColor;
+ UTILS::COLOR::Color focusedColor;
+
+ CGUIControl* Create() override;
+
+ ControlRadioButton() = default;
+#endif
+ };
+ /// @}
+
+ /// \defgroup python_xbmcgui_control_slider Subclass - ControlSlider
+ /// \ingroup python_xbmcgui_control
+ /// @{
+ /// @brief **Used for a volume slider.**
+ ///
+ /// \python_class{ ControlSlider(x, y, width, height[, textureback, texture, texturefocus, orientation]) }
+ ///
+ /// The slider control is used for things where a sliding bar best represents
+ /// the operation at hand (such as a volume control or seek control). You can
+ /// choose the position, size, and look of the slider control.
+ ///
+ /// @note This class include also all calls from \ref python_xbmcgui_control "Control"
+ ///
+ /// @param x integer - x coordinate of control
+ /// @param y integer - y coordinate of control
+ /// @param width integer - width of control
+ /// @param height integer - height of control
+ /// @param textureback [opt] string - image filename
+ /// @param texture [opt] string - image filename
+ /// @param texturefocus [opt] string - image filename
+ /// @param orientation [opt] integer - orientation of slider (xbmcgui.HORIZONTAL / xbmcgui.VERTICAL (default))
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.\n
+ /// After you create the control, you need to add it to the window
+ /// with addControl().
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ /// @python_v17 **orientation** option added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.slider = xbmcgui.ControlSlider(100, 250, 350, 40)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ class ControlSlider : public Control
+ {
+ public:
+ ControlSlider(long x, long y, long width, long height,
+ const char* textureback = NULL,
+ const char* texture = NULL,
+ const char* texturefocus = NULL, int orientation = 1);
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_slider
+ /// @brief \python_func{ getPercent() }
+ /// Returns a float of the percent of the slider.
+ ///
+ /// @return float - Percent of slider
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// print(self.slider.getPercent())
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getPercent();
+#else
+ virtual float getPercent();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_slider
+ /// @brief \python_func{ setPercent(pct) }
+ /// Sets the percent of the slider.
+ ///
+ /// @param pct float - Percent value of slider
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.slider.setPercent(50)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setPercent(...);
+#else
+ virtual void setPercent(float pct);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_slider
+ /// @brief \python_func{ getInt() }
+ /// Returns the value of the slider.
+ ///
+ /// @return int - value of slider
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// print(self.slider.getInt())
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getInt();
+#else
+ virtual int getInt();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_slider
+ /// @brief \python_func{ setInt(value, min, delta, max) }
+ /// Sets the range, value and step size of the slider.
+ ///
+ /// @param value int - value of slider
+ /// @param min int - min of slider
+ /// @param delta int - step size of slider
+ /// @param max int - max of slider
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.slider.setInt(450, 200, 10, 900)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setInt(...);
+#else
+ virtual void setInt(int value, int min, int delta, int max);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_slider
+ /// @brief \python_func{ getFloat() }
+ /// Returns the value of the slider.
+ ///
+ /// @return float - value of slider
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// print(self.slider.getFloat())
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getFloat();
+#else
+ virtual float getFloat();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_control_slider
+ /// @brief \python_func{ setFloat(value, min, delta, max) }
+ /// Sets the range, value and step size of the slider.
+ ///
+ /// @param value float - value of slider
+ /// @param min float - min of slider
+ /// @param delta float - step size of slider
+ /// @param max float - max of slider
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// self.slider.setFloat(15.0, 10.0, 1.0, 20.0)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setFloat(...);
+#else
+ virtual void setFloat(float value, float min, float delta, float max);
+#endif
+
+#ifndef SWIG
+ std::string strTextureBack;
+ std::string strTexture;
+ std::string strTextureFoc;
+ int iOrientation;
+
+ CGUIControl* Create() override;
+
+ inline ControlSlider() = default;
+#endif
+ };
+ /// @}
+ }
+}
diff --git a/xbmc/interfaces/legacy/Dialog.cpp b/xbmc/interfaces/legacy/Dialog.cpp
new file mode 100644
index 0000000..6dd00f1
--- /dev/null
+++ b/xbmc/interfaces/legacy/Dialog.cpp
@@ -0,0 +1,622 @@
+ /*
+ * 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 "Dialog.h"
+
+#include "LanguageHook.h"
+#include "ListItem.h"
+#include "ModuleXbmcgui.h"
+#include "ServiceBroker.h"
+#include "WindowException.h"
+#include "dialogs/GUIDialogColorPicker.h"
+#include "dialogs/GUIDialogContextMenu.h"
+#include "dialogs/GUIDialogFileBrowser.h"
+#include "dialogs/GUIDialogKaiToast.h"
+#include "dialogs/GUIDialogNumeric.h"
+#include "dialogs/GUIDialogSelect.h"
+#include "dialogs/GUIDialogTextViewer.h"
+#include "dialogs/GUIDialogYesNo.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIKeyboardFactory.h"
+#include "guilib/GUIWindowManager.h"
+#include "messaging/helpers/DialogOKHelper.h"
+#include "music/dialogs/GUIDialogMusicInfo.h"
+#include "settings/MediaSourceSettings.h"
+#include "storage/MediaManager.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/XTimeUtils.h"
+#include "utils/log.h"
+#include "video/dialogs/GUIDialogVideoInfo.h"
+
+ using namespace KODI::MESSAGING;
+
+#define ACTIVE_WINDOW CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ Dialog::~Dialog() = default;
+
+ bool Dialog::yesno(const String& heading,
+ const String& message,
+ const String& nolabel,
+ const String& yeslabel,
+ int autoclose,
+ int defaultbutton)
+ {
+ return yesNoCustomInternal(heading, message, nolabel, yeslabel, emptyString, autoclose,
+ defaultbutton) == 1;
+ }
+
+ int Dialog::yesnocustom(const String& heading,
+ const String& message,
+ const String& customlabel,
+ const String& nolabel,
+ const String& yeslabel,
+ int autoclose,
+ int defaultbutton)
+ {
+ return yesNoCustomInternal(heading, message, nolabel, yeslabel, customlabel, autoclose,
+ defaultbutton);
+ }
+
+ int Dialog::yesNoCustomInternal(const String& heading,
+ const String& message,
+ const String& nolabel,
+ const String& yeslabel,
+ const String& customlabel,
+ int autoclose,
+ int defaultbutton)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogYesNo* pDialog =
+ CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogYesNo>(
+ WINDOW_DIALOG_YES_NO);
+ if (pDialog == nullptr)
+ throw WindowException("Error: Window is null");
+
+ return pDialog->ShowAndGetInput(CVariant{heading}, CVariant{message}, CVariant{nolabel},
+ CVariant{yeslabel}, CVariant{customlabel}, autoclose,
+ defaultbutton);
+ }
+
+ bool Dialog::info(const ListItem* item)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ const AddonClass::Ref<xbmcgui::ListItem> listitem(item);
+ if (listitem->item->HasVideoInfoTag())
+ {
+ CGUIDialogVideoInfo::ShowFor(*listitem->item);
+ return true;
+ }
+ else if (listitem->item->HasMusicInfoTag())
+ {
+ CGUIDialogMusicInfo::ShowFor(listitem->item.get());
+ return true;
+ }
+ return false;
+ }
+
+ int Dialog::contextmenu(const std::vector<String>& list)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogContextMenu* pDialog= CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogContextMenu>(WINDOW_DIALOG_CONTEXT_MENU);
+ if (pDialog == NULL)
+ throw WindowException("Error: Window is NULL, this is not possible :-)");
+
+ CContextButtons choices;
+ for(unsigned int i = 0; i < list.size(); i++)
+ {
+ choices.Add(i, list[i]);
+ }
+ return pDialog->Show(choices);
+ }
+
+
+ int Dialog::select(const String& heading, const std::vector<Alternative<String, const ListItem* > > & list, int autoclose, int preselect, bool useDetails)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogSelect* pDialog= CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT);
+ if (pDialog == NULL)
+ throw WindowException("Error: Window is NULL, this is not possible :-)");
+
+ pDialog->Reset();
+ if (!heading.empty())
+ pDialog->SetHeading(CVariant{heading});
+ for (const auto& item : list)
+ {
+ AddonClass::Ref<ListItem> ritem = item.which() == XBMCAddon::first ? ListItem::fromString(item.former()) : AddonClass::Ref<ListItem>(item.later());
+ CFileItemPtr& fileItem = ritem->item;
+ pDialog->Add(*fileItem);
+ }
+ if (preselect > -1)
+ pDialog->SetSelected(preselect);
+ if (autoclose > 0)
+ pDialog->SetAutoClose(autoclose);
+ pDialog->SetUseDetails(useDetails);
+ pDialog->Open();
+
+ return pDialog->GetSelectedItem();
+ }
+
+
+ std::unique_ptr<std::vector<int>> Dialog::multiselect(const String& heading,
+ const std::vector<Alternative<String, const ListItem* > > & options, int autoclose, const std::vector<int>& preselect, bool useDetails)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogSelect* pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogSelect>(WINDOW_DIALOG_SELECT);
+ if (pDialog == nullptr)
+ throw WindowException("Error: Window is NULL");
+
+ pDialog->Reset();
+ pDialog->SetMultiSelection(true);
+ pDialog->SetHeading(CVariant{heading});
+
+ for (const auto& item : options)
+ {
+ AddonClass::Ref<ListItem> ritem = item.which() == XBMCAddon::first ? ListItem::fromString(item.former()) : AddonClass::Ref<ListItem>(item.later());
+ CFileItemPtr& fileItem = ritem->item;
+ pDialog->Add(*fileItem);
+ }
+ if (autoclose > 0)
+ pDialog->SetAutoClose(autoclose);
+ pDialog->SetUseDetails(useDetails);
+ pDialog->SetSelected(preselect);
+ pDialog->Open();
+
+ if (pDialog->IsConfirmed())
+ return std::unique_ptr<std::vector<int>>(new std::vector<int>(pDialog->GetSelectedItems()));
+ else
+ return std::unique_ptr<std::vector<int>>();
+ }
+
+ bool Dialog::ok(const String& heading, const String& message)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ return HELPERS::ShowOKDialogText(CVariant{heading}, CVariant{message});
+ }
+
+ void Dialog::textviewer(const String& heading, const String& text, bool usemono)
+ {
+ DelayedCallGuard dcguard(languageHook);
+
+ CGUIDialogTextViewer* pDialog = CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogTextViewer>(WINDOW_DIALOG_TEXT_VIEWER);
+ if (pDialog == NULL)
+ throw WindowException("Error: Window is NULL, this is not possible :-)");
+ if (!heading.empty())
+ pDialog->SetHeading(heading);
+ if (!text.empty())
+ pDialog->SetText(text);
+ pDialog->UseMonoFont(usemono);
+ pDialog->Open();
+ }
+
+
+ Alternative<String, std::vector<String> > Dialog::browse(int type, const String& heading,
+ const String& s_shares, const String& maskparam, bool useThumbs,
+ bool useFileDirectories, const String& defaultt,
+ bool enableMultiple)
+ {
+ Alternative<String, std::vector<String> > ret;
+ if (enableMultiple)
+ ret.later() = browseMultiple(type,heading,s_shares,maskparam,useThumbs,useFileDirectories,defaultt);
+ else
+ ret.former() = browseSingle(type,heading,s_shares,maskparam,useThumbs,useFileDirectories,defaultt);
+ return ret;
+ }
+
+ String Dialog::browseSingle(int type, const String& heading, const String& s_shares,
+ const String& maskparam, bool useThumbs,
+ bool useFileDirectories,
+ const String& defaultt )
+ {
+ DelayedCallGuard dcguard(languageHook);
+ std::string value;
+ std::string mask = maskparam;
+ VECSOURCES *shares = CMediaSourceSettings::GetInstance().GetSources(s_shares);
+
+ VECSOURCES localShares;
+ if (!shares)
+ {
+ CServiceBroker::GetMediaManager().GetLocalDrives(localShares);
+ if (StringUtils::CompareNoCase(s_shares, "local") != 0)
+ CServiceBroker::GetMediaManager().GetNetworkLocations(localShares);
+ }
+ else // always append local drives
+ {
+ localShares = *shares;
+ CServiceBroker::GetMediaManager().GetLocalDrives(localShares);
+ }
+
+ if (useFileDirectories && !maskparam.empty())
+ mask += "|.rar|.zip";
+
+ value = defaultt;
+ if (type == 1)
+ CGUIDialogFileBrowser::ShowAndGetFile(localShares, mask, heading, value, useThumbs, useFileDirectories);
+ else if (type == 2)
+ CGUIDialogFileBrowser::ShowAndGetImage(localShares, heading, value);
+ else
+ CGUIDialogFileBrowser::ShowAndGetDirectory(localShares, heading, value, type != 0);
+ return value;
+ }
+
+ std::vector<String> Dialog::browseMultiple(int type, const String& heading, const String& s_shares,
+ const String& mask, bool useThumbs,
+ bool useFileDirectories, const String& defaultt )
+ {
+ DelayedCallGuard dcguard(languageHook);
+ VECSOURCES *shares = CMediaSourceSettings::GetInstance().GetSources(s_shares);
+ std::vector<String> valuelist;
+ String lmask = mask;
+
+ VECSOURCES localShares;
+ if (!shares)
+ {
+ CServiceBroker::GetMediaManager().GetLocalDrives(localShares);
+ if (StringUtils::CompareNoCase(s_shares, "local") != 0)
+ CServiceBroker::GetMediaManager().GetNetworkLocations(localShares);
+ }
+ else // always append local drives
+ {
+ localShares = *shares;
+ CServiceBroker::GetMediaManager().GetLocalDrives(localShares);
+ }
+
+ if (useFileDirectories && !lmask.empty())
+ lmask += "|.rar|.zip";
+
+ if (type == 1)
+ CGUIDialogFileBrowser::ShowAndGetFileList(localShares, lmask, heading, valuelist, useThumbs, useFileDirectories);
+ else if (type == 2)
+ CGUIDialogFileBrowser::ShowAndGetImageList(localShares, heading, valuelist);
+ else
+ throw WindowException("Error: Cannot retrieve multiple directories using browse %s is NULL.",s_shares.c_str());
+
+ return valuelist;
+ }
+
+ String Dialog::numeric(int inputtype, const String& heading, const String& defaultt, bool bHiddenInput)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ std::string value;
+ KODI::TIME::SystemTime timedate;
+ KODI::TIME::GetLocalTime(&timedate);
+
+ if (!heading.empty())
+ {
+ if (inputtype == 1)
+ {
+ if (!defaultt.empty() && defaultt.size() == 10)
+ {
+ const std::string& sDefault = defaultt;
+ timedate.day = atoi(sDefault.substr(0, 2).c_str());
+ timedate.month = atoi(sDefault.substr(3, 4).c_str());
+ timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str());
+ }
+ if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading))
+ value =
+ StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month, timedate.year);
+ else
+ return emptyString;
+ }
+ else if (inputtype == 2)
+ {
+ if (!defaultt.empty() && defaultt.size() == 5)
+ {
+ const std::string& sDefault = defaultt;
+ timedate.hour = atoi(sDefault.substr(0, 2).c_str());
+ timedate.minute = atoi(sDefault.substr(3, 2).c_str());
+ }
+ if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading))
+ value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute);
+ else
+ return emptyString;
+ }
+ else if (inputtype == 3)
+ {
+ value = defaultt;
+ if (!CGUIDialogNumeric::ShowAndGetIPAddress(value, heading))
+ return emptyString;
+ }
+ else if (inputtype == 4)
+ {
+ value = defaultt;
+ if (!CGUIDialogNumeric::ShowAndVerifyNewPassword(value))
+ return emptyString;
+ }
+ else
+ {
+ value = defaultt;
+ if (!CGUIDialogNumeric::ShowAndGetNumber(value, heading, 0, bHiddenInput))
+ return emptyString;
+ }
+ }
+ return value;
+ }
+
+ void Dialog::notification(const String& heading, const String& message, const String& icon, int time, bool sound)
+ {
+ DelayedCallGuard dcguard(languageHook);
+
+ std::string strIcon = getNOTIFICATION_INFO();
+ int iTime = TOAST_DISPLAY_TIME;
+
+ if (time > 0)
+ iTime = time;
+ if (!icon.empty())
+ strIcon = icon;
+
+ if (strIcon == getNOTIFICATION_INFO())
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, heading, message, iTime, sound);
+ else if (strIcon == getNOTIFICATION_WARNING())
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, heading, message, iTime, sound);
+ else if (strIcon == getNOTIFICATION_ERROR())
+ CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, heading, message, iTime, sound);
+ else
+ CGUIDialogKaiToast::QueueNotification(strIcon, heading, message, iTime, sound);
+ }
+
+ String Dialog::input(const String& heading, const String& defaultt, int type, int option, int autoclose)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ std::string value(defaultt);
+ KODI::TIME::SystemTime timedate;
+ KODI::TIME::GetLocalTime(&timedate);
+
+ switch (type)
+ {
+ case INPUT_ALPHANUM:
+ {
+ bool bHiddenInput = (option & ALPHANUM_HIDE_INPUT) == ALPHANUM_HIDE_INPUT;
+ if (!CGUIKeyboardFactory::ShowAndGetInput(value, CVariant{heading}, true, bHiddenInput, autoclose))
+ value = emptyString;
+ }
+ break;
+ case INPUT_NUMERIC:
+ {
+ if (!CGUIDialogNumeric::ShowAndGetNumber(value, heading, autoclose))
+ value = emptyString;
+ }
+ break;
+ case INPUT_DATE:
+ {
+ if (!defaultt.empty() && defaultt.size() == 10)
+ {
+ const std::string& sDefault = defaultt;
+ timedate.day = atoi(sDefault.substr(0, 2).c_str());
+ timedate.month = atoi(sDefault.substr(3, 4).c_str());
+ timedate.year = atoi(sDefault.substr(sDefault.size() - 4).c_str());
+ }
+ if (CGUIDialogNumeric::ShowAndGetDate(timedate, heading))
+ value = StringUtils::Format("{:2}/{:2}/{:4}", timedate.day, timedate.month,
+ timedate.year);
+ else
+ value = emptyString;
+ }
+ break;
+ case INPUT_TIME:
+ {
+ if (!defaultt.empty() && defaultt.size() == 5)
+ {
+ const std::string& sDefault = defaultt;
+ timedate.hour = atoi(sDefault.substr(0, 2).c_str());
+ timedate.minute = atoi(sDefault.substr(3, 2).c_str());
+ }
+ if (CGUIDialogNumeric::ShowAndGetTime(timedate, heading))
+ value = StringUtils::Format("{:2}:{:02}", timedate.hour, timedate.minute);
+ else
+ value = emptyString;
+ }
+ break;
+ case INPUT_IPADDRESS:
+ {
+ if (!CGUIDialogNumeric::ShowAndGetIPAddress(value, heading))
+ value = emptyString;
+ }
+ break;
+ case INPUT_PASSWORD:
+ {
+ bool bResult = false;
+
+ if (option & PASSWORD_VERIFY)
+ bResult = CGUIKeyboardFactory::ShowAndVerifyPassword(value, heading, 0, autoclose) == 0 ? true : false;
+ else
+ bResult = CGUIKeyboardFactory::ShowAndVerifyNewPassword(value, heading, true, autoclose);
+
+ if (!bResult)
+ value = emptyString;
+ }
+ break;
+ default:
+ value = emptyString;
+ break;
+ }
+
+ return value;
+ }
+
+ String Dialog::colorpicker(const String& heading,
+ const String& selectedcolor,
+ const String& colorfile,
+ const std::vector<const ListItem*>& colorlist)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ std::string value = emptyString;
+ CGUIDialogColorPicker* pDialog =
+ CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogColorPicker>(
+ WINDOW_DIALOG_COLOR_PICKER);
+ if (pDialog == nullptr)
+ throw WindowException("Error: Window is NULL, this is not possible :-)");
+
+ pDialog->Reset();
+ if (!heading.empty())
+ pDialog->SetHeading(CVariant{heading});
+
+ if (!colorlist.empty())
+ {
+ CFileItemList items;
+ for (const auto& coloritem : colorlist)
+ {
+ items.Add(coloritem->item);
+ }
+ pDialog->SetItems(items);
+ }
+ else if (!colorfile.empty())
+ pDialog->LoadColors(colorfile);
+ else
+ pDialog->LoadColors();
+
+ if (!selectedcolor.empty())
+ pDialog->SetSelectedColor(selectedcolor);
+
+ pDialog->Open();
+
+ if (pDialog->IsConfirmed())
+ value = pDialog->GetSelectedColor();
+ return value;
+ }
+
+ DialogProgress::~DialogProgress() { XBMC_TRACE; deallocating(); }
+
+ void DialogProgress::deallocating()
+ {
+ XBMC_TRACE;
+
+ if (dlg && open)
+ {
+ DelayedCallGuard dg;
+ dlg->Close();
+ }
+ }
+
+ void DialogProgress::create(const String& heading, const String& message)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogProgress* pDialog= CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogProgress>(WINDOW_DIALOG_PROGRESS);
+
+ if (pDialog == NULL)
+ throw WindowException("Error: Window is NULL, this is not possible :-)");
+
+ dlg = pDialog;
+ open = true;
+
+ pDialog->SetHeading(CVariant{heading});
+
+ if (!message.empty())
+ pDialog->SetText(CVariant{message});
+
+ pDialog->Open();
+ }
+
+ void DialogProgress::update(int percent, const String& message)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogProgress* pDialog = dlg;
+
+ if (pDialog == NULL)
+ throw WindowException("Dialog not created.");
+
+ if (percent >= 0 && percent <= 100)
+ {
+ pDialog->SetPercentage(percent);
+ pDialog->ShowProgressBar(true);
+ }
+ else
+ {
+ pDialog->ShowProgressBar(false);
+ }
+
+ if (!message.empty())
+ pDialog->SetText(CVariant{message});
+ }
+
+ void DialogProgress::close()
+ {
+ DelayedCallGuard dcguard(languageHook);
+ if (dlg == NULL)
+ throw WindowException("Dialog not created.");
+ dlg->Close();
+ open = false;
+ }
+
+ bool DialogProgress::iscanceled()
+ {
+ if (dlg == NULL)
+ throw WindowException("Dialog not created.");
+ return dlg->IsCanceled();
+ }
+
+ DialogProgressBG::~DialogProgressBG() { XBMC_TRACE; deallocating(); }
+
+ void DialogProgressBG::deallocating()
+ {
+ XBMC_TRACE;
+
+ if (dlg && open)
+ {
+ DelayedCallGuard dg;
+ dlg->Close();
+ }
+ }
+
+ void DialogProgressBG::create(const String& heading, const String& message)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogExtendedProgressBar* pDialog =
+ CServiceBroker::GetGUI()->GetWindowManager().GetWindow<CGUIDialogExtendedProgressBar>(WINDOW_DIALOG_EXT_PROGRESS);
+
+ if (pDialog == NULL)
+ throw WindowException("Error: Window is NULL, this is not possible :-)");
+
+ CGUIDialogProgressBarHandle* pHandle = pDialog->GetHandle(heading);
+
+ dlg = pDialog;
+ handle = pHandle;
+ open = true;
+
+ pHandle->SetTitle(heading);
+ if (!message.empty())
+ pHandle->SetText(message);
+ }
+
+ void DialogProgressBG::update(int percent, const String& heading, const String& message)
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CGUIDialogProgressBarHandle* pHandle = handle;
+
+ if (pHandle == NULL)
+ throw WindowException("Dialog not created.");
+
+ if (percent >= 0 && percent <= 100)
+ pHandle->SetPercentage((float)percent);
+ if (!heading.empty())
+ pHandle->SetTitle(heading);
+ if (!message.empty())
+ pHandle->SetText(message);
+ }
+
+ void DialogProgressBG::close()
+ {
+ DelayedCallGuard dcguard(languageHook);
+ if (handle == NULL)
+ throw WindowException("Dialog not created.");
+ handle->MarkFinished();
+ open = false;
+ }
+
+ bool DialogProgressBG::isFinished()
+ {
+ if (handle == NULL)
+ throw WindowException("Dialog not created.");
+ return handle->IsFinished();
+ }
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/Dialog.h b/xbmc/interfaces/legacy/Dialog.h
new file mode 100644
index 0000000..9faa733
--- /dev/null
+++ b/xbmc/interfaces/legacy/Dialog.h
@@ -0,0 +1,965 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "AddonString.h"
+#include "Alternative.h"
+#include "ListItem.h"
+#include "dialogs/GUIDialogBoxBase.h"
+#include "dialogs/GUIDialogExtendedProgressBar.h"
+#include "dialogs/GUIDialogProgress.h"
+#include "swighelper.h"
+
+#include <string>
+#include <vector>
+
+namespace XBMCAddon
+{
+namespace xbmcgui
+{
+constexpr int INPUT_ALPHANUM{0};
+constexpr int INPUT_NUMERIC{1};
+constexpr int INPUT_DATE{2};
+constexpr int INPUT_TIME{3};
+constexpr int INPUT_IPADDRESS{4};
+constexpr int INPUT_PASSWORD{5};
+
+constexpr int PASSWORD_VERIFY{1};
+constexpr int ALPHANUM_HIDE_INPUT{2};
+
+ ///
+ /// \defgroup python_Dialog Dialog
+ /// \ingroup python_xbmcgui
+ /// @{
+ /// @brief **Kodi's dialog class**
+ ///
+ /// The graphical control element dialog box (also called dialogue box or
+ /// just dialog) is a small window that communicates information to the user
+ /// and prompts them for a response.
+ ///
+ class Dialog : public AddonClass
+ {
+ public:
+
+ inline Dialog() = default;
+ ~Dialog() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().yesno(heading, message, [nolabel, yeslabel, autoclose]) }
+ /// **Yes / no dialog**
+ ///
+ /// The Yes / No dialog can be used to inform the user about questions and
+ /// get the answer.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param message string or unicode - message text.
+ /// @param nolabel [opt] label to put on the no button.
+ /// @param yeslabel [opt] label to put on the yes button.
+ /// @param autoclose [opt] integer - milliseconds to autoclose dialog. (default=do not autoclose)
+ /// @param defaultbutton [opt] integer - specifies the default focused button.
+ /// <em>(default=DLG_YESNO_NO_BTN)</em>
+ /// | Value: | Description: |
+ /// |------------------------------:|---------------------------------------------------|
+ /// | xbmcgui.DLG_YESNO_NO_BTN | Set the "No" button as default.
+ /// | xbmcgui.DLG_YESNO_YES_BTN | Set the "Yes" button as default.
+ /// | xbmcgui.DLG_YESNO_CUSTOM_BTN | Set the "Custom" button as default.
+ /// @return Returns True if 'Yes' was pressed, else False.
+ ///
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v13 Added new option **autoclose**.
+ /// @python_v19 Renamed option **line1** to **message**.
+ /// @python_v19 Removed option **line2**.
+ /// @python_v19 Removed option **line3**.
+ /// @python_v20 Added new option **defaultbutton**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ret = dialog.yesno('Kodi', 'Do you want to exit this script?')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ yesno(...);
+#else
+ bool yesno(const String& heading,
+ const String& message,
+ const String& nolabel = emptyString,
+ const String& yeslabel = emptyString,
+ int autoclose = 0,
+ int defaultbutton = CONTROL_NO_BUTTON);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().yesnocustom(heading, message, customlabel, [nolabel, yeslabel, autoclose]) }
+ /// **Yes / no / custom dialog**
+ ///
+ /// The YesNoCustom dialog can be used to inform the user about questions and
+ /// get the answer. The dialog provides a third button appart from yes and no.
+ /// Button labels are fully customizable.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param message string or unicode - message text.
+ /// @param customlabel string or unicode - label to put on the custom button.
+ /// @param nolabel [opt] label to put on the no button.
+ /// @param yeslabel [opt] label to put on the yes button.
+ /// @param autoclose [opt] integer - milliseconds to autoclose dialog. (default=do not autoclose)
+ /// @param defaultbutton [opt] integer - specifies the default focused button.
+ /// <em>(default=DLG_YESNO_NO_BTN)</em>
+ /// | Value: | Description: |
+ /// |------------------------------:|---------------------------------------------------|
+ /// | xbmcgui.DLG_YESNO_NO_BTN | Set the "No" button as default.
+ /// | xbmcgui.DLG_YESNO_YES_BTN | Set the "Yes" button as default.
+ /// | xbmcgui.DLG_YESNO_CUSTOM_BTN | Set the "Custom" button as default.
+ /// @return Returns the integer value for the selected button (-1:cancelled, 0:no, 1:yes, 2:custom)
+ ///
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v19 New function added.
+ /// @python_v20 Added new option **defaultbutton**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ret = dialog.yesnocustom('Kodi', 'Question?', 'Maybe')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ yesnocustom(...);
+#else
+ int yesnocustom(const String& heading,
+ const String& message,
+ const String& customlabel,
+ const String& nolabel = emptyString,
+ const String& yeslabel = emptyString,
+ int autoclose = 0,
+ int defaultbutton = CONTROL_NO_BUTTON);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().info(listitem) }
+ /// **Info dialog**
+ ///
+ /// Show the corresponding info dialog for a given listitem
+ ///
+ /// @param listitem xbmcgui.ListItem - ListItem to show info for.
+ /// @return Returns whether the dialog opened successfully.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ret = dialog.info(listitem)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ info(...);
+#else
+ bool info(const ListItem* item);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().select(heading, list[, autoclose, preselect, useDetails]) }
+ /// **Select dialog**
+ ///
+ /// Show of a dialog to select of an entry as a key
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param list list of strings / xbmcgui.ListItems - list of items shown in dialog.
+ /// @param autoclose [opt] integer - milliseconds to autoclose dialog. (default=do not autoclose)
+ /// @param preselect [opt] integer - index of preselected item. (default=no preselected item)
+ /// @param useDetails [opt] bool - use detailed list instead of a compact list. (default=false)
+ /// @return Returns the position of the highlighted item as an integer.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v17 **preselect** option added.
+ /// @python_v17 Added new option **useDetails**.
+ /// @python_v17 Allow listitems for parameter **list**
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ret = dialog.select('Choose a playlist', ['Playlist #1', 'Playlist #2, 'Playlist #3'])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ select(...);
+#else
+ int select(const String& heading, const std::vector<Alternative<String, const ListItem* > > & list, int autoclose=0, int preselect=-1, bool useDetails=false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().contextmenu(list) }
+ /// Show a context menu.
+ ///
+ /// @param list string list - list of items.
+ /// @return the position of the highlighted item as an integer
+ /// (-1 if cancelled).
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ /// @python_v17 New function added
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ret = dialog.contextmenu(['Option #1', 'Option #2', 'Option #3'])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ contextmenu(...);
+#else
+ int contextmenu(const std::vector<String>& list);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().multiselect(heading, options[, autoclose, preselect, useDetails]) }
+ /// Show a multi-select dialog.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param options list of strings / xbmcgui.ListItems - options to choose from.
+ /// @param autoclose [opt] integer - milliseconds to autoclose dialog.
+ /// (default=do not autoclose)
+ /// @param preselect [opt] list of int - indexes of items to preselect
+ /// in list (default: do not preselect any item)
+ /// @param useDetails [opt] bool - use detailed list instead of a compact list. (default=false)
+ /// @return Returns the selected items as a list of indices,
+ /// or None if cancelled.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v16 New function added.
+ /// @python_v17 Added new option **preselect**.
+ /// @python_v17 Added new option **useDetails**.
+ /// @python_v17 Allow listitems for parameter **options**
+ ///
+ /// **Example:**
+ /// @code{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ret = dialog.multiselect("Choose something", ["Foo", "Bar", "Baz"], preselect=[1,2])
+ /// ..
+ /// @endcode
+ ///
+ multiselect(...);
+#else
+ std::unique_ptr<std::vector<int> > multiselect(const String& heading, const std::vector<Alternative<String, const ListItem* > > & options, int autoclose=0, const std::vector<int>& preselect = std::vector<int>(), bool useDetails=false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().ok(heading, message) }
+ /// **OK dialog**
+ ///
+ /// The functions permit the call of a dialog of information, a
+ /// confirmation of the user by press from OK required.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param message string or unicode - message text.
+ /// @return Returns True if 'Ok' was pressed, else False.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v19 Renamed option **line1** to **message**.
+ /// @python_v19 Removed option **line2**.
+ /// @python_v19 Removed option **line3**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// ok = dialog.ok('Kodi', 'There was an error.')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ ok(...);
+#else
+ bool ok(const String& heading, const String& message);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().textviewer(heading, text, usemono) }
+ /// **TextViewer dialog**
+ ///
+ /// The text viewer dialog can be used to display descriptions, help texts
+ /// or other larger texts.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param text string or unicode - text.
+ /// @param usemono [opt] bool - use monospace font
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v16 New function added.
+ /// @python_v18 New optional param added **usemono**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// dialog.textviewer('Plot', 'Some movie plot.')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ textviewer(...);
+#else
+ void textviewer(const String& heading, const String& text, bool usemono = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().browse(type, heading, shares[, mask, useThumbs, treatAsFolder, defaultt, enableMultiple]) }
+ /// **Browser dialog**
+ ///
+ /// The function offer the possibility to select a file by the user of
+ /// the add-on.
+ ///
+ /// It allows all the options that are possible in Kodi itself and offers
+ /// all support file types.
+ ///
+ /// @param type integer - the type of browse dialog.
+ /// | Param | Name |
+ /// |:-----:|:--------------------------------|
+ /// | 0 | ShowAndGetDirectory |
+ /// | 1 | ShowAndGetFile |
+ /// | 2 | ShowAndGetImage |
+ /// | 3 | ShowAndGetWriteableDirectory |
+ /// @param heading string or unicode - dialog heading.
+ /// @param shares string or unicode - from [sources.xml](http://kodi.wiki/view/Sources.xml)
+ /// | Param | Name |
+ /// |:--------------:|:---------------------------------------------|
+ /// | "programs" | list program addons
+ /// | "video" | list video sources
+ /// | "music" | list music sources
+ /// | "pictures" | list picture sources
+ /// | "files" | list file sources (added through filemanager)
+ /// | "games" | list game sources
+ /// | "local" | list local drives
+ /// | "" | list local drives and network shares
+ /// @param mask [opt] string or unicode - '|' separated file mask. (i.e. '.jpg|.png')
+ /// @param useThumbs [opt] boolean - if True autoswitch to Thumb view if files exist.
+ /// @param treatAsFolder [opt] boolean - if True playlists and archives act as folders.
+ /// @param defaultt [opt] string - default path or file.
+ /// @param enableMultiple [opt] boolean - if True multiple file selection is enabled.
+ ///
+ /// @return If enableMultiple is False (default): returns filename and/or path as a string
+ /// to the location of the highlighted item, if user pressed 'Ok' or a masked item
+ /// was selected. Returns the default value if dialog was canceled.
+ /// If enableMultiple is True: returns tuple of marked filenames as a string
+ /// if user pressed 'Ok' or a masked item was selected. Returns empty tuple if dialog was canceled.\n\n
+ /// If type is 0 or 3 the enableMultiple parameter is ignore
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New option added to browse network and/or local drives.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// fn = dialog.browse(3, 'Kodi', 'files', '', False, False, False, 'special://masterprofile/script_data/Kodi Lyrics')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ browse(...);
+#else
+ Alternative<String, std::vector<String> > browse(int type, const String& heading, const String& shares,
+ const String& mask = emptyString, bool useThumbs = false,
+ bool treatAsFolder = false, const String& defaultt = emptyString,
+ bool enableMultiple = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().browseSingle(type, heading, shares[, mask, useThumbs, treatAsFolder, defaultt]) }
+ /// **Browse single dialog**
+ ///
+ /// The function offer the possibility to select a file by the user of
+ /// the add-on.
+ ///
+ /// It allows all the options that are possible in Kodi itself and offers
+ /// all support file types.
+ ///
+ /// @param type integer - the type of browse dialog.
+ /// | Param | Name |
+ /// |:-----:|:--------------------------------|
+ /// | 0 | ShowAndGetDirectory
+ /// | 1 | ShowAndGetFile
+ /// | 2 | ShowAndGetImage
+ /// | 3 | ShowAndGetWriteableDirectory
+ /// @param heading string or unicode - dialog heading.
+ /// @param shares string or unicode - from [sources.xml](http://kodi.wiki/view/Sources.xml)
+ /// | Param | Name |
+ /// |:--------------:|:---------------------------------------------|
+ /// | "programs" | list program addons
+ /// | "video" | list video sources
+ /// | "music" | list music sources
+ /// | "pictures" | list picture sources
+ /// | "files" | list file sources (added through filemanager)
+ /// | "games" | list game sources
+ /// | "local" | list local drives
+ /// | "" | list local drives and network shares
+ /// @param mask [opt] string or unicode - '|' separated file mask. (i.e. '.jpg|.png')
+ /// @param useThumbs [opt] boolean - if True autoswitch to Thumb view if files exist (default=false).
+ /// @param treatAsFolder [opt] boolean - if True playlists and archives act as folders (default=false).
+ /// @param defaultt [opt] string - default path or file.
+ ///
+ /// @return Returns filename and/or path as a string to the location of the highlighted item,
+ /// if user pressed 'Ok' or a masked item was selected.
+ /// Returns the default value if dialog was canceled.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New option added to browse network and/or local drives.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// fn = dialog.browseSingle(3, 'Kodi', 'files', '', False, False, 'special://masterprofile/script_data/Kodi Lyrics')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ browseSingle(...);
+#else
+ String browseSingle(int type, const String& heading, const String& shares,
+ const String& mask = emptyString, bool useThumbs = false,
+ bool treatAsFolder = false,
+ const String& defaultt = emptyString );
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().browseMultiple(type, heading, shares[, mask, useThumbs, treatAsFolder, defaultt]) }
+ /// **Browser dialog**
+ ///
+ /// The function offer the possibility to select multiple files by the
+ /// user of the add-on.
+ ///
+ /// It allows all the options that are possible in Kodi itself and offers
+ /// all support file types.
+ ///
+ /// @param type integer - the type of browse dialog.
+ /// | Param | Name |
+ /// |:-----:|:--------------------------------|
+ /// | 1 | ShowAndGetFile
+ /// | 2 | ShowAndGetImage
+ /// @param heading string or unicode - dialog heading.
+ /// @param shares string or unicode - from [sources.xml](http://kodi.wiki/view/Sources.xml)
+ /// | Param | Name |
+ /// |:--------------:|:---------------------------------------------|
+ /// | "programs" | list program addons
+ /// | "video" | list video sources
+ /// | "music" | list music sources
+ /// | "pictures" | list picture sources
+ /// | "files" | list file sources (added through filemanager)
+ /// | "games" | list game sources
+ /// | "local" | list local drives
+ /// | "" | list local drives and network shares
+ /// @param mask [opt] string or unicode - '|' separated file mask. (i.e. '.jpg|.png')
+ /// @param useThumbs [opt] boolean - if True autoswitch to Thumb view if files exist (default=false).
+ /// @param treatAsFolder [opt] boolean - if True playlists and archives act as folders (default=false).
+ /// @param defaultt [opt] string - default path or file.
+ /// @return Returns tuple of marked filenames as a string,"
+ /// if user pressed 'Ok' or a masked item was selected. Returns empty tuple if dialog was canceled.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New option added to browse network and/or local drives.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// fn = dialog.browseMultiple(2, 'Kodi', 'files', '', False, False, 'special://masterprofile/script_data/Kodi Lyrics')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ browseMultiple(...);
+#else
+ std::vector<String> browseMultiple(int type, const String& heading, const String& shares,
+ const String& mask = emptyString, bool useThumbs = false,
+ bool treatAsFolder = false,
+ const String& defaultt = emptyString );
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().numeric(type, heading[, defaultt, bHiddenInput]) }
+ /// **Numeric dialog**
+ ///
+ /// The function have to be permitted by the user for the representation
+ /// of a numeric keyboard around an input.
+ ///
+ /// @param type integer - the type of numeric dialog.
+ /// | Param | Name | Format |
+ /// |:-----:|:-------------------------|:-----------------------------|
+ /// | 0 | ShowAndGetNumber | (default format: #)
+ /// | 1 | ShowAndGetDate | (default format: DD/MM/YYYY)
+ /// | 2 | ShowAndGetTime | (default format: HH:MM)
+ /// | 3 | ShowAndGetIPAddress | (default format: #.#.#.#)
+ /// | 4 | ShowAndVerifyNewPassword | (default format: *)
+ /// @param heading string or unicode - dialog heading (will be ignored for type 4).
+ /// @param defaultt [opt] string - default value.
+ /// @param bHiddenInput [opt] bool - mask input (available for type 0).
+ /// @return Returns the entered data as a string.
+ /// Returns the default value if dialog was canceled.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v19 New option added ShowAndVerifyNewPassword.
+ /// @python_v19 Added new option **bHiddenInput**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// d = dialog.numeric(1, 'Enter date of birth')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ numeric(...);
+#else
+ String numeric(int type, const String& heading, const String& defaultt = emptyString, bool bHiddenInput = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().notification(heading, message[, icon, time, sound]) }
+ /// Show a Notification alert.
+ ///
+ /// @param heading string - dialog heading.
+ /// @param message string - dialog message.
+ /// @param icon [opt] string - icon to use. (default xbmcgui.NOTIFICATION_INFO)
+ /// @param time [opt] integer - time in milliseconds (default 5000)
+ /// @param sound [opt] bool - play notification sound (default True)
+ ///
+ /// Builtin Icons:
+ /// - xbmcgui.NOTIFICATION_INFO
+ /// - xbmcgui.NOTIFICATION_WARNING
+ /// - xbmcgui.NOTIFICATION_ERROR
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v13 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// dialog.notification('Movie Trailers', 'Finding Nemo download finished.', xbmcgui.NOTIFICATION_INFO, 5000)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ notification(...);
+#else
+ void notification(const String& heading, const String& message, const String& icon = emptyString, int time = 0, bool sound = true);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().input(heading[, defaultt, type, option, autoclose]) }
+ /// Show an Input dialog.
+ ///
+ /// @param heading string - dialog heading.
+ /// @param defaultt [opt] string - default value. (default=empty string)
+ /// @param type [opt] integer - the type of keyboard dialog. (default=xbmcgui.INPUT_ALPHANUM)
+ /// | Parameter | Format |
+ /// |---------------------------------:|:--------------------------------|
+ /// | <tt>xbmcgui.INPUT_ALPHANUM</tt> | (standard keyboard)
+ /// | <tt>xbmcgui.INPUT_NUMERIC</tt> | (format: #)
+ /// | <tt>xbmcgui.INPUT_DATE</tt> | (format: DD/MM/YYYY)
+ /// | <tt>xbmcgui.INPUT_TIME</tt> | (format: HH:MM)
+ /// | <tt>xbmcgui.INPUT_IPADDRESS</tt> | (format: #.#.#.#)
+ /// | <tt>xbmcgui.INPUT_PASSWORD</tt> | (return md5 hash of input, input is masked)
+ /// @param option [opt] integer - option for the dialog. (see Options below)
+ /// - Password dialog:
+ /// - <tt>xbmcgui.PASSWORD_VERIFY</tt> (verifies an existing (default) md5 hashed password)
+ /// - Alphanum dialog:
+ /// - <tt>xbmcgui.ALPHANUM_HIDE_INPUT</tt> (masks input)
+ /// @param autoclose [opt] integer - milliseconds to autoclose dialog. (default=do not autoclose)
+ ///
+ /// @return Returns the entered data as a string.
+ /// Returns an empty string if dialog was canceled.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v13 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.Dialog()
+ /// d = dialog.input('Enter secret code', type=xbmcgui.INPUT_ALPHANUM, option=xbmcgui.ALPHANUM_HIDE_INPUT)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ input(...);
+#else
+ String input(const String& heading,
+ const String& defaultt = emptyString,
+ int type = INPUT_ALPHANUM,
+ int option = 0,
+ int autoclose = 0);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Dialog
+ /// \python_func{ xbmcgui.Dialog().colorpicker(heading[, colorfile, colorlist, selectedcolor]) }
+ /// Show a color selection dialog.
+ ///
+ /// @param heading string - dialog heading.
+ /// @param selectedcolor [opt] string - hex value of the preselected color.
+ /// @param colorfile [opt] string - xml file containing color definitions.\n
+ /// **XML content style:**
+ /// ~~~~~~xml
+ /// <colors>
+ /// <color name="white">ffffffff</color>
+ /// <color name="grey">7fffffff</color>
+ /// <color name="green">ff00ff7f</color>
+ /// </colors>
+ /// ~~~~~~
+ /// @param colorlist [opt] xbmcgui.ListItems - where label defines the color name and label2 is set to the hex value.
+ ///
+ /// @return Returns the hex value of the selected color as a string.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # colorfile example
+ /// dialog = xbmcgui.Dialog()
+ /// value = dialog.colorpicker('Select color', 'ff00ff00', 'os.path.join(xbmcaddon.Addon().getAddonInfo("path"), "colors.xml")')
+ /// ..
+ /// # colorlist example
+ /// listitems = []
+ /// l1 = xbmcgui.ListItem("red", "FFFF0000")
+ /// l2 = xbmcgui.ListItem("green", "FF00FF00")
+ /// l3 = xbmcgui.ListItem("blue", "FF0000FF")
+ /// listitems.append(l1)
+ /// listitems.append(l2)
+ /// listitems.append(l3)
+ /// dialog = xbmcgui.Dialog()
+ /// value = dialog.colorpicker("Select color", "FF0000FF", colorlist=listitems)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ colorpicker(...);
+#else
+ String colorpicker(
+ const String& heading,
+ const String& selectedcolor = emptyString,
+ const String& colorfile = emptyString,
+ const std::vector<const ListItem*>& colorlist = std::vector<const ListItem*>());
+#endif
+
+ private:
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ // used by both yesno() and yesnocustom()
+ int yesNoCustomInternal(const String& heading,
+ const String& message,
+ const String& nolabel,
+ const String& yeslabel,
+ const String& customlabel,
+ int autoclose,
+ int defaultbutton);
+#endif
+ };
+ //@}
+
+ ///
+ /// \defgroup python_DialogProgress DialogProgress
+ /// \ingroup python_xbmcgui
+ /// @{
+ /// @brief <b>Kodi's progress dialog class (Duh!)</b>
+ ///
+ ///
+ class DialogProgress : public AddonClass
+ {
+ CGUIDialogProgress* dlg = nullptr;
+ bool open = false;
+
+ protected:
+ void deallocating() override;
+
+ public:
+
+ DialogProgress() = default;
+ ~DialogProgress() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgress
+ /// \python_func{ xbmcgui.DialogProgress().create(heading[, message]) }
+ /// Create and show a progress dialog.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param message [opt] string or unicode - message text.
+ ///
+ /// @note Use update() to update lines and progressbar.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v19 Renamed option **line1** to **message**.
+ /// @python_v19 Removed option **line2**.
+ /// @python_v19 Removed option **line3**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pDialog = xbmcgui.DialogProgress()
+ /// pDialog.create('Kodi', 'Initializing script...')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ create(...);
+#else
+ void create(const String& heading, const String& message = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgress
+ /// \python_func{ xbmcgui.DialogProgress().update(percent[, message]) }
+ /// Updates the progress dialog.
+ ///
+ /// @param percent integer - percent complete. (0:100)
+ /// @param message [opt] string or unicode - message text.
+ ///
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v19 Renamed option **line1** to **message**.
+ /// @python_v19 Removed option **line2**.
+ /// @python_v19 Removed option **line3**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pDialog.update(25, 'Importing modules...')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ update(...);
+#else
+ void update(int percent, const String& message = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgress
+ /// \python_func{ xbmcgui.DialogProgress().close() }
+ /// Close the progress dialog.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pDialog.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ close(...);
+#else
+ void close();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgress
+ /// \python_func{ xbmcgui.DialogProgress().iscanceled() }
+ /// Checks progress is canceled.
+ ///
+ /// @return True if the user pressed cancel.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// if (pDialog.iscanceled()): return
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ iscanceled(...);
+#else
+ bool iscanceled();
+#endif
+ };
+
+ //@}
+
+ ///
+ /// \defgroup python_DialogProgressBG DialogProgressBG
+ /// \ingroup python_xbmcgui
+ /// @{
+ /// @brief <b>Kodi's background progress dialog class</b>
+ ///
+ ///
+ class DialogProgressBG : public AddonClass
+ {
+ CGUIDialogExtendedProgressBar* dlg = nullptr;
+ CGUIDialogProgressBarHandle* handle = nullptr;
+ bool open = false;
+
+ protected:
+ void deallocating() override;
+
+ public:
+
+ DialogProgressBG() = default;
+ ~DialogProgressBG() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgressBG
+ /// \python_func{ xbmcgui.DialogProgressBG().create(heading[, message]) }
+ /// Create and show a background progress dialog.
+ ///
+ /// @param heading string or unicode - dialog heading.
+ /// @param message [opt] string or unicode - message text.
+ ///
+ /// @note 'heading' is used for the dialog's id. Use a unique heading.
+ /// Use update() to update heading, message and progressbar.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pDialog = xbmcgui.DialogProgressBG()
+ /// pDialog.create('Movie Trailers', 'Downloading Monsters Inc... .')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ create(...);
+#else
+ void create(const String& heading, const String& message = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgressBG
+ /// \python_func{ xbmcgui.DialogProgressBG().update([percent, heading, message]) }
+ /// Updates the background progress dialog.
+ ///
+ /// @param percent [opt] integer - percent complete. (0:100)
+ /// @param heading [opt] string or unicode - dialog heading.
+ /// @param message [opt] string or unicode - message text.
+ ///
+ /// @note To clear heading or message, you must pass a blank character.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pDialog.update(25, message='Downloading Finding Nemo ...')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ update(...);
+#else
+ void update(int percent = 0, const String& heading = emptyString, const String& message = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgressBG
+ /// \python_func{ xbmcgui.DialogProgressBG().close() }
+ /// Close the background progress dialog
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pDialog.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ close(...);
+#else
+ void close();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_DialogProgressBG
+ /// \python_func{ xbmcgui.DialogProgressBG().isFinished() }
+ /// Checks progress is finished
+ ///
+ /// @return True if the background dialog is active.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// if (pDialog.isFinished()): return
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ isFinished(...);
+#else
+ bool isFinished();
+#endif
+ };
+ //@}
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ SWIG_CONSTANT2(int, DLG_YESNO_NO_BTN, CONTROL_NO_BUTTON);
+ SWIG_CONSTANT2(int, DLG_YESNO_YES_BTN, CONTROL_YES_BUTTON);
+ SWIG_CONSTANT2(int, DLG_YESNO_CUSTOM_BTN, CONTROL_CUSTOM_BUTTON);
+#endif
+} // namespace xbmcgui
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/Dictionary.h b/xbmc/interfaces/legacy/Dictionary.h
new file mode 100644
index 0000000..65a4db8
--- /dev/null
+++ b/xbmc/interfaces/legacy/Dictionary.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonString.h"
+
+#include <map>
+
+namespace XBMCAddon
+{
+ // This is a hack in order to handle int's as strings. The correct fix for
+ // this is to get rid of Alternative all together and make the codegenerator
+ // finally handle overloading correctly.
+ typedef String StringOrInt;
+
+ /**
+ * This is a bit of a hack for dynamically typed languages. In some
+ * cases python addon api calls handle dictionaries with variable
+ * value types. In this case we coerce all of these types into
+ * strings and then convert them back in the api. Yes, this is messy
+ * and maybe we should use the CVariant here. But for now the
+ * native api handles these calls by converting the string to the
+ * appropriate types.
+ */
+ template<class T> class Dictionary : public std::map<String,T> {};
+
+ typedef Dictionary<StringOrInt> Properties;
+}
diff --git a/xbmc/interfaces/legacy/DrmCryptoSession.cpp b/xbmc/interfaces/legacy/DrmCryptoSession.cpp
new file mode 100644
index 0000000..26f69be
--- /dev/null
+++ b/xbmc/interfaces/legacy/DrmCryptoSession.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 "DrmCryptoSession.h"
+
+#include "media/drm/CryptoSession.h"
+
+using namespace XbmcCommons;
+
+namespace XBMCAddon
+{
+ namespace xbmcdrm
+ {
+ CryptoSession::CryptoSession(const String& UUID,
+ const String& cipherAlgorithm,
+ const String& macAlgorithm)
+ : m_cryptoSession(DRM::CCryptoSession::GetCryptoSession(UUID, cipherAlgorithm, macAlgorithm))
+ {
+ }
+
+ CryptoSession::~CryptoSession()
+ {
+ delete m_cryptoSession;
+ }
+
+ Buffer CryptoSession::GetKeyRequest(const Buffer &init, const String &mimeType, bool offlineKey, const std::map<String, String> &parameters)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->GetKeyRequest(init, mimeType, offlineKey, parameters);
+
+ return Buffer();
+ }
+
+ String CryptoSession::GetPropertyString(const String &name)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->GetPropertyString(name);
+
+ return "";
+ }
+
+ String CryptoSession::ProvideKeyResponse(const Buffer &response)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->ProvideKeyResponse(response);
+
+ return "";
+ }
+
+ void CryptoSession::RemoveKeys()
+ {
+ if (m_cryptoSession)
+ m_cryptoSession->RemoveKeys();
+ }
+
+ void CryptoSession::RestoreKeys(const String& keySetId)
+ {
+ if (m_cryptoSession)
+ m_cryptoSession->RestoreKeys(keySetId);
+ }
+
+ void CryptoSession::SetPropertyString(const String &name, const String &value)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->SetPropertyString(name, value);
+ }
+
+ /*******************Crypto section *****************/
+
+ Buffer CryptoSession::Decrypt(const Buffer &cipherKeyId, const Buffer &input, const Buffer &iv)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->Decrypt(cipherKeyId, input, iv);
+
+ return Buffer();
+ }
+
+ Buffer CryptoSession::Encrypt(const Buffer &cipherKeyId, const Buffer &input, const Buffer &iv)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->Encrypt(cipherKeyId, input, iv);
+
+ return Buffer();
+ }
+
+ Buffer CryptoSession::Sign(const Buffer &macKeyId, const Buffer &message)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->Sign(macKeyId, message);
+
+ return Buffer();
+ }
+
+ bool CryptoSession::Verify(const Buffer &macKeyId, const Buffer &message, const Buffer &signature)
+ {
+ if (m_cryptoSession)
+ return m_cryptoSession->Verify(macKeyId, message, signature);
+
+ return false;
+ }
+
+ } //namespace xbmcdrm
+} //namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/DrmCryptoSession.h b/xbmc/interfaces/legacy/DrmCryptoSession.h
new file mode 100644
index 0000000..816bec8
--- /dev/null
+++ b/xbmc/interfaces/legacy/DrmCryptoSession.h
@@ -0,0 +1,342 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "Exception.h"
+#include "commons/Buffer.h"
+
+#include <map>
+#include <vector>
+
+namespace DRM
+{
+ class CCryptoSession;
+}
+
+namespace XBMCAddon
+{
+
+ typedef std::vector<char> charVec;
+
+ namespace xbmcdrm
+ {
+
+ XBMCCOMMONS_STANDARD_EXCEPTION(DRMException);
+
+ //
+ /// \defgroup python_xbmcdrm Library - xbmcdrm
+ ///@{
+ /// @brief **Kodi's %DRM class.**
+ ///
+ /// Offers classes and functions that allow a developer to work with
+ /// DRM-protected contents like Widevine.
+ ///
+ /// This type of functionality is closely related to the type of %DRM
+ /// used and the service to be implemented.
+ ///
+ /// Using the \ref xbmcdrm_CryptoSession "CryptoSession" constructor allow you
+ /// to have access to a %DRM session.
+ /// With a %DRM session you can read and write the %DRM properties
+ /// \ref xbmcdrm_GetPropertyString "GetPropertyString",
+ /// \ref xbmcdrm_SetPropertyString "SetPropertyString"
+ /// and establish session keys with
+ /// \ref xbmcdrm_GetKeyRequest "GetKeyRequest" and
+ /// \ref xbmcdrm_ProvideKeyResponse "ProvideKeyResponse",
+ /// or resume previous session keys with
+ /// \ref xbmcdrm_RestoreKeys "RestoreKeys".
+ ///
+ /// When the session keys are established you can use these methods
+ /// to perform various operations:
+ /// \ref xbmcdrm_Encrypt "Encrypt" /
+ /// \ref xbmcdrm_Decrypt "Decrypt" for data encryption / decryption,
+ /// \ref xbmcdrm_Sign "Sign" /
+ /// \ref xbmcdrm_Verify "Verify" for make or verify data-signature.
+ /// Useful for example to implement encrypted communication between
+ /// a client and the server.
+ ///
+ /// An example where such functionality is useful is the Message
+ /// Security Layer (MSL) transmission protocol used in some VOD applications.
+ /// This protocol (or rather framework) is used to increase the level of security
+ /// in the exchange of messages (such as licences, manifests or other data),
+ /// which defines a security extension / layer on top of the HTTP protocol.
+ ///
+ ///--------------------------------------------------------------------------
+ /// Constructor for %DRM crypto session
+ ///
+ /// \anchor xbmcdrm_CryptoSession
+ /// \python_class{ xbmcdrm.CryptoSession(UUID, cipherAlgorithm, macAlgorithm) }
+ ///
+ /// @param UUID string - 16 byte UUID of the %DRM system to use
+ /// @param cipherAlgorithm string - Algorithm used for encryption / decryption ciphers
+ /// @param macAlgorithm string - Algorithm used for sign / verify
+ ///
+ /// @throws RuntimeException If the session can not be established
+ ///
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New class added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// uuid_widevine = 'edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'
+ /// crypto_session = xbmcdrm.CryptoSession(uuid_widevine, 'AES/CBC/NoPadding', 'HmacSHA256')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ class CryptoSession : public AddonClass
+ {
+ DRM::CCryptoSession* m_cryptoSession;
+ public:
+ CryptoSession(const String& UUID, const String& cipherAlgorithm, const String& macAlgorithm);
+ ~CryptoSession() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ GetKeyRequest(init, mimeType, offlineKey, optionalParameters) }
+ /// Generate a key request
+ ///
+ /// Generate a key request, used for request/response exchange between the app
+ /// and a license server to obtain or release keys used to decrypt encrypted content.
+ /// After the app has received the key request response from the license server,
+ /// it should deliver to the response to the %DRM instance using
+ /// the method \ref xbmcdrm_ProvideKeyResponse "ProvideKeyResponse", to activate the keys.
+ // \anchor xbmcdrm_GetKeyRequest
+ ///
+ /// @param init byte - Initialization bytes container-specific data,
+ /// its meaning is interpreted based on the mime type provided
+ /// in the mimeType parameter. It could contain, for example,
+ /// the content ID, key ID or other data required in generating
+ /// the key request.
+ /// @param mimeType string - Type of media which is exchanged
+ /// (e.g. "application/xml", "video/mp4")
+ /// @param offlineKey bool - Specifies the type of the request.
+ /// The request may be to acquire keys for Streaming or Offline content
+ /// @param optionalParameters [opt] map - Will be included in the key request message
+ /// to allow a client application to provide additional
+ /// message parameters to the server
+ ///
+ /// @return byte - The opaque key request data (challenge) which is send to key server
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 With python 3 the init param must be a bytearray instead of byte.
+ ///
+ GetKeyRequest(...);
+#else
+ XbmcCommons::Buffer GetKeyRequest(const XbmcCommons::Buffer &init, const String &mimeType, bool offlineKey, const std::map<String, String> &optionalParameters);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ GetPropertyString(name) }
+ /// Request a system specific property value of the %DRM system.
+ ///
+ ///\anchor xbmcdrm_GetPropertyString
+ /// @param Name string - Name of the property to query
+ ///
+ /// @return Value of the requested property
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ GetPropertyString(...);
+#else
+ String GetPropertyString(const String &name);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ ProvideKeyResponse(response) }
+ /// Provide a key response
+ ///
+ /// \anchor xbmcdrm_ProvideKeyResponse
+ /// When a key response is received from the license server,
+ /// must be sent to the %DRM instance by using provideKeyResponse.
+ /// See also \ref xbmcdrm_GetKeyRequest "GetKeyRequest".
+ ///
+ /// @param response byte - Key data returned from the license server
+ ///
+ /// @return A keySetId if the response is for an offline key requests which
+ /// can be used later with restoreKeys,
+ /// else return empty for streaming key requests.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 With python 3 the response argument must be a bytearray instead of byte.
+ ///
+ ProvideKeyResponse(...);
+#else
+ String ProvideKeyResponse(const XbmcCommons::Buffer &response);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ RemoveKeys() }
+ /// Removes all keys currently loaded in a session.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ RemoveKeys(...);
+#else
+ void RemoveKeys();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ RestoreKeys(keySetId) }
+ /// Restores session keys stored during previous
+ /// \ref xbmcdrm_ProvideKeyResponse "ProvideKeyResponse" call.
+ /// \anchor xbmcdrm_RestoreKeys
+ ///
+ /// @param keySetId string - Identifies the saved key set to restore.
+ /// This value must never be null.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ RestoreKeys(...);
+#else
+ void RestoreKeys(const String& keySetId);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ SetPropertyString(name, value) }
+ /// Set a system specific property value in the %DRM system.
+ ///
+ /// \anchor xbmcdrm_SetPropertyString
+ ///
+ /// @param name string - Name of the property. This value must never be null.
+ /// @param value string - Value of the property to set. This value must never be null.
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ SetPropertyString(...);
+#else
+ void SetPropertyString(const String &name, const String &value);
+#endif
+
+/*******************Crypto section *****************/
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ Decrypt(cipherKeyId, input, iv) }
+ /// Decrypt an encrypted data by using session keys.
+ ///
+ /// \anchor xbmcdrm_Decrypt
+ ///
+ /// @param cipherKeyId byte - Encryption key id (provided from a service handshake)
+ /// @param input byte - Cipher text to decrypt
+ /// @param iv byte - Initialization vector of cipher text
+ ///
+ /// @return Decrypted input data
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 With python 3 all arguments need to be of type bytearray instead of byte.
+ ///
+ Decrypt(...);
+#else
+ XbmcCommons::Buffer Decrypt(const XbmcCommons::Buffer &cipherKeyId, const XbmcCommons::Buffer &input, const XbmcCommons::Buffer &iv);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ Encrypt(cipherKeyId, input, iv) }
+ /// Encrypt data by using session keys.
+ ///
+ /// \anchor xbmcdrm_Encrypt
+ ///
+ /// @param cipherKeyId byte - Encryption key id (provided from a service handshake)
+ /// @param input byte - Encrypted text
+ /// @param iv byte - Initialization vector of encrypted text
+ ///
+ /// @return byte - Encrypted input data
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 With python 3 all arguments need to be of type bytearray instead of byte.
+ ///
+ Encrypt(...);
+#else
+ XbmcCommons::Buffer Encrypt(const XbmcCommons::Buffer &cipherKeyId, const XbmcCommons::Buffer &input, const XbmcCommons::Buffer &iv);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ Sign(macKeyId, message) }
+ /// Generate a %DRM encrypted signature for a text message.
+ ///
+ /// \anchor xbmcdrm_Sign
+ ///
+ /// @param macKeyId byte - HMAC key id (provided from a service handshake)
+ /// @param message byte - Message text on which to base the signature
+ ///
+ /// @return byte - Signature
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 With python 3 all arguments need to be of type bytearray instead of byte.
+ ///
+ Sign(...);
+#else
+ XbmcCommons::Buffer Sign(const XbmcCommons::Buffer &macKeyId, const XbmcCommons::Buffer &message);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcdrm
+ /// @brief \python_func{ Verify(macKeyId, message, signature) }
+ /// Verify the validity of a %DRM signature of a text message.
+ ///
+ /// \anchor xbmcdrm_Verify
+ ///
+ /// @param macKeyId byte - HMAC key id (provided from a service handshake)
+ /// @param message byte - Message text on which the signature is based
+ /// @param signature byte - The signature to verify
+ ///
+ /// @return true when the signature is valid
+ ///
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 With python 3 for all arguments is needed to pass bytearray instead of byte.
+ ///
+ Verify(...);
+#else
+ bool Verify(const XbmcCommons::Buffer &macKeyId, const XbmcCommons::Buffer &message, const XbmcCommons::Buffer &signature);
+#endif
+
+ };
+ ///@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/Exception.h b/xbmc/interfaces/legacy/Exception.h
new file mode 100644
index 0000000..61a32be
--- /dev/null
+++ b/xbmc/interfaces/legacy/Exception.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "commons/Exception.h"
+#include "utils/log.h"
+
+#ifndef SWIG
+namespace XBMCAddon
+{
+ XBMCCOMMONS_STANDARD_EXCEPTION(WrongTypeException);
+
+ /**
+ * UnimplementedException Can be used in places like the
+ * Control hierarchy where the
+ * requirements of dynamic language usage force us to add
+ * unimplemented methods to a class hierarchy. See the
+ * detailed explanation on the class Control for more.
+ */
+ class UnimplementedException : public XbmcCommons::Exception
+ {
+ public:
+ inline UnimplementedException(const UnimplementedException& other) = default;
+ inline UnimplementedException(const char* classname, const char* methodname) :
+ Exception("UnimplementedException")
+ { SetMessage("Unimplemented method: %s::%s(...)", classname, methodname); }
+ };
+
+ /**
+ * This is what callback exceptions from the scripting language
+ * are translated to.
+ */
+ class UnhandledException : public XbmcCommons::Exception
+ {
+ public:
+ inline UnhandledException(const UnhandledException& other) = default;
+ inline UnhandledException(const char* _message,...) : Exception("UnhandledException") { XBMCCOMMONS_COPYVARARGS(_message); }
+ };
+}
+#endif
+
+/**
+ * These macros allow the easy declaration (and definition) of parent
+ * class virtual methods that are not implemented until the child class.
+ * This is to support the idosyncracies of dynamically typed scripting
+ * languages. See the comment in AddonControl.h for more details.
+ */
+#define THROW_UNIMP(classname) throw UnimplementedException(classname, __FUNCTION__)
+
diff --git a/xbmc/interfaces/legacy/File.cpp b/xbmc/interfaces/legacy/File.cpp
new file mode 100644
index 0000000..4c0ca68
--- /dev/null
+++ b/xbmc/interfaces/legacy/File.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "File.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcvfs
+ {
+ XbmcCommons::Buffer File::readBytes(unsigned long numBytes)
+ {
+ DelayedCallGuard dg(languageHook);
+ int64_t size = file->GetLength();
+ if ((!numBytes || (((int64_t)numBytes) > size)) && (size >= 0))
+ numBytes = (unsigned long) size;
+
+
+ XbmcCommons::Buffer ret(numBytes);
+
+ if (numBytes == 0)
+ return ret;
+
+ while(ret.remaining() > 0)
+ {
+ ssize_t bytesRead = file->Read(ret.curPosition(), ret.remaining());
+ if (bytesRead <= 0) // we consider this a failure or a EOF, can't tell which,
+ { // return whatever we have already.
+ ret.flip();
+ return ret;
+ }
+ ret.forward(bytesRead);
+ }
+ ret.flip();
+ return ret;
+ }
+
+ bool File::write(XbmcCommons::Buffer& buffer)
+ {
+ DelayedCallGuard dg(languageHook);
+ while (buffer.remaining() > 0)
+ {
+ ssize_t bytesWritten = file->Write( buffer.curPosition(), buffer.remaining());
+ if (bytesWritten == 0) // this could be a failure (see HDFile, and XFileUtils) or
+ // it could mean something else when a negative number means an error
+ // (see CCurlFile). There is no consistency so we can only assume we're
+ // done when we get a 0.
+ return false;
+ else if (bytesWritten < 0) // But, if we get something less than zero, we KNOW it's an error.
+ return false;
+ buffer.forward(bytesWritten);// Otherwise, we advance the buffer by the amount written.
+ }
+ return true;
+ }
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/File.h b/xbmc/interfaces/legacy/File.h
new file mode 100644
index 0000000..01a757a
--- /dev/null
+++ b/xbmc/interfaces/legacy/File.h
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "AddonString.h"
+#include "LanguageHook.h"
+#include "commons/Buffer.h"
+#include "filesystem/File.h"
+
+#include <algorithm>
+
+namespace XBMCAddon
+{
+
+ namespace xbmcvfs
+ {
+
+ //
+ /// \defgroup python_file File
+ /// \ingroup python_xbmcvfs
+ /// @{
+ /// @brief <b>Kodi's file class.</b>
+ ///
+ /// \python_class{ xbmcvfs.File(filepath, [mode]) }
+ ///
+ /// @param filepath string Selected file path
+ /// @param mode [opt] string Additional mode options (if no mode is supplied, the default is Open for Read).
+ /// | Mode | Description |
+ /// |:------:|:--------------------------------|
+ /// | w | Open for write |
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ /// @python_v19 Added context manager support
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file, 'w')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file, 'w') as f:
+ /// ..
+ /// ..
+ /// ~~~~~~~~~~~~~
+ //
+ class File : public AddonClass
+ {
+ XFILE::CFile* file;
+ public:
+ inline File(const String& filepath, const char* mode = NULL) : file(new XFILE::CFile())
+ {
+ DelayedCallGuard dg(languageHook);
+ if (mode && strncmp(mode, "w", 1) == 0)
+ file->OpenForWrite(filepath,true);
+ else
+ file->Open(filepath, XFILE::READ_NO_CACHE);
+ }
+
+ inline ~File() override { delete file; }
+
+#if !defined(DOXYGEN_SHOULD_USE_THIS)
+ inline File* __enter__() { return this; }
+ inline void __exit__() { close(); }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ read([bytes]) }
+ /// Read file parts as string.
+ ///
+ /// @param bytes [opt] How many bytes to read - if not
+ /// set it will read the whole file
+ /// @return string
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// b = f.read()
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file) as file:
+ /// b = f.read()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ read(...);
+#else
+ inline String read(unsigned long numBytes = 0)
+ {
+ XbmcCommons::Buffer b = readBytes(numBytes);
+ return b.getString(numBytes == 0 ? b.remaining() : std::min((unsigned long)b.remaining(),numBytes));
+ }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ readBytes(numbytes) }
+ /// Read bytes from file.
+ ///
+ /// @param numbytes How many bytes to read [opt]- if not set
+ /// it will read the whole file
+ /// @return bytearray
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// b = f.readBytes()
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file) as f:
+ /// b = f.readBytes()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ readBytes(...);
+#else
+ XbmcCommons::Buffer readBytes(unsigned long numBytes = 0);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ write(buffer) }
+ /// To write given data in file.
+ ///
+ /// @param buffer Buffer to write to file
+ /// @return True on success.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file, 'w')
+ /// result = f.write(buffer)
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file, 'w') as f:
+ /// result = f.write(buffer)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ write(...);
+#else
+ bool write(XbmcCommons::Buffer& buffer);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ size() }
+ /// Get the file size.
+ ///
+ /// @return The file size
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// s = f.size()
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file) as f:
+ /// s = f.size()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ size();
+#else
+ inline long long size() { DelayedCallGuard dg(languageHook); return file->GetLength(); }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ seek(seekBytes, iWhence) }
+ /// Seek to position in file.
+ ///
+ /// @param seekBytes position in the file
+ /// @param iWhence [opt] where in a file to seek from[0 beginning,
+ /// 1 current , 2 end position]
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 Function changed. param **iWhence** is now optional.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// result = f.seek(8129, 0)
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file) as f:
+ /// result = f.seek(8129, 0)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ seek(...);
+#else
+ inline long long seek(long long seekBytes, int iWhence = SEEK_SET) { DelayedCallGuard dg(languageHook); return file->Seek(seekBytes,iWhence); }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ tell() }
+ /// Get the current position in the file.
+ ///
+ /// @return The file position
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// s = f.tell()
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file) as f:
+ /// s = f.tell()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ tell();
+#else
+ inline long long tell() { DelayedCallGuard dg(languageHook); return file->GetPosition(); }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_file
+ /// @brief \python_func{ close() }
+ /// Close opened file.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// f = xbmcvfs.File(file)
+ /// f.close()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// **Example (v19 and up):**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// with xbmcvfs.File(file) as f:
+ /// ..
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ close();
+#else
+ inline void close() { DelayedCallGuard dg(languageHook); file->Close(); }
+#endif
+
+#ifndef SWIG
+ inline const XFILE::CFile* getFile() const { return file; }
+#endif
+
+ };
+ //@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/InfoTagGame.cpp b/xbmc/interfaces/legacy/InfoTagGame.cpp
new file mode 100644
index 0000000..697247b
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagGame.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 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 "InfoTagGame.h"
+
+#include "AddonUtils.h"
+#include "games/tags/GameInfoTag.h"
+
+using namespace KODI::GAME;
+using namespace XBMCAddonUtils;
+
+namespace XBMCAddon
+{
+namespace xbmc
+{
+
+InfoTagGame::InfoTagGame(bool offscreen /* = false */)
+ : infoTag(new CGameInfoTag), offscreen(offscreen), owned(true)
+{
+}
+
+InfoTagGame::InfoTagGame(const CGameInfoTag* tag)
+ : infoTag(new CGameInfoTag(*tag)), offscreen(true), owned(true)
+{
+}
+
+InfoTagGame::InfoTagGame(CGameInfoTag* tag, bool offscreen /* = false */)
+ : infoTag(tag), offscreen(offscreen), owned(false)
+{
+}
+
+InfoTagGame::~InfoTagGame()
+{
+ if (owned)
+ delete infoTag;
+}
+
+String InfoTagGame::getTitle()
+{
+ return infoTag->GetTitle();
+}
+
+String InfoTagGame::getPlatform()
+{
+ return infoTag->GetPlatform();
+}
+
+std::vector<String> InfoTagGame::getGenres()
+{
+ return infoTag->GetGenres();
+}
+
+String InfoTagGame::getPublisher()
+{
+ return infoTag->GetPublisher();
+}
+
+String InfoTagGame::getDeveloper()
+{
+ return infoTag->GetDeveloper();
+}
+
+String InfoTagGame::getOverview()
+{
+ return infoTag->GetOverview();
+}
+
+unsigned int InfoTagGame::getYear()
+{
+ return infoTag->GetYear();
+}
+
+String InfoTagGame::getGameClient()
+{
+ return infoTag->GetGameClient();
+}
+
+void InfoTagGame::setTitle(const String& title)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTitleRaw(infoTag, title);
+}
+
+void InfoTagGame::setPlatform(const String& platform)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPlatformRaw(infoTag, platform);
+}
+
+void InfoTagGame::setGenres(const std::vector<String>& genres)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setGenresRaw(infoTag, genres);
+}
+
+void InfoTagGame::setPublisher(const String& publisher)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPublisherRaw(infoTag, publisher);
+}
+
+void InfoTagGame::setDeveloper(const String& developer)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDeveloperRaw(infoTag, developer);
+}
+
+void InfoTagGame::setOverview(const String& overview)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setOverviewRaw(infoTag, overview);
+}
+
+void InfoTagGame::setYear(unsigned int year)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setYearRaw(infoTag, year);
+}
+
+void InfoTagGame::setGameClient(const String& gameClient)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setGameClientRaw(infoTag, gameClient);
+}
+
+void InfoTagGame::setTitleRaw(KODI::GAME::CGameInfoTag* infoTag, const String& title)
+{
+ infoTag->SetTitle(title);
+}
+
+void InfoTagGame::setPlatformRaw(KODI::GAME::CGameInfoTag* infoTag, const String& platform)
+{
+ infoTag->SetPlatform(platform);
+}
+
+void InfoTagGame::setGenresRaw(KODI::GAME::CGameInfoTag* infoTag, const std::vector<String>& genres)
+{
+ infoTag->SetGenres(genres);
+}
+
+void InfoTagGame::setPublisherRaw(KODI::GAME::CGameInfoTag* infoTag, const String& publisher)
+{
+ infoTag->SetPublisher(publisher);
+}
+
+void InfoTagGame::setDeveloperRaw(KODI::GAME::CGameInfoTag* infoTag, const String& developer)
+{
+ infoTag->SetDeveloper(developer);
+}
+
+void InfoTagGame::setOverviewRaw(KODI::GAME::CGameInfoTag* infoTag, const String& overview)
+{
+ infoTag->SetOverview(overview);
+}
+
+void InfoTagGame::setYearRaw(KODI::GAME::CGameInfoTag* infoTag, unsigned int year)
+{
+ infoTag->SetYear(year);
+}
+
+void InfoTagGame::setGameClientRaw(KODI::GAME::CGameInfoTag* infoTag, const String& gameClient)
+{
+ infoTag->SetGameClient(gameClient);
+}
+
+} // namespace xbmc
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/InfoTagGame.h b/xbmc/interfaces/legacy/InfoTagGame.h
new file mode 100644
index 0000000..a6161b4
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagGame.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2021 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 "AddonClass.h"
+
+namespace KODI
+{
+namespace GAME
+{
+class CGameInfoTag;
+}
+} // namespace KODI
+
+namespace XBMCAddon
+{
+namespace xbmc
+{
+///
+/// \defgroup python_InfoTagGame InfoTagGame
+/// \ingroup python_xbmc
+/// @{
+/// @brief **Kodi's game info tag class.**
+///
+/// \python_class{ InfoTagGame() }
+///
+/// Access and / or modify the game metadata of a ListItem.
+///
+///-------------------------------------------------------------------------
+/// @python_v20 New class added.
+///
+/// **Example:**
+/// ~~~~~~~~~~~~~{.py}
+/// ...
+/// tag = item.getGameInfoTag()
+///
+/// title = tag.getTitle()
+/// tag.setDeveloper('John Doe')
+/// ...
+/// ~~~~~~~~~~~~~
+///
+class InfoTagGame : public AddonClass
+{
+private:
+ KODI::GAME::CGameInfoTag* infoTag;
+ bool offscreen;
+ bool owned;
+
+public:
+#ifndef SWIG
+ explicit InfoTagGame(const KODI::GAME::CGameInfoTag* tag);
+ explicit InfoTagGame(KODI::GAME::CGameInfoTag* tag, bool offscreen = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ xbmc.InfoTagGame([offscreen]) }
+ /// Create a game info tag.
+ ///
+ /// @param offscreen [opt] bool (default `False`) - if GUI based locks should be
+ /// avoided. Most of the times listitems are created
+ /// offscreen and added later to a container
+ /// for display (e.g. plugins) or they are not
+ /// even displayed (e.g. python scrapers).
+ /// In such cases, there is no need to lock the
+ /// GUI when creating the items (increasing your addon
+ /// performance).
+ /// Note however, that if you are creating listitems
+ /// and managing the container itself (e.g using
+ /// WindowXML or WindowXMLDialog classes) subsquent
+ /// modifications to the item will require locking.
+ /// Thus, in such cases, use the default value (`False`).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// gameinfo = xbmc.InfoTagGame(offscreen=False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ InfoTagGame(...);
+#else
+ explicit InfoTagGame(bool offscreen = false);
+#endif
+ ~InfoTagGame() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getTitle() }
+ /// Gets the title of the game.
+ ///
+ /// @return [string] title
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getTitle();
+#else
+ String getTitle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getPlatform() }
+ /// Gets the platform on which the game is run.
+ ///
+ /// @return [string] platform
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getPlatform();
+#else
+ String getPlatform();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getGenres() }
+ /// Gets the genres of the game.
+ ///
+ /// @return [list] genres
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getGenres();
+#else
+ std::vector<String> getGenres();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getPublisher() }
+ /// Gets the publisher of the game.
+ ///
+ /// @return [string] publisher
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getPublisher();
+#else
+ String getPublisher();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getDeveloper() }
+ /// Gets the developer of the game.
+ ///
+ /// @return [string] developer
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getDeveloper();
+#else
+ String getDeveloper();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getOverview() }
+ /// Gets the overview of the game.
+ ///
+ /// @return [string] overview
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getOverview();
+#else
+ String getOverview();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getYear() }
+ /// Gets the year in which the game was published.
+ ///
+ /// @return [integer] year
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getYear();
+#else
+ unsigned int getYear();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ getGameClient() }
+ /// Gets the add-on ID of the game client executing the game.
+ ///
+ /// @return [string] game client
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getGameClient();
+#else
+ String getGameClient();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setTitle(title) }
+ /// Sets the title of the game.
+ ///
+ /// @param title string - title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTitle(...);
+#else
+ void setTitle(const String& title);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setPlatform(platform) }
+ /// Sets the platform on which the game is run.
+ ///
+ /// @param platform string - platform.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPlatform(...);
+#else
+ void setPlatform(const String& platform);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setGenres(genres) }
+ /// Sets the genres of the game.
+ ///
+ /// @param genres list - genres.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setGenres(...);
+#else
+ void setGenres(const std::vector<String>& genres);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setPublisher(publisher) }
+ /// Sets the publisher of the game.
+ ///
+ /// @param publisher string - publisher.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPublisher(...);
+#else
+ void setPublisher(const String& publisher);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setDeveloper(developer) }
+ /// Sets the developer of the game.
+ ///
+ /// @param developer string - title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDeveloper(...);
+#else
+ void setDeveloper(const String& developer);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setOverview(overview) }
+ /// Sets the overview of the game.
+ ///
+ /// @param overview string - overview.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setOverview(...);
+#else
+ void setOverview(const String& overview);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setYear(year) }
+ /// Sets the year in which the game was published.
+ ///
+ /// @param year integer - year.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setYear(...);
+#else
+ void setYear(unsigned int year);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagGame
+ /// @brief \python_func{ setGameClient(gameClient) }
+ /// Sets the add-on ID of the game client executing the game.
+ ///
+ /// @param gameClient string - game client.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setGameClient(...);
+#else
+ void setGameClient(const String& gameClient);
+#endif
+
+#ifndef SWIG
+ static void setTitleRaw(KODI::GAME::CGameInfoTag* infoTag, const String& title);
+ static void setPlatformRaw(KODI::GAME::CGameInfoTag* infoTag, const String& platform);
+ static void setGenresRaw(KODI::GAME::CGameInfoTag* infoTag, const std::vector<String>& genres);
+ static void setPublisherRaw(KODI::GAME::CGameInfoTag* infoTag, const String& publisher);
+ static void setDeveloperRaw(KODI::GAME::CGameInfoTag* infoTag, const String& developer);
+ static void setOverviewRaw(KODI::GAME::CGameInfoTag* infoTag, const String& overview);
+ static void setYearRaw(KODI::GAME::CGameInfoTag* infoTag, unsigned int year);
+ static void setGameClientRaw(KODI::GAME::CGameInfoTag* infoTag, const String& gameClient);
+#endif
+};
+
+} // namespace xbmc
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/InfoTagMusic.cpp b/xbmc/interfaces/legacy/InfoTagMusic.cpp
new file mode 100644
index 0000000..3baf7d5
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagMusic.cpp
@@ -0,0 +1,468 @@
+/*
+ * 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 "InfoTagMusic.h"
+
+#include "AddonUtils.h"
+#include "ServiceBroker.h"
+#include "music/tags/MusicInfoTag.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ InfoTagMusic::InfoTagMusic(bool offscreen /* = false */)
+ : infoTag(new MUSIC_INFO::CMusicInfoTag()), offscreen(offscreen), owned(true)
+ {
+ }
+
+ InfoTagMusic::InfoTagMusic(const MUSIC_INFO::CMusicInfoTag* tag) : InfoTagMusic(true)
+ {
+ *infoTag = *tag;
+ }
+
+ InfoTagMusic::InfoTagMusic(MUSIC_INFO::CMusicInfoTag* tag, bool offscreen /* = false */)
+ : infoTag(tag), offscreen(offscreen), owned(false)
+ {
+ }
+
+ InfoTagMusic::~InfoTagMusic()
+ {
+ if (owned)
+ delete infoTag;
+ }
+
+ int InfoTagMusic::getDbId()
+ {
+ return infoTag->GetDatabaseId();
+ }
+
+ String InfoTagMusic::getURL()
+ {
+ return infoTag->GetURL();
+ }
+
+ String InfoTagMusic::getTitle()
+ {
+ return infoTag->GetTitle();
+ }
+
+ String InfoTagMusic::getMediaType()
+ {
+ return infoTag->GetType();
+ }
+
+ String InfoTagMusic::getArtist()
+ {
+ return infoTag->GetArtistString();
+ }
+
+ String InfoTagMusic::getAlbumArtist()
+ {
+ return infoTag->GetAlbumArtistString();
+ }
+
+ String InfoTagMusic::getAlbum()
+ {
+ return infoTag->GetAlbum();
+ }
+
+ String InfoTagMusic::getGenre()
+ {
+ return StringUtils::Join(infoTag->GetGenre(), CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator);
+ }
+
+ std::vector<String> InfoTagMusic::getGenres()
+ {
+ return infoTag->GetGenre();
+ }
+
+ int InfoTagMusic::getDuration()
+ {
+ return infoTag->GetDuration();
+ }
+
+ int InfoTagMusic::getYear()
+ {
+ return infoTag->GetYear();
+ }
+
+ int InfoTagMusic::getRating()
+ {
+ return infoTag->GetRating();
+ }
+
+ int InfoTagMusic::getUserRating()
+ {
+ return infoTag->GetUserrating();
+ }
+
+ int InfoTagMusic::getTrack()
+ {
+ return infoTag->GetTrackNumber();
+ }
+
+ int InfoTagMusic::getDisc()
+ {
+ return infoTag->GetDiscNumber();
+ }
+
+ String InfoTagMusic::getReleaseDate()
+ {
+ return infoTag->GetReleaseDate();
+ }
+
+ int InfoTagMusic::getListeners()
+ {
+ return infoTag->GetListeners();
+ }
+
+ int InfoTagMusic::getPlayCount()
+ {
+ return infoTag->GetPlayCount();
+ }
+
+ String InfoTagMusic::getLastPlayed()
+ {
+ CLog::Log(LOGWARNING, "InfoTagMusic.getLastPlayed() is deprecated and might be removed in "
+ "future Kodi versions. Please use InfoTagMusic.getLastPlayedAsW3C().");
+
+ return infoTag->GetLastPlayed().GetAsLocalizedDate();
+ }
+
+ String InfoTagMusic::getLastPlayedAsW3C()
+ {
+ return infoTag->GetLastPlayed().GetAsW3CDateTime();
+ }
+
+ String InfoTagMusic::getComment()
+ {
+ return infoTag->GetComment();
+ }
+
+ String InfoTagMusic::getLyrics()
+ {
+ return infoTag->GetLyrics();
+ }
+
+ String InfoTagMusic::getMusicBrainzTrackID()
+ {
+ return infoTag->GetMusicBrainzTrackID();
+ }
+
+ std::vector<String> InfoTagMusic::getMusicBrainzArtistID()
+ {
+ return infoTag->GetMusicBrainzArtistID();
+ }
+
+ String InfoTagMusic::getMusicBrainzAlbumID()
+ {
+ return infoTag->GetMusicBrainzAlbumID();
+ }
+
+ String InfoTagMusic::getMusicBrainzReleaseGroupID()
+ {
+ return infoTag->GetMusicBrainzReleaseGroupID();
+ }
+
+ std::vector<String> InfoTagMusic::getMusicBrainzAlbumArtistID()
+ {
+ return infoTag->GetMusicBrainzAlbumArtistID();
+ }
+
+ void InfoTagMusic::setDbId(int dbId, const String& type)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDbIdRaw(infoTag, dbId, type);
+ }
+
+ void InfoTagMusic::setURL(const String& url)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setURLRaw(infoTag, url);
+ }
+
+ void InfoTagMusic::setMediaType(const String& mediaType)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMediaTypeRaw(infoTag, mediaType);
+ }
+
+ void InfoTagMusic::setTrack(int track)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTrackRaw(infoTag, track);
+ }
+
+ void InfoTagMusic::setDisc(int disc)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDiscRaw(infoTag, disc);
+ }
+
+ void InfoTagMusic::setDuration(int duration)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDurationRaw(infoTag, duration);
+ }
+
+ void InfoTagMusic::setYear(int year)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setYearRaw(infoTag, year);
+ }
+
+ void InfoTagMusic::setReleaseDate(const String& releaseDate)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setReleaseDateRaw(infoTag, releaseDate);
+ }
+
+ void InfoTagMusic::setListeners(int listeners)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setListenersRaw(infoTag, listeners);
+ }
+
+ void InfoTagMusic::setPlayCount(int playcount)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPlayCountRaw(infoTag, playcount);
+ }
+
+ void InfoTagMusic::setGenres(const std::vector<String>& genres)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setGenresRaw(infoTag, genres);
+ }
+
+ void InfoTagMusic::setAlbum(const String& album)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setAlbumRaw(infoTag, album);
+ }
+
+ void InfoTagMusic::setArtist(const String& artist)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setArtistRaw(infoTag, artist);
+ }
+
+ void InfoTagMusic::setAlbumArtist(const String& albumArtist)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setAlbumArtistRaw(infoTag, albumArtist);
+ }
+
+ void InfoTagMusic::setTitle(const String& title)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTitleRaw(infoTag, title);
+ }
+
+ void InfoTagMusic::setRating(float rating)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setRatingRaw(infoTag, rating);
+ }
+
+ void InfoTagMusic::setUserRating(int userrating)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setUserRatingRaw(infoTag, userrating);
+ }
+
+ void InfoTagMusic::setLyrics(const String& lyrics)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setLyricsRaw(infoTag, lyrics);
+ }
+
+ void InfoTagMusic::setLastPlayed(const String& lastPlayed)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setLastPlayedRaw(infoTag, lastPlayed);
+ }
+
+ void InfoTagMusic::setMusicBrainzTrackID(const String& musicBrainzTrackID)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMusicBrainzTrackIDRaw(infoTag, musicBrainzTrackID);
+ }
+
+ void InfoTagMusic::setMusicBrainzArtistID(const std::vector<String>& musicBrainzArtistID)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMusicBrainzArtistIDRaw(infoTag, musicBrainzArtistID);
+ }
+
+ void InfoTagMusic::setMusicBrainzAlbumID(const String& musicBrainzAlbumID)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMusicBrainzAlbumIDRaw(infoTag, musicBrainzAlbumID);
+ }
+
+ void InfoTagMusic::setMusicBrainzReleaseGroupID(const String& musicBrainzReleaseGroupID)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMusicBrainzReleaseGroupIDRaw(infoTag, musicBrainzReleaseGroupID);
+ }
+
+ void InfoTagMusic::setMusicBrainzAlbumArtistID(
+ const std::vector<String>& musicBrainzAlbumArtistID)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMusicBrainzAlbumArtistIDRaw(infoTag, musicBrainzAlbumArtistID);
+ }
+
+ void InfoTagMusic::setComment(const String& comment)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setCommentRaw(infoTag, comment);
+ }
+
+ void InfoTagMusic::setDbIdRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int dbId, const String& type)
+ {
+ infoTag->SetDatabaseId(dbId, type);
+ }
+
+ void InfoTagMusic::setURLRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& url)
+ {
+ infoTag->SetURL(url);
+ }
+
+ void InfoTagMusic::setMediaTypeRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& mediaType)
+ {
+ infoTag->SetType(mediaType);
+ }
+
+ void InfoTagMusic::setTrackRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int track)
+ {
+ infoTag->SetTrackNumber(track);
+ }
+
+ void InfoTagMusic::setDiscRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int disc)
+ {
+ infoTag->SetDiscNumber(disc);
+ }
+
+ void InfoTagMusic::setDurationRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int duration)
+ {
+ infoTag->SetDuration(duration);
+ }
+
+ void InfoTagMusic::setYearRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int year)
+ {
+ infoTag->SetYear(year);
+ }
+
+ void InfoTagMusic::setReleaseDateRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& releaseDate)
+ {
+ infoTag->SetReleaseDate(releaseDate);
+ }
+
+ void InfoTagMusic::setListenersRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int listeners)
+ {
+ infoTag->SetListeners(listeners);
+ }
+
+ void InfoTagMusic::setPlayCountRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int playcount)
+ {
+ infoTag->SetPlayCount(playcount);
+ }
+
+ void InfoTagMusic::setGenresRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const std::vector<String>& genres)
+ {
+ infoTag->SetGenre(genres);
+ }
+
+ void InfoTagMusic::setAlbumRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& album)
+ {
+ infoTag->SetAlbum(album);
+ }
+
+ void InfoTagMusic::setArtistRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& artist)
+ {
+ infoTag->SetArtist(artist);
+ }
+
+ void InfoTagMusic::setAlbumArtistRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& albumArtist)
+ {
+ infoTag->SetAlbumArtist(albumArtist);
+ }
+
+ void InfoTagMusic::setTitleRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& title)
+ {
+ infoTag->SetTitle(title);
+ }
+
+ void InfoTagMusic::setRatingRaw(MUSIC_INFO::CMusicInfoTag* infoTag, float rating)
+ {
+ infoTag->SetRating(rating);
+ }
+
+ void InfoTagMusic::setUserRatingRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int userrating)
+ {
+ infoTag->SetUserrating(userrating);
+ }
+
+ void InfoTagMusic::setLyricsRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& lyrics)
+ {
+ infoTag->SetLyrics(lyrics);
+ }
+
+ void InfoTagMusic::setLastPlayedRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& lastPlayed)
+ {
+ infoTag->SetLastPlayed(lastPlayed);
+ }
+
+ void InfoTagMusic::setMusicBrainzTrackIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& musicBrainzTrackID)
+ {
+ infoTag->SetMusicBrainzTrackID(musicBrainzTrackID);
+ }
+
+ void InfoTagMusic::setMusicBrainzArtistIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const std::vector<String>& musicBrainzArtistID)
+ {
+ infoTag->SetMusicBrainzArtistID(musicBrainzArtistID);
+ }
+
+ void InfoTagMusic::setMusicBrainzAlbumIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& musicBrainzAlbumID)
+ {
+ infoTag->SetMusicBrainzAlbumID(musicBrainzAlbumID);
+ }
+
+ void InfoTagMusic::setMusicBrainzReleaseGroupIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& musicBrainzReleaseGroupID)
+ {
+ infoTag->SetMusicBrainzReleaseGroupID(musicBrainzReleaseGroupID);
+ }
+
+ void InfoTagMusic::setMusicBrainzAlbumArtistIDRaw(
+ MUSIC_INFO::CMusicInfoTag* infoTag, const std::vector<String>& musicBrainzAlbumArtistID)
+ {
+ infoTag->SetMusicBrainzAlbumArtistID(musicBrainzAlbumArtistID);
+ }
+
+ void InfoTagMusic::setCommentRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& comment)
+ {
+ infoTag->SetComment(comment);
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/InfoTagMusic.h b/xbmc/interfaces/legacy/InfoTagMusic.h
new file mode 100644
index 0000000..835a705
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagMusic.h
@@ -0,0 +1,1034 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+
+#include <vector>
+
+namespace MUSIC_INFO
+{
+class CMusicInfoTag;
+}
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ //
+ /// \defgroup python_InfoTagMusic InfoTagMusic
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's music info tag class.**
+ ///
+ /// \python_class{ xbmc.InfoTagMusic([offscreen]) }
+ ///
+ /// Access and / or modify the music metadata of a ListItem.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// tag = xbmc.Player().getMusicInfoTag()
+ ///
+ /// title = tag.getTitle()
+ /// url = tag.getURL()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ //
+ class InfoTagMusic : public AddonClass
+ {
+ private:
+ MUSIC_INFO::CMusicInfoTag* infoTag;
+ bool offscreen;
+ bool owned;
+
+ public:
+#ifndef SWIG
+ explicit InfoTagMusic(const MUSIC_INFO::CMusicInfoTag* tag);
+ explicit InfoTagMusic(MUSIC_INFO::CMusicInfoTag* tag, bool offscreen = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ xbmc.InfoTagMusic([offscreen]) }
+ /// Create a music info tag.
+ ///
+ /// @param offscreen [opt] bool (default `False`) - if GUI based locks should be
+ /// avoided. Most of the times listitems are created
+ /// offscreen and added later to a container
+ /// for display (e.g. plugins) or they are not
+ /// even displayed (e.g. python scrapers).
+ /// In such cases, there is no need to lock the
+ /// GUI when creating the items (increasing your addon
+ /// performance).
+ /// Note however, that if you are creating listitems
+ /// and managing the container itself (e.g using
+ /// WindowXML or WindowXMLDialog classes) subsquent
+ /// modifications to the item will require locking.
+ /// Thus, in such cases, use the default value (`False`).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Added **offscreen** argument.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// musicinfo = xbmc.InfoTagMusic(offscreen=False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ InfoTagMusic(...);
+#else
+ explicit InfoTagMusic(bool offscreen = false);
+#endif
+ ~InfoTagMusic() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getDbId() }
+ /// Get identification number of tag in database.
+ ///
+ /// @return [integer] database id.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getDbId();
+#else
+ int getDbId();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getURL() }
+ /// Returns url of source as string from music info tag.
+ ///
+ /// @return [string] Url of source
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getURL();
+#else
+ String getURL();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getTitle() }
+ /// Returns the title from music as string on info tag.
+ ///
+ /// @return [string] Music title
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getTitle();
+#else
+ String getTitle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getMediaType() }
+ /// Get the media type of the music item.
+ ///
+ /// @return [string] media type
+ ///
+ /// Available strings about media type for music:
+ /// | String | Description |
+ /// |---------------:|:--------------------------------------------------|
+ /// | artist | If it is defined as an artist
+ /// | album | If it is defined as an album
+ /// | song | If it is defined as a song
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getMediaType();
+#else
+ String getMediaType();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getArtist() }
+ /// Returns the artist from music as string if present.
+ ///
+ /// @return [string] Music artist
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getArtist();
+#else
+ String getArtist();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getAlbum() }
+ /// Returns the album from music tag as string if present.
+ ///
+ /// @return [string] Music album name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getAlbum();
+#else
+ String getAlbum();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getAlbumArtist() }
+ /// Returns the album artist from music tag as string if present.
+ ///
+ /// @return [string] Music album artist name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getAlbumArtist();
+#else
+ String getAlbumArtist();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getGenre() }
+ /// Returns the genre name from music tag as string if present.
+ ///
+ /// @return [string] Genre name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getGenres()** instead.
+ ///
+ getGenre();
+#else
+ String getGenre();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getGenres() }
+ /// Returns the list of genres from music tag if present.
+ ///
+ /// @return [list] List of genres
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getGenres();
+#else
+ std::vector<String> getGenres();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getDuration() }
+ /// Returns the duration of music as integer from info tag.
+ ///
+ /// @return [integer] Duration
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getDuration();
+#else
+ int getDuration();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getYear() }
+ /// Returns the year of music as integer from info tag.
+ ///
+ /// @return [integer] Year
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ ///
+ getYear();
+#else
+ int getYear();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getRating() }
+ /// Returns the scraped rating as integer.
+ ///
+ /// @return [integer] Rating
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getRating();
+#else
+ int getRating();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getUserRating() }
+ /// Returns the user rating as integer (-1 if not existing)
+ ///
+ /// @return [integer] User rating
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getUserRating();
+#else
+ int getUserRating();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getTrack() }
+ /// Returns the track number (if present) from music info tag as integer.
+ ///
+ /// @return [integer] Track number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getTrack();
+#else
+ int getTrack();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getDisc() }
+ /// Returns the disk number (if present) from music info tag as integer.
+ ///
+ /// @return [integer] Disc number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getDisc();
+#else
+ /**
+ * getDisc() -- returns an integer.\n
+ */
+ int getDisc();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getReleaseDate() }
+ /// Returns the release date as string from music info tag (if present).
+ ///
+ /// @return [string] Release date
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getReleaseDate();
+#else
+ String getReleaseDate();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getListeners() }
+ /// Returns the listeners as integer from music info tag.
+ ///
+ /// @return [integer] Listeners
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getListeners();
+#else
+ int getListeners();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getPlayCount() }
+ /// Returns the number of carried out playbacks.
+ ///
+ /// @return [integer] Playback count
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getPlayCount();
+#else
+ int getPlayCount();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getLastPlayed() }
+ /// Returns last played time as string from music info tag.
+ ///
+ /// @return [string] Last played date / time on tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getLastPlayedAsW3C()** instead.
+ ///
+ getLastPlayed();
+#else
+ String getLastPlayed();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getLastPlayedAsW3C() }
+ /// Returns last played time as string in W3C format (YYYY-MM-DDThh:mm:ssTZD).
+ ///
+ /// @return [string] Last played datetime (W3C)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getLastPlayedAsW3C();
+#else
+ String getLastPlayedAsW3C();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getComment() }
+ /// Returns comment as string from music info tag.
+ ///
+ /// @return [string] Comment on tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getComment();
+#else
+ String getComment();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getLyrics() }
+ /// Returns a string from lyrics.
+ ///
+ /// @return [string] Lyrics on tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getLyrics();
+#else
+ String getLyrics();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getMusicBrainzTrackID() }
+ /// Returns the MusicBrainz Recording ID from music info tag (if present).
+ ///
+ /// @return [string] MusicBrainz Recording ID
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added.
+ ///
+ getMusicBrainzTrackID();
+#else
+ String getMusicBrainzTrackID();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getMusicBrainzArtistID() }
+ /// Returns the MusicBrainz Artist IDs from music info tag (if present).
+ ///
+ /// @return [list] MusicBrainz Artist IDs
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added.
+ ///
+ getMusicBrainzArtistID();
+#else
+ std::vector<String> getMusicBrainzArtistID();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getMusicBrainzAlbumID() }
+ /// Returns the MusicBrainz Release ID from music info tag (if present).
+ ///
+ /// @return [string] MusicBrainz Release ID
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added.
+ ///
+ getMusicBrainzAlbumID();
+#else
+ String getMusicBrainzAlbumID();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getMusicBrainzReleaseGroupID() }
+ /// Returns the MusicBrainz Release Group ID from music info tag (if present).
+ ///
+ /// @return [string] MusicBrainz Release Group ID
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added.
+ ///
+ getMusicBrainzReleaseGroupID();
+#else
+ String getMusicBrainzReleaseGroupID();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ getMusicBrainzAlbumArtistID() }
+ /// Returns the MusicBrainz Release Artist IDs from music info tag (if present).
+ ///
+ /// @return [list] MusicBrainz Release Artist IDs
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added.
+ ///
+ getMusicBrainzAlbumArtistID();
+#else
+ std::vector<String> getMusicBrainzAlbumArtistID();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setDbId(dbId, type) }
+ /// Set the database identifier of the music item.
+ ///
+ /// @param dbId integer - Database identifier.
+ /// @param type string - Media type of the item.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDbId(...);
+#else
+ void setDbId(int dbId, const String& type);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setURL(url) }
+ /// Set the URL of the music item.
+ ///
+ /// @param url string - URL.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setURL(...);
+#else
+ void setURL(const String& url);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setMediaType(mediaType) }
+ /// Set the media type of the music item.
+ ///
+ /// @param mediaType string - Media type.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMediaType(...);
+#else
+ void setMediaType(const String& mediaType);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setTrack(track) }
+ /// Set the track number of the song.
+ ///
+ /// @param track integer - Track number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTrack(...);
+#else
+ void setTrack(int track);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setDisc(disc) }
+ /// Set the disc number of the song.
+ ///
+ /// @param disc integer - Disc number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDisc(...);
+#else
+ void setDisc(int disc);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setDuration(duration) }
+ /// Set the duration of the song.
+ ///
+ /// @param duration integer - Duration in seconds.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDuration(...);
+#else
+ void setDuration(int duration);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setYear(year) }
+ /// Set the year of the music item.
+ ///
+ /// @param year integer - Year.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setYear(...);
+#else
+ void setYear(int year);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setReleaseDate(releaseDate) }
+ /// Set the release date of the music item.
+ ///
+ /// @param releaseDate string - Release date in ISO8601 format (YYYY, YYYY-MM or YYYY-MM-DD).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setReleaseDate(...);
+#else
+ void setReleaseDate(const String& releaseDate);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setListeners(listeners) }
+ /// Set the number of listeners of the music item.
+ ///
+ /// @param listeners integer - Number of listeners.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setListeners(...);
+#else
+ void setListeners(int listeners);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setPlayCount(playcount) }
+ /// Set the playcount of the music item.
+ ///
+ /// @param playcount integer - Playcount.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPlayCount(...);
+#else
+ void setPlayCount(int playcount);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setGenres(genres) }
+ /// Set the genres of the music item.
+ ///
+ /// @param genres list - Genres.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setGenres(...);
+#else
+ void setGenres(const std::vector<String>& genres);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setAlbum(album) }
+ /// Set the album of the music item.
+ ///
+ /// @param album string - Album.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setAlbum(...);
+#else
+ void setAlbum(const String& album);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setArtist(artist) }
+ /// Set the artist(s) of the music item.
+ ///
+ /// @param artist string - Artist(s).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setArtist(...);
+#else
+ void setArtist(const String& artist);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setAlbumArtist(albumArtist) }
+ /// Set the album artist(s) of the music item.
+ ///
+ /// @param albumArtist string - Album artist(s).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setAlbumArtist(...);
+#else
+ void setAlbumArtist(const String& albumArtist);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setTitle(title) }
+ /// Set the title of the music item.
+ ///
+ /// @param title string - Title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTitle(...);
+#else
+ void setTitle(const String& title);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setRating(rating) }
+ /// Set the rating of the music item.
+ ///
+ /// @param rating float - Rating.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setRating(...);
+#else
+ void setRating(float rating);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setUserRating(userrating) }
+ /// Set the user rating of the music item.
+ ///
+ /// @param userrating integer - User rating.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setUserRating(...);
+#else
+ void setUserRating(int userrating);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setLyrics(lyrics) }
+ /// Set the lyrics of the song.
+ ///
+ /// @param lyrics string - Lyrics.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setLyrics(...);
+#else
+ void setLyrics(const String& lyrics);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setLastPlayed(lastPlayed) }
+ /// Set the last played date of the music item.
+ ///
+ /// @param lastPlayed string - Last played date (YYYY-MM-DD HH:MM:SS).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setLastPlayed(...);
+#else
+ void setLastPlayed(const String& lastPlayed);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setMusicBrainzTrackID(musicBrainzTrackID) }
+ /// Set the MusicBrainz track ID of the song.
+ ///
+ /// @param musicBrainzTrackID string - MusicBrainz track ID.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMusicBrainzTrackID(...);
+#else
+ void setMusicBrainzTrackID(const String& musicBrainzTrackID);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setMusicBrainzArtistID(musicBrainzArtistID) }
+ /// Set the MusicBrainz artist IDs of the music item.
+ ///
+ /// @param musicBrainzArtistID list - MusicBrainz artist IDs.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMusicBrainzArtistID(...);
+#else
+ void setMusicBrainzArtistID(const std::vector<String>& musicBrainzArtistID);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setMusicBrainzAlbumID(musicBrainzAlbumID) }
+ /// Set the MusicBrainz album ID of the music item.
+ ///
+ /// @param musicBrainzAlbumID string - MusicBrainz album ID.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMusicBrainzAlbumID(...);
+#else
+ void setMusicBrainzAlbumID(const String& musicBrainzAlbumID);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setMusicBrainzReleaseGroupID(musicBrainzReleaseGroupID) }
+ /// Set the MusicBrainz release group ID of the music item.
+ ///
+ /// @param musicBrainzReleaseGroupID string - MusicBrainz release group ID.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMusicBrainzReleaseGroupID(...);
+#else
+ void setMusicBrainzReleaseGroupID(const String& musicBrainzReleaseGroupID);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setMusicBrainzAlbumArtistID(musicBrainzAlbumArtistID) }
+ /// Set the MusicBrainz album artist IDs of the music item.
+ ///
+ /// @param musicBrainzAlbumArtistID list - MusicBrainz album artist IDs.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMusicBrainzAlbumArtistID(...);
+#else
+ void setMusicBrainzAlbumArtistID(const std::vector<String>& musicBrainzAlbumArtistID);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagMusic
+ /// @brief \python_func{ setComment(comment) }
+ /// Set the comment of the music item.
+ ///
+ /// @param comment string - Comment.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setComment(...);
+#else
+ void setComment(const String& comment);
+#endif
+
+#ifndef SWIG
+ static void setDbIdRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int dbId, const String& type);
+ static void setURLRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& url);
+ static void setMediaTypeRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& mediaType);
+ static void setTrackRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int track);
+ static void setDiscRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int disc);
+ static void setDurationRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int duration);
+ static void setYearRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int year);
+ static void setReleaseDateRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& releaseDate);
+ static void setListenersRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int listeners);
+ static void setPlayCountRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int playcount);
+ static void setGenresRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const std::vector<String>& genres);
+ static void setAlbumRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& album);
+ static void setArtistRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& artist);
+ static void setAlbumArtistRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& albumArtist);
+ static void setTitleRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& title);
+ static void setRatingRaw(MUSIC_INFO::CMusicInfoTag* infoTag, float rating);
+ static void setUserRatingRaw(MUSIC_INFO::CMusicInfoTag* infoTag, int userrating);
+ static void setLyricsRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& lyrics);
+ static void setLastPlayedRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& lastPlayed);
+ static void setMusicBrainzTrackIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& musicBrainzTrackID);
+ static void setMusicBrainzArtistIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const std::vector<String>& musicBrainzArtistID);
+ static void setMusicBrainzAlbumIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& musicBrainzAlbumID);
+ static void setMusicBrainzReleaseGroupIDRaw(MUSIC_INFO::CMusicInfoTag* infoTag,
+ const String& musicBrainzReleaseGroupID);
+ static void setMusicBrainzAlbumArtistIDRaw(
+ MUSIC_INFO::CMusicInfoTag* infoTag, const std::vector<String>& musicBrainzAlbumArtistID);
+ static void setCommentRaw(MUSIC_INFO::CMusicInfoTag* infoTag, const String& comment);
+#endif
+ };
+ //@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/InfoTagPicture.cpp b/xbmc/interfaces/legacy/InfoTagPicture.cpp
new file mode 100644
index 0000000..892e2be
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagPicture.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2021 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 "InfoTagPicture.h"
+
+#include "AddonUtils.h"
+#include "guilib/guiinfo/GUIInfoLabels.h"
+#include "interfaces/legacy/Exception.h"
+#include "pictures/PictureInfoTag.h"
+#include "utils/StringUtils.h"
+
+using namespace XBMCAddonUtils;
+
+namespace XBMCAddon
+{
+namespace xbmc
+{
+
+InfoTagPicture::InfoTagPicture(bool offscreen /* = false */)
+ : infoTag(new CPictureInfoTag), offscreen(offscreen), owned(true)
+{
+}
+
+InfoTagPicture::InfoTagPicture(const CPictureInfoTag* tag)
+ : infoTag(new CPictureInfoTag(*tag)), offscreen(true), owned(true)
+{
+}
+
+InfoTagPicture::InfoTagPicture(CPictureInfoTag* tag, bool offscreen /* = false */)
+ : infoTag(tag), offscreen(offscreen), owned(false)
+{
+}
+
+InfoTagPicture::~InfoTagPicture()
+{
+ if (owned)
+ delete infoTag;
+}
+
+String InfoTagPicture::getResolution()
+{
+ return infoTag->GetInfo(SLIDESHOW_RESOLUTION);
+}
+
+String InfoTagPicture::getDateTimeTaken()
+{
+ return infoTag->GetDateTimeTaken().GetAsW3CDateTime();
+}
+
+void InfoTagPicture::setResolution(int width, int height)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setResolutionRaw(infoTag, width, height);
+}
+
+void InfoTagPicture::setDateTimeTaken(const String& datetimetaken)
+{
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDateTimeTakenRaw(infoTag, datetimetaken);
+}
+
+void InfoTagPicture::setResolutionRaw(CPictureInfoTag* infoTag, const String& resolution)
+{
+ infoTag->SetInfo("resolution", resolution);
+}
+
+void InfoTagPicture::setResolutionRaw(CPictureInfoTag* infoTag, int width, int height)
+{
+ if (width <= 0)
+ throw WrongTypeException("InfoTagPicture.setResolution: width must be greater than zero (0)");
+ if (height <= 0)
+ throw WrongTypeException("InfoTagPicture.setResolution: height must be greater than zero (0)");
+
+ setResolutionRaw(infoTag, StringUtils::Format("{:d},{:d}", width, height));
+}
+
+void InfoTagPicture::setDateTimeTakenRaw(CPictureInfoTag* infoTag, String datetimetaken)
+{
+ // try to parse the datetimetaken as from W3C format and adjust it to the EXIF datetime format YYYY:MM:DD HH:MM:SS
+ CDateTime w3cDateTimeTaken;
+ if (w3cDateTimeTaken.SetFromW3CDateTime(datetimetaken))
+ {
+ datetimetaken = StringUtils::Format("{:4d}:{:2d}:{:2d} {:2d}:{:2d}:{:2d}",
+ w3cDateTimeTaken.GetYear(), w3cDateTimeTaken.GetMonth(),
+ w3cDateTimeTaken.GetDay(), w3cDateTimeTaken.GetHour(),
+ w3cDateTimeTaken.GetMinute(), w3cDateTimeTaken.GetSecond());
+ }
+
+ infoTag->SetInfo("exiftime", datetimetaken);
+}
+
+} // namespace xbmc
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/InfoTagPicture.h b/xbmc/interfaces/legacy/InfoTagPicture.h
new file mode 100644
index 0000000..a03bf0f
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagPicture.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2021 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 "AddonClass.h"
+
+class CPictureInfoTag;
+
+namespace XBMCAddon
+{
+namespace xbmc
+{
+
+///
+/// \defgroup python_InfoTagPicture InfoTagPicture
+/// \ingroup python_xbmc
+/// @{
+/// @brief **Kodi's picture info tag class.**
+///
+/// \python_class{ InfoTagPicture() }
+///
+/// Access and / or modify the picture metadata of a ListItem.
+///
+///-------------------------------------------------------------------------
+/// @python_v20 New class added.
+///
+/// **Example:**
+/// ~~~~~~~~~~~~~{.py}
+/// ...
+/// tag = item.getPictureInfoTag()
+///
+/// datetime_taken = tag.getDateTimeTaken()
+/// tag.setResolution(1920, 1080)
+/// ...
+/// ~~~~~~~~~~~~~
+///
+class InfoTagPicture : public AddonClass
+{
+private:
+ CPictureInfoTag* infoTag;
+ bool offscreen;
+ bool owned;
+
+public:
+#ifndef SWIG
+ explicit InfoTagPicture(const CPictureInfoTag* tag);
+ explicit InfoTagPicture(CPictureInfoTag* tag, bool offscreen = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagPicture
+ /// @brief \python_func{ xbmc.InfoTagPicture([offscreen]) }
+ /// Create a picture info tag.
+ ///
+ /// @param offscreen [opt] bool (default `False`) - if GUI based locks should be
+ /// avoided. Most of the times listitems are created
+ /// offscreen and added later to a container
+ /// for display (e.g. plugins) or they are not
+ /// even displayed (e.g. python scrapers).
+ /// In such cases, there is no need to lock the
+ /// GUI when creating the items (increasing your addon
+ /// performance).
+ /// Note however, that if you are creating listitems
+ /// and managing the container itself (e.g using
+ /// WindowXML or WindowXMLDialog classes) subsquent
+ /// modifications to the item will require locking.
+ /// Thus, in such cases, use the default value (`False`).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// pictureinfo = xbmc.InfoTagPicture(offscreen=False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ InfoTagPicture(...);
+#else
+ explicit InfoTagPicture(bool offscreen = false);
+#endif
+ ~InfoTagPicture() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagPicture
+ /// @brief \python_func{ getResolution() }
+ /// Get the resolution of the picture in the format "w x h".
+ ///
+ /// @return [string] Resolution of the picture in the format "w x h".
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getResolution();
+#else
+ String getResolution();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagPicture
+ /// @brief \python_func{ getDateTimeTaken() }
+ /// Get the date and time at which the picture was taken in W3C format.
+ ///
+ /// @return [string] Date and time at which the picture was taken in W3C format.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getDirector();
+#else
+ String getDateTimeTaken();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagPicture
+ /// @brief \python_func{ setResolution(width, height) }
+ /// Sets the resolution of the picture.
+ ///
+ /// @param width int - Width of the picture in pixels.
+ /// @param height int - Height of the picture in pixels.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setResolution(...);
+#else
+ void setResolution(int width, int height);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagPicture
+ /// @brief \python_func{ setDateTimeTaken(datetimetaken) }
+ /// Sets the date and time at which the picture was taken in W3C format.
+ /// The following formats are supported:
+ /// - YYYY
+ /// - YYYY-MM-DD
+ /// - YYYY-MM-DDThh:mm[TZD]
+ /// - YYYY-MM-DDThh:mm:ss[TZD]
+ /// where the timezone (TZD) is always optional and can be in one of the
+ /// following formats:
+ /// - Z (for UTC)
+ /// - +hh:mm
+ /// - -hh:mm
+ ///
+ /// @param datetimetaken string - Date and time at which the picture was taken in W3C format.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDateTimeTaken(...);
+#else
+ void setDateTimeTaken(const String& datetimetaken);
+#endif
+
+#ifndef SWIG
+ static void setResolutionRaw(CPictureInfoTag* infoTag, const String& resolution);
+ static void setResolutionRaw(CPictureInfoTag* infoTag, int width, int height);
+ static void setDateTimeTakenRaw(CPictureInfoTag* infoTag, String datetimetaken);
+#endif
+};
+
+} // namespace xbmc
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/InfoTagRadioRDS.cpp b/xbmc/interfaces/legacy/InfoTagRadioRDS.cpp
new file mode 100644
index 0000000..b60ea4c
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagRadioRDS.cpp
@@ -0,0 +1,234 @@
+/*
+ * 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 "InfoTagRadioRDS.h"
+
+#include "pvr/channels/PVRChannel.h"
+#include "pvr/channels/PVRRadioRDSInfoTag.h"
+#include "utils/StringUtils.h"
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ InfoTagRadioRDS::InfoTagRadioRDS() = default;
+
+ InfoTagRadioRDS::InfoTagRadioRDS(const std::shared_ptr<PVR::CPVRChannel>& channel)
+ {
+ if (channel)
+ infoTag = channel->GetRadioRDSInfoTag();
+ }
+
+ InfoTagRadioRDS::~InfoTagRadioRDS() = default;
+
+ String InfoTagRadioRDS::getTitle()
+ {
+ if (infoTag)
+ return infoTag->GetTitle();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getBand()
+ {
+ if (infoTag)
+ return infoTag->GetBand();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getArtist()
+ {
+ if (infoTag)
+ return infoTag->GetArtist();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getComposer()
+ {
+ if (infoTag)
+ return infoTag->GetComposer();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getConductor()
+ {
+ if (infoTag)
+ return infoTag->GetConductor();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getAlbum()
+ {
+ if (infoTag)
+ return infoTag->GetAlbum();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getComment()
+ {
+ if (infoTag)
+ return infoTag->GetComment();
+ return "";
+ }
+
+ int InfoTagRadioRDS::getAlbumTrackNumber()
+ {
+ if (infoTag)
+ return infoTag->GetAlbumTrackNumber();
+ return 0;
+ }
+
+ String InfoTagRadioRDS::getInfoNews()
+ {
+ if (infoTag)
+ return infoTag->GetInfoNews();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoNewsLocal()
+ {
+ if (infoTag)
+ return infoTag->GetInfoNewsLocal();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoSport()
+ {
+ if (infoTag)
+ return infoTag->GetInfoSport();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoStock()
+ {
+ if (infoTag)
+ return infoTag->GetInfoStock();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoWeather()
+ {
+ if (infoTag)
+ return infoTag->GetInfoWeather();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoHoroscope()
+ {
+ if (infoTag)
+ return infoTag->GetInfoHoroscope();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoCinema()
+ {
+ if (infoTag)
+ return infoTag->GetInfoCinema();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoLottery()
+ {
+ if (infoTag)
+ return infoTag->GetInfoLottery();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getInfoOther()
+ {
+ if (infoTag)
+ return infoTag->GetInfoOther();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getEditorialStaff()
+ {
+ if (infoTag)
+ return infoTag->GetEditorialStaff();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getProgStation()
+ {
+ if (infoTag)
+ return infoTag->GetProgStation();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getProgStyle()
+ {
+ if (infoTag)
+ return infoTag->GetProgStyle();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getProgHost()
+ {
+ if (infoTag)
+ return infoTag->GetProgHost();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getProgWebsite()
+ {
+ if (infoTag)
+ return infoTag->GetProgWebsite();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getProgNow()
+ {
+ if (infoTag)
+ return infoTag->GetProgNow();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getProgNext()
+ {
+ if (infoTag)
+ return infoTag->GetProgNext();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getPhoneHotline()
+ {
+ if (infoTag)
+ return infoTag->GetPhoneHotline();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getEMailHotline()
+ {
+ if (infoTag)
+ return infoTag->GetEMailHotline();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getPhoneStudio()
+ {
+ if (infoTag)
+ return infoTag->GetPhoneStudio();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getEMailStudio()
+ {
+ if (infoTag)
+ return infoTag->GetEMailStudio();
+ return "";
+ }
+
+ String InfoTagRadioRDS::getSMSStudio()
+ {
+ if (infoTag)
+ return infoTag->GetSMSStudio();
+ return "";
+ }
+
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/InfoTagRadioRDS.h b/xbmc/interfaces/legacy/InfoTagRadioRDS.h
new file mode 100644
index 0000000..6a68221
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagRadioRDS.h
@@ -0,0 +1,443 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+
+#include <memory>
+
+namespace PVR
+{
+class CPVRChannel;
+class CPVRRadioRDSInfoTag;
+}
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ //
+ /// \defgroup python_InfoTagRadioRDS InfoTagRadioRDS
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's radio RDS info tag class.**
+ ///
+ /// \python_class{ InfoTagRadioRDS() }
+ ///
+ /// To get radio RDS info tag data of currently played PVR radio channel source.
+ ///
+ /// @note Info tag load is only be possible from present player class.\n
+ /// Also is all the data variable from radio channels and not known on beginning
+ /// of radio receiving.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// tag = xbmc.Player().getRadioRDSInfoTag()
+ ///
+ /// title = tag.getTitle()
+ /// artist = tag.getArtist()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ //
+ class InfoTagRadioRDS : public AddonClass
+ {
+ private:
+ std::shared_ptr<PVR::CPVRRadioRDSInfoTag> infoTag;
+
+ public:
+#ifndef SWIG
+ explicit InfoTagRadioRDS(const std::shared_ptr<PVR::CPVRChannel>& channel);
+#endif
+ InfoTagRadioRDS();
+ ~InfoTagRadioRDS() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getTitle() }
+ /// Title of the item on the air; i.e. song title.
+ ///
+ /// @return Title
+ ///
+ getTitle();
+#else
+ String getTitle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getBand() }
+ /// Band of the item on air.
+ ///
+ /// @return Band
+ ///
+ getBand();
+#else
+ String getBand();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getArtist() }
+ /// Artist of the item on air.
+ ///
+ /// @return Artist
+ ///
+ getArtist();
+#else
+ String getArtist();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getComposer() }
+ /// Get the Composer of the music.
+ ///
+ /// @return Composer
+ ///
+ getComposer();
+#else
+ String getComposer();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getConductor() }
+ /// Get the Conductor of the Band.
+ ///
+ /// @return Conductor
+ ///
+ getConductor();
+#else
+ String getConductor();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getAlbum() }
+ /// Album of item on air.
+ ///
+ /// @return Album name
+ ///
+ getAlbum();
+#else
+ String getAlbum();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getComment() }
+ /// Get Comment text from channel.
+ ///
+ /// @return Comment
+ ///
+ getComment();
+#else
+ String getComment();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getAlbumTrackNumber() }
+ /// Get the album track number of currently sended music.
+ ///
+ /// @return Track Number
+ ///
+ getAlbumTrackNumber();
+#else
+ int getAlbumTrackNumber();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoNews() }
+ /// Get News informations.
+ ///
+ /// @return News Information
+ ///
+ getInfoNews();
+#else
+ String getInfoNews();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoNewsLocal() }
+ /// Get Local news informations.
+ ///
+ /// @return Local News Information
+ ///
+ getInfoNewsLocal();
+#else
+ String getInfoNewsLocal();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoSport() }
+ /// Get Sport informations.
+ ///
+ /// @return Sport Information
+ ///
+ getInfoSport();
+#else
+ String getInfoSport();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoStock() }
+ /// Get Stock informations.
+ ///
+ /// @return Stock Information
+ ///
+ getInfoStock();
+#else
+ String getInfoStock();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoWeather() }
+ /// Get Weather informations.
+ ///
+ /// @return Weather Information
+ ///
+ getInfoWeather();
+#else
+ String getInfoWeather();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoHoroscope() }
+ /// Get Horoscope informations.
+ ///
+ /// @return Horoscope Information
+ ///
+ getInfoHoroscope();
+#else
+ String getInfoHoroscope();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoCinema() }
+ /// Get Cinema informations.
+ ///
+ /// @return Cinema Information
+ ///
+ getInfoCinema();
+#else
+ String getInfoCinema();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoLottery() }
+ /// Get Lottery informations.
+ ///
+ /// @return Lottery Information
+ ///
+ getInfoLottery();
+#else
+ String getInfoLottery();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getInfoOther() }
+ /// Get other informations.
+ ///
+ /// @return Other Information
+ ///
+ getInfoOther();
+#else
+ String getInfoOther();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getEditorialStaff() }
+ /// Get Editorial Staff names.
+ ///
+ /// @return Editorial Staff
+ ///
+ getEditorialStaff();
+#else
+ String getEditorialStaff();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getProgStation() }
+ /// Name describing station.
+ ///
+ /// @return Program Station
+ ///
+ getProgStation();
+#else
+ String getProgStation();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getProgStyle() }
+ /// The the radio channel style currently used.
+ ///
+ /// @return Program Style
+ ///
+ getProgStyle();
+#else
+ String getProgStyle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getProgHost() }
+ /// Host of current radio show.
+ ///
+ /// @return Program Host
+ ///
+ getProgHost();
+#else
+ String getProgHost();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getProgWebsite() }
+ /// Link to URL (web page) for radio station homepage.
+ ///
+ /// @return Program Website
+ ///
+ getProgWebsite();
+#else
+ String getProgWebsite();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getProgNow() }
+ /// Current radio program show.
+ ///
+ /// @return Program Now
+ ///
+ getProgNow();
+#else
+ String getProgNow();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getProgNext() }
+ /// Next program show.
+ ///
+ /// @return Program Next
+ ///
+ getProgNext();
+#else
+ String getProgNext();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getPhoneHotline() }
+ /// Telephone number of the radio station's hotline.
+ ///
+ /// @return Phone Hotline
+ ///
+ getPhoneHotline();
+#else
+ String getPhoneHotline();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getEMailHotline() }
+ /// Email address of the radio station's studio.
+ ///
+ /// @return EMail Hotline
+ ///
+ getEMailHotline();
+#else
+ String getEMailHotline();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getPhoneStudio() }
+ /// Telephone number of the radio station's studio.
+ ///
+ /// @return Phone Studio
+ ///
+ getPhoneStudio();
+#else
+ String getPhoneStudio();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getEMailStudio() }
+ /// Email address of radio station studio.
+ ///
+ /// @return EMail Studio
+ ///
+ getEMailStudio();
+#else
+ String getEMailStudio();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// @ingroup python_InfoTagRadioRDS
+ /// @brief \python_func{ getSMSStudio() }
+ /// SMS (Text Messaging) number for studio.
+ ///
+ /// @return SMS Studio
+ ///
+ getSMSStudio();
+#else
+ String getSMSStudio();
+#endif
+ };
+ //@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/InfoTagVideo.cpp b/xbmc/interfaces/legacy/InfoTagVideo.cpp
new file mode 100644
index 0000000..8bc5fd1
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagVideo.cpp
@@ -0,0 +1,1063 @@
+/*
+ * 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 "InfoTagVideo.h"
+
+#include "AddonUtils.h"
+#include "ServiceBroker.h"
+#include "interfaces/legacy/Exception.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include <utility>
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ Actor::Actor(const String& name /* = emptyString */,
+ const String& role /* = emptyString */,
+ int order /* = -1 */,
+ const String& thumbnail /* = emptyString */)
+ : m_name(name), m_role(role), m_order(order), m_thumbnail(thumbnail)
+ {
+ if (m_name.empty())
+ throw WrongTypeException("Actor: name property must not be empty");
+ }
+
+ SActorInfo Actor::ToActorInfo() const
+ {
+ SActorInfo actorInfo;
+ actorInfo.strName = m_name;
+ actorInfo.strRole = m_role;
+ actorInfo.order = m_order;
+ actorInfo.thumbUrl = CScraperUrl(m_thumbnail);
+ if (!actorInfo.thumbUrl.GetFirstThumbUrl().empty())
+ actorInfo.thumb = CScraperUrl::GetThumbUrl(actorInfo.thumbUrl.GetFirstUrlByType());
+
+ return actorInfo;
+ }
+
+ VideoStreamDetail::VideoStreamDetail(int width /* = 0 */,
+ int height /* = 0 */,
+ float aspect /* = 0.0f */,
+ int duration /* = 0 */,
+ const String& codec /* = emptyString */,
+ const String& stereoMode /* = emptyString */,
+ const String& language /* = emptyString */,
+ const String& hdrType /* = emptyString */)
+ : m_width(width),
+ m_height(height),
+ m_aspect(aspect),
+ m_duration(duration),
+ m_codec(codec),
+ m_stereoMode(stereoMode),
+ m_language(language),
+ m_hdrType(hdrType)
+ {
+ }
+
+ CStreamDetailVideo* VideoStreamDetail::ToStreamDetailVideo() const
+ {
+ auto streamDetail = new CStreamDetailVideo();
+ streamDetail->m_iWidth = m_width;
+ streamDetail->m_iHeight = m_height;
+ streamDetail->m_fAspect = m_aspect;
+ streamDetail->m_iDuration = m_duration;
+ streamDetail->m_strCodec = m_codec;
+ streamDetail->m_strStereoMode = m_stereoMode;
+ streamDetail->m_strLanguage = m_language;
+ streamDetail->m_strHdrType = m_hdrType;
+
+ return streamDetail;
+ }
+
+ AudioStreamDetail::AudioStreamDetail(int channels /* = -1 */,
+ const String& codec /* = emptyString */,
+ const String& language /* = emptyString */)
+ : m_channels(channels), m_codec(codec), m_language(language)
+ {
+ }
+
+ CStreamDetailAudio* AudioStreamDetail::ToStreamDetailAudio() const
+ {
+ auto streamDetail = new CStreamDetailAudio();
+ streamDetail->m_iChannels = m_channels;
+ streamDetail->m_strCodec = m_codec;
+ streamDetail->m_strLanguage = m_language;
+
+ return streamDetail;
+ }
+
+ SubtitleStreamDetail::SubtitleStreamDetail(const String& language /* = emptyString */)
+ : m_language(language)
+ {
+ }
+
+ CStreamDetailSubtitle* SubtitleStreamDetail::ToStreamDetailSubtitle() const
+ {
+ auto streamDetail = new CStreamDetailSubtitle();
+ streamDetail->m_strLanguage = m_language;
+
+ return streamDetail;
+ }
+
+ InfoTagVideo::InfoTagVideo(bool offscreen /* = false */)
+ : infoTag(new CVideoInfoTag), offscreen(offscreen), owned(true)
+ {
+ }
+
+ InfoTagVideo::InfoTagVideo(const CVideoInfoTag* tag)
+ : infoTag(new CVideoInfoTag(*tag)), offscreen(true), owned(true)
+ {
+ }
+
+ InfoTagVideo::InfoTagVideo(CVideoInfoTag* tag, bool offscreen /* = false */)
+ : infoTag(tag), offscreen(offscreen), owned(false)
+ {
+ }
+
+ InfoTagVideo::~InfoTagVideo()
+ {
+ if (owned)
+ delete infoTag;
+ }
+
+ int InfoTagVideo::getDbId()
+ {
+ return infoTag->m_iDbId;
+ }
+
+ String InfoTagVideo::getDirector()
+ {
+ return StringUtils::Join(infoTag->m_director, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ }
+
+ std::vector<String> InfoTagVideo::getDirectors()
+ {
+ return infoTag->m_director;
+ }
+
+ String InfoTagVideo::getWritingCredits()
+ {
+ return StringUtils::Join(infoTag->m_writingCredits, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ }
+
+ std::vector<String> InfoTagVideo::getWriters()
+ {
+ return infoTag->m_writingCredits;
+ }
+
+ String InfoTagVideo::getGenre()
+ {
+ return StringUtils::Join(infoTag->m_genre, CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ }
+
+ std::vector<String> InfoTagVideo::getGenres()
+ {
+ return infoTag->m_genre;
+ }
+
+ String InfoTagVideo::getTagLine()
+ {
+ return infoTag->m_strTagLine;
+ }
+
+ String InfoTagVideo::getPlotOutline()
+ {
+ return infoTag->m_strPlotOutline;
+ }
+
+ String InfoTagVideo::getPlot()
+ {
+ return infoTag->m_strPlot;
+ }
+
+ String InfoTagVideo::getPictureURL()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ infoTag->m_strPictureURL.Parse();
+ return infoTag->m_strPictureURL.GetFirstThumbUrl();
+ }
+
+ String InfoTagVideo::getTVShowTitle()
+ {
+ return infoTag->m_strShowTitle;
+ }
+
+ String InfoTagVideo::getTitle()
+ {
+ return infoTag->m_strTitle;
+ }
+
+ String InfoTagVideo::getMediaType()
+ {
+ return infoTag->m_type;
+ }
+
+ String InfoTagVideo::getVotes()
+ {
+ CLog::Log(
+ LOGWARNING,
+ "InfoTagVideo.getVotes() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getVotesAsInt().");
+
+ return std::to_string(getVotesAsInt());
+ }
+
+ int InfoTagVideo::getVotesAsInt(const String& type /* = "" */)
+ {
+ return infoTag->GetRating(type).votes;
+ }
+
+ String InfoTagVideo::getCast()
+ {
+ return infoTag->GetCast(true);
+ }
+
+ std::vector<Actor*> InfoTagVideo::getActors()
+ {
+ std::vector<Actor*> actors;
+ actors.reserve(infoTag->m_cast.size());
+
+ for (const auto& cast : infoTag->m_cast)
+ actors.push_back(new Actor(cast.strName, cast.strRole, cast.order, cast.thumbUrl.GetFirstUrlByType().m_url));
+
+ return actors;
+ }
+
+ String InfoTagVideo::getFile()
+ {
+ return infoTag->m_strFile;
+ }
+
+ String InfoTagVideo::getPath()
+ {
+ return infoTag->m_strPath;
+ }
+
+ String InfoTagVideo::getFilenameAndPath()
+ {
+ return infoTag->m_strFileNameAndPath;
+ }
+
+ String InfoTagVideo::getIMDBNumber()
+ {
+ return infoTag->GetUniqueID();
+ }
+
+ int InfoTagVideo::getSeason()
+ {
+ return infoTag->m_iSeason;
+ }
+
+ int InfoTagVideo::getEpisode()
+ {
+ return infoTag->m_iEpisode;
+ }
+
+ int InfoTagVideo::getYear()
+ {
+ return infoTag->GetYear();
+ }
+
+ double InfoTagVideo::getRating(const String& type /* = "" */)
+ {
+ return static_cast<double>(infoTag->GetRating(type).rating);
+ }
+
+ int InfoTagVideo::getUserRating()
+ {
+ return infoTag->m_iUserRating;
+ }
+
+ int InfoTagVideo::getPlayCount()
+ {
+ return infoTag->GetPlayCount();
+ }
+
+ String InfoTagVideo::getLastPlayed()
+ {
+ CLog::Log(LOGWARNING, "InfoTagVideo.getLastPlayed() is deprecated and might be removed in "
+ "future Kodi versions. Please use InfoTagVideo.getLastPlayedAsW3C().");
+
+ return infoTag->m_lastPlayed.GetAsLocalizedDateTime();
+ }
+
+ String InfoTagVideo::getLastPlayedAsW3C()
+ {
+ return infoTag->m_lastPlayed.GetAsW3CDateTime();
+ }
+
+ String InfoTagVideo::getOriginalTitle()
+ {
+ return infoTag->m_strOriginalTitle;
+ }
+
+ String InfoTagVideo::getPremiered()
+ {
+ CLog::Log(LOGWARNING, "InfoTagVideo.getPremiered() is deprecated and might be removed in "
+ "future Kodi versions. Please use InfoTagVideo.getPremieredAsW3C().");
+
+ return infoTag->GetPremiered().GetAsLocalizedDate();
+ }
+
+ String InfoTagVideo::getPremieredAsW3C()
+ {
+ return infoTag->GetPremiered().GetAsW3CDate();
+ }
+
+ String InfoTagVideo::getFirstAired()
+ {
+ CLog::Log(LOGWARNING, "InfoTagVideo.getFirstAired() is deprecated and might be removed in "
+ "future Kodi versions. Please use InfoTagVideo.getFirstAiredAsW3C().");
+
+ return infoTag->m_firstAired.GetAsLocalizedDate();
+ }
+
+ String InfoTagVideo::getFirstAiredAsW3C()
+ {
+ return infoTag->m_firstAired.GetAsW3CDate();
+ }
+
+ String InfoTagVideo::getTrailer()
+ {
+ return infoTag->m_strTrailer;
+ }
+
+ std::vector<std::string> InfoTagVideo::getArtist()
+ {
+ return infoTag->m_artist;
+ }
+
+ String InfoTagVideo::getAlbum()
+ {
+ return infoTag->m_strAlbum;
+ }
+
+ int InfoTagVideo::getTrack()
+ {
+ return infoTag->m_iTrack;
+ }
+
+ unsigned int InfoTagVideo::getDuration()
+ {
+ return infoTag->GetDuration();
+ }
+
+ double InfoTagVideo::getResumeTime()
+ {
+ return infoTag->GetResumePoint().timeInSeconds;
+ }
+
+ double InfoTagVideo::getResumeTimeTotal()
+ {
+ return infoTag->GetResumePoint().totalTimeInSeconds;
+ }
+
+ String InfoTagVideo::getUniqueID(const char* key)
+ {
+ return infoTag->GetUniqueID(key);
+ }
+
+ void InfoTagVideo::setUniqueID(const String& uniqueID,
+ const String& type /* = "" */,
+ bool isDefault /* = false */)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setUniqueIDRaw(infoTag, uniqueID, type, isDefault);
+ }
+
+ void InfoTagVideo::setUniqueIDs(const std::map<String, String>& uniqueIDs,
+ const String& defaultUniqueID /* = "" */)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setUniqueIDsRaw(infoTag, uniqueIDs, defaultUniqueID);
+ }
+
+ void InfoTagVideo::setDbId(int dbId)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDbIdRaw(infoTag, dbId);
+ }
+
+ void InfoTagVideo::setYear(int year)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setYearRaw(infoTag, year);
+ }
+
+ void InfoTagVideo::setEpisode(int episode)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setEpisodeRaw(infoTag, episode);
+ }
+
+ void InfoTagVideo::setSeason(int season)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSeasonRaw(infoTag, season);
+ }
+
+ void InfoTagVideo::setSortEpisode(int sortEpisode)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSortEpisodeRaw(infoTag, sortEpisode);
+ }
+
+ void InfoTagVideo::setSortSeason(int sortSeason)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSortSeasonRaw(infoTag, sortSeason);
+ }
+
+ void InfoTagVideo::setEpisodeGuide(const String& episodeGuide)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setEpisodeGuideRaw(infoTag, episodeGuide);
+ }
+
+ void InfoTagVideo::setTop250(int top250)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTop250Raw(infoTag, top250);
+ }
+
+ void InfoTagVideo::setSetId(int setId)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSetIdRaw(infoTag, setId);
+ }
+
+ void InfoTagVideo::setTrackNumber(int trackNumber)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTrackNumberRaw(infoTag, trackNumber);
+ }
+
+ void InfoTagVideo::setRating(float rating,
+ int votes /* = 0 */,
+ const String& type /* = "" */,
+ bool isDefault /* = false */)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setRatingRaw(infoTag, rating, votes, type, isDefault);
+ }
+
+ void InfoTagVideo::setRatings(const std::map<String, Tuple<float, int>>& ratings,
+ const String& defaultRating /* = "" */)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setRatingsRaw(infoTag, ratings, defaultRating);
+ }
+
+ void InfoTagVideo::setUserRating(int userRating)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setUserRatingRaw(infoTag, userRating);
+ }
+
+ void InfoTagVideo::setPlaycount(int playcount)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPlaycountRaw(infoTag, playcount);
+ }
+
+ void InfoTagVideo::setMpaa(const String& mpaa)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setMpaaRaw(infoTag, mpaa);
+ }
+
+ void InfoTagVideo::setPlot(const String& plot)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPlotRaw(infoTag, plot);
+ }
+
+ void InfoTagVideo::setPlotOutline(const String& plotOutline)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPlotOutlineRaw(infoTag, plotOutline);
+ }
+
+ void InfoTagVideo::setTitle(const String& title)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTitleRaw(infoTag, title);
+ }
+
+ void InfoTagVideo::setOriginalTitle(const String& originalTitle)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setOriginalTitleRaw(infoTag, originalTitle);
+ }
+
+ void InfoTagVideo::setSortTitle(const String& sortTitle)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSortTitleRaw(infoTag, sortTitle);
+ }
+
+ void InfoTagVideo::setTagLine(const String& tagLine)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTagLineRaw(infoTag, tagLine);
+ }
+
+ void InfoTagVideo::setTvShowTitle(const String& tvshowTitle)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTvShowTitleRaw(infoTag, tvshowTitle);
+ }
+
+ void InfoTagVideo::setTvShowStatus(const String& tvshowStatus)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTvShowStatusRaw(infoTag, tvshowStatus);
+ }
+
+ void InfoTagVideo::setGenres(std::vector<String> genre)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setGenresRaw(infoTag, std::move(genre));
+ }
+
+ void InfoTagVideo::setCountries(std::vector<String> countries)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setCountriesRaw(infoTag, std::move(countries));
+ }
+
+ void InfoTagVideo::setDirectors(std::vector<String> directors)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDirectorsRaw(infoTag, std::move(directors));
+ }
+
+ void InfoTagVideo::setStudios(std::vector<String> studios)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setStudiosRaw(infoTag, std::move(studios));
+ }
+
+ void InfoTagVideo::setWriters(std::vector<String> writers)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setWritersRaw(infoTag, std::move(writers));
+ }
+
+ void InfoTagVideo::setDuration(int duration)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDurationRaw(infoTag, duration);
+ }
+
+ void InfoTagVideo::setPremiered(const String& premiered)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPremieredRaw(infoTag, premiered);
+ }
+
+ void InfoTagVideo::setSet(const String& set)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSetRaw(infoTag, set);
+ }
+
+ void InfoTagVideo::setSetOverview(const String& setOverview)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setSetOverviewRaw(infoTag, setOverview);
+ }
+
+ void InfoTagVideo::setTags(std::vector<String> tags)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTagsRaw(infoTag, std::move(tags));
+ }
+
+ void InfoTagVideo::setProductionCode(const String& productionCode)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setProductionCodeRaw(infoTag, productionCode);
+ }
+
+ void InfoTagVideo::setFirstAired(const String& firstAired)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setFirstAiredRaw(infoTag, firstAired);
+ }
+
+ void InfoTagVideo::setLastPlayed(const String& lastPlayed)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setLastPlayedRaw(infoTag, lastPlayed);
+ }
+
+ void InfoTagVideo::setAlbum(const String& album)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setAlbumRaw(infoTag, album);
+ }
+
+ void InfoTagVideo::setVotes(int votes)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setVotesRaw(infoTag, votes);
+ }
+
+ void InfoTagVideo::setTrailer(const String& trailer)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setTrailerRaw(infoTag, trailer);
+ }
+
+ void InfoTagVideo::setPath(const String& path)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setPathRaw(infoTag, path);
+ }
+
+ void InfoTagVideo::setFilenameAndPath(const String& filenameAndPath)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setFilenameAndPathRaw(infoTag, filenameAndPath);
+ }
+
+ void InfoTagVideo::setIMDBNumber(const String& imdbNumber)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setIMDBNumberRaw(infoTag, imdbNumber);
+ }
+
+ void InfoTagVideo::setDateAdded(const String& dateAdded)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setDateAddedRaw(infoTag, dateAdded);
+ }
+
+ void InfoTagVideo::setMediaType(const String& mediaType)
+ {
+ setMediaTypeRaw(infoTag, mediaType);
+ }
+
+ void InfoTagVideo::setShowLinks(std::vector<String> showLinks)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setShowLinksRaw(infoTag, std::move(showLinks));
+ }
+
+ void InfoTagVideo::setArtists(std::vector<String> artists)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setArtistsRaw(infoTag, std::move(artists));
+ }
+
+ void InfoTagVideo::setCast(const std::vector<const Actor*>& actors)
+ {
+ std::vector<SActorInfo> cast;
+ cast.reserve(actors.size());
+ for (const auto& actor : actors)
+ cast.push_back(actor->ToActorInfo());
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setCastRaw(infoTag, std::move(cast));
+ }
+ }
+
+ void InfoTagVideo::setResumePoint(double time, double totalTime /* = 0.0 */)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ setResumePointRaw(infoTag, time, totalTime);
+ }
+
+ void InfoTagVideo::addSeason(int number, std::string name /* = "" */)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ addSeasonRaw(infoTag, number, std::move(name));
+ }
+
+ void InfoTagVideo::addSeasons(const std::vector<Tuple<int, std::string>>& namedSeasons)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ addSeasonsRaw(infoTag, namedSeasons);
+ }
+
+ void InfoTagVideo::addVideoStream(const VideoStreamDetail* stream)
+ {
+ if (stream == nullptr)
+ return;
+
+ auto streamDetail = stream->ToStreamDetailVideo();
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ addStreamRaw(infoTag, streamDetail);
+ }
+ }
+
+ void InfoTagVideo::addAudioStream(const AudioStreamDetail* stream)
+ {
+ if (stream == nullptr)
+ return;
+
+ auto streamDetail = stream->ToStreamDetailAudio();
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ addStreamRaw(infoTag, streamDetail);
+ }
+ }
+
+ void InfoTagVideo::addSubtitleStream(const SubtitleStreamDetail* stream)
+ {
+ if (stream == nullptr)
+ return;
+
+ auto streamDetail = stream->ToStreamDetailSubtitle();
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ addStreamRaw(infoTag, streamDetail);
+ }
+ }
+
+ void InfoTagVideo::addAvailableArtwork(const std::string& url,
+ const std::string& art_type,
+ const std::string& preview,
+ const std::string& referrer,
+ const std::string& cache,
+ bool post,
+ bool isgz,
+ int season)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, offscreen);
+ addAvailableArtworkRaw(infoTag, url, art_type, preview, referrer, cache, post, isgz, season);
+ }
+
+ void InfoTagVideo::setDbIdRaw(CVideoInfoTag* infoTag, int dbId)
+ {
+ infoTag->m_iDbId = dbId;
+ }
+
+ void InfoTagVideo::setUniqueIDRaw(CVideoInfoTag* infoTag,
+ const String& uniqueID,
+ const String& type /* = "" */,
+ bool isDefault /* = false */)
+ {
+ infoTag->SetUniqueID(uniqueID, type, isDefault);
+ }
+
+ void InfoTagVideo::setUniqueIDsRaw(CVideoInfoTag* infoTag,
+ std::map<String, String> uniqueIDs,
+ const String& defaultUniqueID /* = "" */)
+ {
+ infoTag->SetUniqueIDs(uniqueIDs);
+ auto defaultUniqueIDEntry = uniqueIDs.find(defaultUniqueID);
+ if (defaultUniqueIDEntry != uniqueIDs.end())
+ infoTag->SetUniqueID(defaultUniqueIDEntry->second, defaultUniqueIDEntry->first, true);
+ }
+
+ void InfoTagVideo::setYearRaw(CVideoInfoTag* infoTag, int year)
+ {
+ infoTag->SetYear(year);
+ }
+
+ void InfoTagVideo::setEpisodeRaw(CVideoInfoTag* infoTag, int episode)
+ {
+ infoTag->m_iEpisode = episode;
+ }
+
+ void InfoTagVideo::setSeasonRaw(CVideoInfoTag* infoTag, int season)
+ {
+ infoTag->m_iSeason = season;
+ }
+
+ void InfoTagVideo::setSortEpisodeRaw(CVideoInfoTag* infoTag, int sortEpisode)
+ {
+ infoTag->m_iSpecialSortEpisode = sortEpisode;
+ }
+
+ void InfoTagVideo::setSortSeasonRaw(CVideoInfoTag* infoTag, int sortSeason)
+ {
+ infoTag->m_iSpecialSortSeason = sortSeason;
+ }
+
+ void InfoTagVideo::setEpisodeGuideRaw(CVideoInfoTag* infoTag, const String& episodeGuide)
+ {
+ infoTag->SetEpisodeGuide(episodeGuide);
+ }
+
+ void InfoTagVideo::setTop250Raw(CVideoInfoTag* infoTag, int top250)
+ {
+ infoTag->m_iTop250 = top250;
+ }
+
+ void InfoTagVideo::setSetIdRaw(CVideoInfoTag* infoTag, int setId)
+ {
+ infoTag->m_set.id = setId;
+ }
+
+ void InfoTagVideo::setTrackNumberRaw(CVideoInfoTag* infoTag, int trackNumber)
+ {
+ infoTag->m_iTrack = trackNumber;
+ }
+
+ void InfoTagVideo::setRatingRaw(CVideoInfoTag* infoTag,
+ float rating,
+ int votes /* = 0 */,
+ const std::string& type /* = "" */,
+ bool isDefault /* = false */)
+ {
+ infoTag->SetRating(rating, votes, type, isDefault);
+ }
+
+ void InfoTagVideo::setRatingsRaw(CVideoInfoTag* infoTag,
+ const std::map<String, Tuple<float, int>>& ratings,
+ const String& defaultRating /* = "" */)
+ {
+ RatingMap ratingMap;
+ for (const auto& rating : ratings)
+ ratingMap.emplace(rating.first, CRating{rating.second.first(), rating.second.second()});
+
+ infoTag->SetRatings(std::move(ratingMap), defaultRating);
+ }
+
+ void InfoTagVideo::setUserRatingRaw(CVideoInfoTag* infoTag, int userRating)
+ {
+ infoTag->m_iUserRating = userRating;
+ }
+
+ void InfoTagVideo::setPlaycountRaw(CVideoInfoTag* infoTag, int playcount)
+ {
+ infoTag->SetPlayCount(playcount);
+ }
+
+ void InfoTagVideo::setMpaaRaw(CVideoInfoTag* infoTag, const String& mpaa)
+ {
+ infoTag->SetMPAARating(mpaa);
+ }
+
+ void InfoTagVideo::setPlotRaw(CVideoInfoTag* infoTag, const String& plot)
+ {
+ infoTag->SetPlot(plot);
+ }
+
+ void InfoTagVideo::setPlotOutlineRaw(CVideoInfoTag* infoTag, const String& plotOutline)
+ {
+ infoTag->SetPlotOutline(plotOutline);
+ }
+
+ void InfoTagVideo::setTitleRaw(CVideoInfoTag* infoTag, const String& title)
+ {
+ infoTag->SetTitle(title);
+ }
+
+ void InfoTagVideo::setOriginalTitleRaw(CVideoInfoTag* infoTag, const String& originalTitle)
+ {
+ infoTag->SetOriginalTitle(originalTitle);
+ }
+
+ void InfoTagVideo::setSortTitleRaw(CVideoInfoTag* infoTag, const String& sortTitle)
+ {
+ infoTag->SetSortTitle(sortTitle);
+ }
+
+ void InfoTagVideo::setTagLineRaw(CVideoInfoTag* infoTag, const String& tagLine)
+ {
+ infoTag->SetTagLine(tagLine);
+ }
+
+ void InfoTagVideo::setTvShowTitleRaw(CVideoInfoTag* infoTag, const String& tvshowTitle)
+ {
+ infoTag->SetShowTitle(tvshowTitle);
+ }
+
+ void InfoTagVideo::setTvShowStatusRaw(CVideoInfoTag* infoTag, const String& tvshowStatus)
+ {
+ infoTag->SetStatus(tvshowStatus);
+ }
+
+ void InfoTagVideo::setGenresRaw(CVideoInfoTag* infoTag, std::vector<String> genre)
+ {
+ infoTag->SetGenre(std::move(genre));
+ }
+
+ void InfoTagVideo::setCountriesRaw(CVideoInfoTag* infoTag, std::vector<String> countries)
+ {
+ infoTag->SetCountry(std::move(countries));
+ }
+
+ void InfoTagVideo::setDirectorsRaw(CVideoInfoTag* infoTag, std::vector<String> directors)
+ {
+ infoTag->SetDirector(std::move(directors));
+ }
+
+ void InfoTagVideo::setStudiosRaw(CVideoInfoTag* infoTag, std::vector<String> studios)
+ {
+ infoTag->SetStudio(std::move(studios));
+ }
+
+ void InfoTagVideo::setWritersRaw(CVideoInfoTag* infoTag, std::vector<String> writers)
+ {
+ infoTag->SetWritingCredits(std::move(writers));
+ }
+
+ void InfoTagVideo::setDurationRaw(CVideoInfoTag* infoTag, int duration)
+ {
+ infoTag->SetDuration(duration);
+ }
+
+ void InfoTagVideo::setPremieredRaw(CVideoInfoTag* infoTag, const String& premiered)
+ {
+ CDateTime premieredDate;
+ premieredDate.SetFromDateString(premiered);
+ infoTag->SetPremiered(premieredDate);
+ }
+
+ void InfoTagVideo::setSetRaw(CVideoInfoTag* infoTag, const String& set)
+ {
+ infoTag->SetSet(set);
+ }
+
+ void InfoTagVideo::setSetOverviewRaw(CVideoInfoTag* infoTag, const String& setOverview)
+ {
+ infoTag->SetSetOverview(setOverview);
+ }
+
+ void InfoTagVideo::setTagsRaw(CVideoInfoTag* infoTag, std::vector<String> tags)
+ {
+ infoTag->SetTags(std::move(tags));
+ }
+
+ void InfoTagVideo::setProductionCodeRaw(CVideoInfoTag* infoTag, const String& productionCode)
+ {
+ infoTag->SetProductionCode(productionCode);
+ }
+
+ void InfoTagVideo::setFirstAiredRaw(CVideoInfoTag* infoTag, const String& firstAired)
+ {
+ CDateTime firstAiredDate;
+ firstAiredDate.SetFromDateString(firstAired);
+ infoTag->m_firstAired = firstAiredDate;
+ }
+
+ void InfoTagVideo::setLastPlayedRaw(CVideoInfoTag* infoTag, const String& lastPlayed)
+ {
+ CDateTime lastPlayedDate;
+ lastPlayedDate.SetFromDBDateTime(lastPlayed);
+ infoTag->m_lastPlayed = lastPlayedDate;
+ }
+
+ void InfoTagVideo::setAlbumRaw(CVideoInfoTag* infoTag, const String& album)
+ {
+ infoTag->SetAlbum(album);
+ }
+
+ void InfoTagVideo::setVotesRaw(CVideoInfoTag* infoTag, int votes)
+ {
+ infoTag->SetVotes(votes);
+ }
+
+ void InfoTagVideo::setTrailerRaw(CVideoInfoTag* infoTag, const String& trailer)
+ {
+ infoTag->SetTrailer(trailer);
+ }
+
+ void InfoTagVideo::setPathRaw(CVideoInfoTag* infoTag, const String& path)
+ {
+ infoTag->SetPath(path);
+ }
+
+ void InfoTagVideo::setFilenameAndPathRaw(CVideoInfoTag* infoTag, const String& filenameAndPath)
+ {
+ infoTag->SetFileNameAndPath(filenameAndPath);
+ }
+
+ void InfoTagVideo::setIMDBNumberRaw(CVideoInfoTag* infoTag, const String& imdbNumber)
+ {
+ infoTag->SetUniqueID(imdbNumber);
+ }
+
+ void InfoTagVideo::setDateAddedRaw(CVideoInfoTag* infoTag, const String& dateAdded)
+ {
+ CDateTime dateAddedDate;
+ dateAddedDate.SetFromDBDateTime(dateAdded);
+ infoTag->m_dateAdded = dateAddedDate;
+ }
+
+ void InfoTagVideo::setMediaTypeRaw(CVideoInfoTag* infoTag, const String& mediaType)
+ {
+ if (CMediaTypes::IsValidMediaType(mediaType))
+ infoTag->m_type = mediaType;
+ }
+
+ void InfoTagVideo::setShowLinksRaw(CVideoInfoTag* infoTag, std::vector<String> showLinks)
+ {
+ infoTag->SetShowLink(std::move(showLinks));
+ }
+
+ void InfoTagVideo::setArtistsRaw(CVideoInfoTag* infoTag, std::vector<String> artists)
+ {
+ infoTag->m_artist = std::move(artists);
+ }
+
+ void InfoTagVideo::setCastRaw(CVideoInfoTag* infoTag, std::vector<SActorInfo> cast)
+ {
+ infoTag->m_cast = std::move(cast);
+ }
+
+ void InfoTagVideo::setResumePointRaw(CVideoInfoTag* infoTag,
+ double time,
+ double totalTime /* = 0.0 */)
+ {
+ auto resumePoint = infoTag->GetResumePoint();
+ resumePoint.timeInSeconds = time;
+ if (totalTime > 0.0)
+ resumePoint.totalTimeInSeconds = totalTime;
+ infoTag->SetResumePoint(resumePoint);
+ }
+
+ void InfoTagVideo::addSeasonRaw(CVideoInfoTag* infoTag, int number, std::string name /* = "" */)
+ {
+ infoTag->m_namedSeasons[number] = std::move(name);
+ }
+
+ void InfoTagVideo::addSeasonsRaw(CVideoInfoTag* infoTag,
+ const std::vector<Tuple<int, std::string>>& namedSeasons)
+ {
+ for (const auto& season : namedSeasons)
+ addSeasonRaw(infoTag, season.first(), season.second());
+ }
+
+ void InfoTagVideo::addStreamRaw(CVideoInfoTag* infoTag, CStreamDetail* stream)
+ {
+ infoTag->m_streamDetails.AddStream(stream);
+ }
+
+ void InfoTagVideo::finalizeStreamsRaw(CVideoInfoTag* infoTag)
+ {
+ infoTag->m_streamDetails.DetermineBestStreams();
+ }
+
+ void InfoTagVideo::addAvailableArtworkRaw(CVideoInfoTag* infoTag,
+ const std::string& url,
+ const std::string& art_type,
+ const std::string& preview,
+ const std::string& referrer,
+ const std::string& cache,
+ bool post,
+ bool isgz,
+ int season)
+ {
+ infoTag->m_strPictureURL.AddParsedUrl(url, art_type, preview, referrer, cache, post, isgz,
+ season);
+ }
+ }
+}
diff --git a/xbmc/interfaces/legacy/InfoTagVideo.h b/xbmc/interfaces/legacy/InfoTagVideo.h
new file mode 100644
index 0000000..91f925e
--- /dev/null
+++ b/xbmc/interfaces/legacy/InfoTagVideo.h
@@ -0,0 +1,2772 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "Tuple.h"
+#include "utils/StreamDetails.h"
+#include "video/VideoInfoTag.h"
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ ///
+ /// \defgroup python_xbmc_actor Actor
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Actor class used in combination with InfoTagVideo.**
+ ///
+ /// \python_class{ xbmc.Actor([name, role, order, thumbnail]) }
+ ///
+ /// Represents a single actor in the cast of a video item wrapped by InfoTagVideo.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v20 New class added.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// actor = xbmc.Actor('Sean Connery', 'James Bond', order=1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class Actor : public AddonClass
+ {
+ public:
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor Actor
+ /// @brief \python_func{ xbmc.Actor([name, role, order, thumbnail]) }
+ /// Creates a single actor for the cast of a video item wrapped by InfoTagVideo.
+ ///
+ /// @param name [opt] string - Name of the actor.
+ /// @param role [opt] string - Role of the actor in the specific video item.
+ /// @param order [opt] integer - Order of the actor in the cast of the specific video item.
+ /// @param thumbnail [opt] string - Path / URL to the thumbnail of the actor.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// actor = xbmc.Actor('Sean Connery', 'James Bond', order=1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ Actor(...);
+#else
+ explicit Actor(const String& name = emptyString,
+ const String& role = emptyString,
+ int order = -1,
+ const String& thumbnail = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ getName() }
+ /// Get the name of the actor.
+ ///
+ /// @return [string] Name of the actor
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getName();
+#else
+ String getName() const { return m_name; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ getRole() }
+ /// Get the role of the actor in the specific video item.
+ ///
+ /// @return [string] Role of the actor in the specific video item
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getRole();
+#else
+ String getRole() const { return m_role; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ getOrder() }
+ /// Get the order of the actor in the cast of the specific video item.
+ ///
+ /// @return [integer] Order of the actor in the cast of the specific video item
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getOrder();
+#else
+ int getOrder() const { return m_order; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ getThumbnail() }
+ /// Get the path / URL to the thumbnail of the actor.
+ ///
+ /// @return [string] Path / URL to the thumbnail of the actor
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getThumbnail();
+#else
+ String getThumbnail() const { return m_thumbnail; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ setName(name) }
+ /// Set the name of the actor.
+ ///
+ /// @param name string - Name of the actor.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setName(...);
+#else
+ void setName(const String& name) { m_name = name; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ setRole(role) }
+ /// Set the role of the actor in the specific video item.
+ ///
+ /// @param role string - Role of the actor in the specific video item.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setRole(...);
+#else
+ void setRole(const String& role) { m_role = role; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ setOrder(order) }
+ /// Set the order of the actor in the cast of the specific video item.
+ ///
+ /// @param order integer - Order of the actor in the cast of the specific video item.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setOrder(...);
+#else
+ void setOrder(int order) { m_order = order; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_actor
+ /// @brief \python_func{ setThumbnail(thumbnail) }
+ /// Set the path / URL to the thumbnail of the actor.
+ ///
+ /// @param thumbnail string - Path / URL to the thumbnail of the actor.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setThumbnail(...);
+#else
+ void setThumbnail(const String& thumbnail) { m_thumbnail = thumbnail; }
+#endif
+
+#ifndef SWIG
+ SActorInfo ToActorInfo() const;
+#endif
+
+ private:
+ String m_name;
+ String m_role;
+ int m_order;
+ String m_thumbnail;
+ };
+ /// @}
+
+ ///
+ /// \defgroup python_xbmc_videostreamdetail VideoStreamDetail
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Video stream details class used in combination with InfoTagVideo.**
+ ///
+ /// \python_class{ xbmc.VideoStreamDetail([width, height, aspect, duration, codec, stereoMode, language, hdrType]) }
+ ///
+ /// Represents a single selectable video stream for a video item wrapped by InfoTagVideo.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v20 New class added.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// videostream = xbmc.VideoStreamDetail(1920, 1080, language='English')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class VideoStreamDetail : public AddonClass
+ {
+ public:
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ xbmc.VideoStreamDetail([width, height, aspect, duration, codec, stereomode, language, hdrtype]) }
+ /// Creates a single video stream details class for a video item wrapped by InfoTagVideo.
+ ///
+ /// @param width [opt] integer - Width of the video stream in pixel.
+ /// @param height [opt] integer - Height of the video stream in pixel.
+ /// @param aspect [opt] float - Aspect ratio of the video stream.
+ /// @param duration [opt] integer - Duration of the video stream in seconds.
+ /// @param codec [opt] string - Codec of the video stream.
+ /// @param stereomode [opt] string - Stereo mode of the video stream.
+ /// @param language [opt] string - Language of the video stream.
+ /// @param hdrtype [opt] string - HDR type of the video stream.
+ /// The following types are supported:
+ /// dolbyvision, hdr10, hlg
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// videostream = xbmc.VideoStreamDetail(1920, 1080, language='English')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ VideoStreamDetail(...);
+#else
+ explicit VideoStreamDetail(int width = 0,
+ int height = 0,
+ float aspect = 0.0f,
+ int duration = 0,
+ const String& codec = emptyString,
+ const String& stereomode = emptyString,
+ const String& language = emptyString,
+ const String& hdrtype = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getWidth() }
+ /// Get the width of the video stream in pixel.
+ ///
+ /// @return [integer] Width of the video stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getWidth();
+#else
+ int getWidth() const { return m_width; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getHeight() }
+ /// Get the height of the video stream in pixel.
+ ///
+ /// @return [integer] Height of the video stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getHeight();
+#else
+ int getHeight() const { return m_height; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getAspect() }
+ /// Get the aspect ratio of the video stream.
+ ///
+ /// @return [float] Aspect ratio of the video stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getAspect();
+#else
+ float getAspect() const { return m_aspect; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getDuration() }
+ /// Get the duration of the video stream in seconds.
+ ///
+ /// @return [float] Duration of the video stream in seconds
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getDuration();
+#else
+ int getDuration() const { return m_duration; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getCodec() }
+ /// Get the codec of the stream.
+ ///
+ /// @return [string] Codec of the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getCodec();
+#else
+ String getCodec() const { return m_codec; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getStereoMode() }
+ /// Get the stereo mode of the video stream.
+ ///
+ /// @return [string] Stereo mode of the video stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getStereoMode();
+#else
+ String getStereoMode() const { return m_stereoMode; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getLanguage() }
+ /// Get the language of the stream.
+ ///
+ /// @return [string] Language of the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getLanguage();
+#else
+ String getLanguage() const { return m_language; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ getHDRType() }
+ /// Get the HDR type of the stream.
+ ///
+ /// @return [string] HDR type of the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getHDRType();
+#else
+ String getHDRType() const { return m_hdrType; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setWidth(width) }
+ /// Set the width of the video stream in pixel.
+ ///
+ /// @param width integer - Width of the video stream in pixel.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setWidth(...);
+#else
+ void setWidth(int width) { m_width = width; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setHeight(height) }
+ /// Set the height of the video stream in pixel.
+ ///
+ /// @param height integer - Height of the video stream in pixel.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setHeight(...);
+#else
+ void setHeight(int height) { m_height = height; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setAspect(aspect) }
+ /// Set the aspect ratio of the video stream.
+ ///
+ /// @param aspect float - Aspect ratio of the video stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setAspect(...);
+#else
+ void setAspect(float aspect) { m_aspect = aspect; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setDuration(duration) }
+ /// Set the duration of the video stream in seconds.
+ ///
+ /// @param duration integer - Duration of the video stream in seconds.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDuration(...);
+#else
+ void setDuration(int duration) { m_duration = duration; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setCodec(codec) }
+ /// Set the codec of the stream.
+ ///
+ /// @param codec string - Codec of the stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setCodec(...);
+#else
+ void setCodec(const String& codec) { m_codec = codec; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setStereoMode(stereomode) }
+ /// Set the stereo mode of the video stream.
+ ///
+ /// @param stereomode string - Stereo mode of the video stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setStereoMode(...);
+#else
+ void setStereoMode(const String& stereomode) { m_stereoMode = stereomode; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setLanguage(language) }
+ /// Set the language of the stream.
+ ///
+ /// @param language string - Language of the stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setLanguage(...);
+#else
+ void setLanguage(const String& language) { m_language = language; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_videostreamdetail
+ /// @brief \python_func{ setHDRType(hdrtype) }
+ /// Set the HDR type of the stream.
+ ///
+ /// @param hdrtype string - HDR type of the stream.
+ /// The following types are supported:
+ /// dolbyvision, hdr10, hlg
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setHDRType(...);
+#else
+ void setHDRType(const String& hdrtype) { m_hdrType = hdrtype; }
+#endif
+
+#ifndef SWIG
+ CStreamDetailVideo* ToStreamDetailVideo() const;
+#endif
+
+ private:
+ int m_width;
+ int m_height;
+ float m_aspect;
+ int m_duration;
+ String m_codec;
+ String m_stereoMode;
+ String m_language;
+ String m_hdrType;
+ };
+ /// @}
+
+ ///
+ /// \defgroup python_xbmc_audiostreamdetail AudioStreamDetail
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Audio stream details class used in combination with InfoTagVideo.**
+ ///
+ /// \python_class{ xbmc.AudioStreamDetail([channels, codec, language]) }
+ ///
+ /// Represents a single selectable audio stream for a video item wrapped by InfoTagVideo.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v20 New class added.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// audiostream = xbmc.AudioStreamDetail(6, 'DTS', 'English')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class AudioStreamDetail : public AddonClass
+ {
+ public:
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail AudioStreamDetail
+ /// @brief \python_func{ xbmc.AudioStreamDetail([channels, codec, language]) }
+ /// Creates a single audio stream details class for a video item wrapped by InfoTagVideo.
+ ///
+ /// @param channels [opt] integer - Number of channels in the audio stream.
+ /// @param codec [opt] string - Codec of the audio stream.
+ /// @param language [opt] string - Language of the audio stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// audiostream = xbmc.AudioStreamDetail(6, 'DTS', 'English')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ AudioStreamDetail(...);
+#else
+ explicit AudioStreamDetail(int channels = -1,
+ const String& codec = emptyString,
+ const String& language = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail
+ /// @brief \python_func{ getChannels() }
+ /// Get the number of channels in the stream.
+ ///
+ /// @return [integer] Number of channels in the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getChannels();
+#else
+ int getChannels() const { return m_channels; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail
+ /// @brief \python_func{ getCodec() }
+ /// Get the codec of the stream.
+ ///
+ /// @return [string] Codec of the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getCodec();
+#else
+ String getCodec() const { return m_codec; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail
+ /// @brief \python_func{ getLanguage() }
+ /// Get the language of the stream.
+ ///
+ /// @return [string] Language of the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getLanguage();
+#else
+ String getLanguage() const { return m_language; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail
+ /// @brief \python_func{ setChannels(channels) }
+ /// Set the number of channels in the stream.
+ ///
+ /// @param channels integer - Number of channels in the stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setChannels(...);
+#else
+ void setChannels(int channels) { m_channels = channels; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail
+ /// @brief \python_func{ setCodec(codec) }
+ /// Set the codec of the stream.
+ ///
+ /// @param codec string - Codec of the stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setCodec(...);
+#else
+ void setCodec(const String& codec) { m_codec = codec; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_audiostreamdetail
+ /// @brief \python_func{ setLanguage(language) }
+ /// Set the language of the stream.
+ ///
+ /// @param language string - Language of the stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setLanguage(...);
+#else
+ void setLanguage(const String& language) { m_language = language; }
+#endif
+
+#ifndef SWIG
+ CStreamDetailAudio* ToStreamDetailAudio() const;
+#endif
+
+ private:
+ int m_channels;
+ String m_codec;
+ String m_language;
+ };
+ /// @}
+
+ ///
+ /// \defgroup python_xbmc_subtitlestreamdetail SubtitleStreamDetail
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Subtitle stream details class used in combination with InfoTagVideo.**
+ ///
+ /// \python_class{ xbmc.SubtitleStreamDetail([language]) }
+ ///
+ /// Represents a single selectable subtitle stream for a video item wrapped by InfoTagVideo.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v20 New class added.
+ ///
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// subtitlestream = xbmc.SubtitleStreamDetail('English')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class SubtitleStreamDetail : public AddonClass
+ {
+ public:
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_subtitlestreamdetail SubtitleStreamDetail
+ /// @brief \python_func{ xbmc.SubtitleStreamDetail([language]) }
+ /// Creates a single subtitle stream details class for a video item wrapped by InfoTagVideo.
+ ///
+ /// @param language [opt] string - Language of the subtitle.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// subtitlestream = xbmc.SubtitleStreamDetail('English')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ SubtitleStreamDetail(...);
+#else
+ explicit SubtitleStreamDetail(const String& language = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_subtitlestreamdetail
+ /// @brief \python_func{ getLanguage() }
+ /// Get the language of the stream.
+ ///
+ /// @return [string] Language of the stream
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getLanguage();
+#else
+ String getLanguage() const { return m_language; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_subtitlestreamdetail
+ /// @brief \python_func{ setLanguage(language) }
+ /// Set the language of the stream.
+ ///
+ /// @param language string - Language of the stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setLanguage(...);
+#else
+ void setLanguage(const String& language) { m_language = language; }
+#endif
+
+#ifndef SWIG
+ CStreamDetailSubtitle* ToStreamDetailSubtitle() const;
+#endif
+
+ private:
+ String m_language;
+ };
+ /// @}
+
+ ///
+ /// \defgroup python_InfoTagVideo InfoTagVideo
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's video info tag class.**
+ ///
+ /// \python_class{ xbmc.InfoTagVideo([offscreen]) }
+ ///
+ /// Access and / or modify the video metadata of a ListItem.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// tag = xbmc.Player().getVideoInfoTag()
+ ///
+ /// title = tag.getTitle()
+ /// file = tag.getFile()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ class InfoTagVideo : public AddonClass
+ {
+ private:
+ CVideoInfoTag* infoTag;
+ bool offscreen;
+ bool owned;
+
+ public:
+#ifndef SWIG
+ explicit InfoTagVideo(const CVideoInfoTag* tag);
+ explicit InfoTagVideo(CVideoInfoTag* tag, bool offscreen = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ xbmc.InfoTagVideo([offscreen]) }
+ /// Create a video info tag.
+ ///
+ /// @param offscreen [opt] bool (default `False`) - if GUI based locks should be
+ /// avoided. Most of the times listitems are created
+ /// offscreen and added later to a container
+ /// for display (e.g. plugins) or they are not
+ /// even displayed (e.g. python scrapers).
+ /// In such cases, there is no need to lock the
+ /// GUI when creating the items (increasing your addon
+ /// performance).
+ /// Note however, that if you are creating listitems
+ /// and managing the container itself (e.g using
+ /// WindowXML or WindowXMLDialog classes) subsquent
+ /// modifications to the item will require locking.
+ /// Thus, in such cases, use the default value (`False`).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Added **offscreen** argument.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// videoinfo = xbmc.InfoTagVideo(offscreen=False)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ InfoTagVideo(...);
+#else
+ explicit InfoTagVideo(bool offscreen = false);
+#endif
+ ~InfoTagVideo() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getDbId() }
+ /// Get identification number of tag in database
+ ///
+ /// @return [integer] database id
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ getDbId();
+#else
+ int getDbId();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getDirector() }
+ /// Get [film director](https://en.wikipedia.org/wiki/Film_director)
+ /// who has made the film (if present).
+ ///
+ /// @return [string] Film director name.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getDirectors()** instead.
+ ///
+ getDirector();
+#else
+ String getDirector();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getDirectors() }
+ /// Get a list of [film directors](https://en.wikipedia.org/wiki/Film_director)
+ /// who have made the film (if present).
+ ///
+ /// @return [list] List of film director names.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getDirectors();
+#else
+ std::vector<String> getDirectors();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getWritingCredits() }
+ /// Get the writing credits if present from video info tag.
+ ///
+ /// @return [string] Writing credits
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getWriters()** instead.
+ ///
+ getWritingCredits();
+#else
+ String getWritingCredits();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getWriters() }
+ /// Get the list of writers (if present) from video info tag.
+ ///
+ /// @return [list] List of writers
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getWriters();
+#else
+ std::vector<String> getWriters();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getGenre() }
+ /// To get the [Video Genre](https://en.wikipedia.org/wiki/Film_genre)
+ /// if available.
+ ///
+ /// @return [string] Genre name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getGenres()** instead.
+ ///
+ getGenre();
+#else
+ String getGenre();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getGenres() }
+ /// Get the list of [Video Genres](https://en.wikipedia.org/wiki/Film_genre)
+ /// if available.
+ ///
+ /// @return [list] List of genres
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getGenres();
+#else
+ std::vector<String> getGenres();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getTagLine() }
+ /// Get video tag line if available.
+ ///
+ /// @return [string] Video tag line
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getTagLine();
+#else
+ String getTagLine();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPlotOutline() }
+ /// Get the outline plot of the video if present.
+ ///
+ /// @return [string] Outline plot
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getPlotOutline();
+#else
+ String getPlotOutline();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPlot() }
+ /// Get the plot of the video if present.
+ ///
+ /// @return [string] Plot
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getPlot();
+#else
+ String getPlot();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPictureURL() }
+ /// Get a picture URL of the video to show as screenshot.
+ ///
+ /// @return [string] Picture URL
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getPictureURL();
+#else
+ String getPictureURL();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getTitle() }
+ /// Get the video title.
+ ///
+ /// @return [string] Video title
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getTitle();
+#else
+ String getTitle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getTVShowTitle() }
+ /// Get the video TV show title.
+ ///
+ /// @return [string] TV show title
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ getTVShowTitle();
+#else
+ String getTVShowTitle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getMediaType() }
+ /// Get the media type of the video.
+ ///
+ /// @return [string] media type
+ ///
+ /// Available strings about media type for video:
+ /// | String | Description |
+ /// |---------------:|:--------------------------------------------------|
+ /// | video | For normal video
+ /// | set | For a selection of video
+ /// | musicvideo | To define it as music video
+ /// | movie | To define it as normal movie
+ /// | tvshow | If this is it defined as tvshow
+ /// | season | The type is used as a series season
+ /// | episode | The type is used as a series episode
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ getMediaType();
+#else
+ String getMediaType();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getVotes() }
+ /// Get the video votes if available from video info tag.
+ ///
+ /// @return [string] Votes
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getVotesAsInt()** instead.
+ ///
+ getVotes();
+#else
+ String getVotes();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getVotesAsInt([type]) }
+ /// Get the votes of the rating (if available) as an integer.
+ ///
+ /// @param type [opt] string - the type of the rating.
+ /// - Some rating type values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | imdb | string - type name
+ /// | tvdb | string - type name
+ /// | tmdb | string - type name
+ /// | anidb | string - type name
+ ///
+ /// @return [integer] Votes
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getVotesAsInt(type);
+#else
+ int getVotesAsInt(const String& type = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getCast() }
+ /// To get the cast of the video when available.
+ ///
+ /// @return [string] Video casts
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getActors()** instead.
+ ///
+ getCast();
+#else
+ String getCast();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getActors() }
+ /// Get the cast of the video if available.
+ ///
+ /// @return [list] List of actors
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getActors();
+#else
+ std::vector<Actor*> getActors();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getFile() }
+ /// To get the video file name.
+ ///
+ /// @return [string] File name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getFile();
+#else
+ String getFile();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPath() }
+ /// To get the path where the video is stored.
+ ///
+ /// @return [string] Path
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getPath();
+#else
+ String getPath();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getFilenameAndPath() }
+ /// To get the full path with filename where the video is stored.
+ ///
+ /// @return [string] File name and Path
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v19 New function added.
+ ///
+ getFilenameAndPath();
+#else
+ String getFilenameAndPath();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getIMDBNumber() }
+ /// To get the [IMDb](https://en.wikipedia.org/wiki/Internet_Movie_Database)
+ /// number of the video (if present).
+ ///
+ /// @return [string] IMDb number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getIMDBNumber();
+#else
+ String getIMDBNumber();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getSeason() }
+ /// To get season number of a series
+ ///
+ /// @return [integer] season number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ getSeason();
+#else
+ int getSeason();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getEpisode() }
+ /// To get episode number of a series
+ ///
+ /// @return [integer] episode number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ getEpisode();
+#else
+ int getEpisode();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getYear() }
+ /// Get production year of video if present.
+ ///
+ /// @return [integer] Production Year
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getYear();
+#else
+ int getYear();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getRating([type]) }
+ /// Get the video rating if present as float (double where supported).
+ ///
+ /// @param type [opt] string - the type of the rating.
+ /// - Some rating type values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | imdb | string - type name
+ /// | tvdb | string - type name
+ /// | tmdb | string - type name
+ /// | anidb | string - type name
+ ///
+ /// @return [float] The rating of the video
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Optional `type` parameter added.
+ ///
+ getRating(type);
+#else
+ double getRating(const String& type = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getUserRating() }
+ /// Get the user rating if present as integer.
+ ///
+ /// @return [integer] The user rating of the video
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getUserRating();
+#else
+ int getUserRating();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPlayCount() }
+ /// To get the number of plays of the video.
+ ///
+ /// @return [integer] Play Count
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getPlayCount();
+#else
+ int getPlayCount();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getLastPlayed() }
+ /// Get the last played date / time as string.
+ ///
+ /// @return [string] Last played date / time
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getLastPlayedAsW3C()** instead.
+ ///
+ getLastPlayed();
+#else
+ String getLastPlayed();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getLastPlayedAsW3C() }
+ /// Get last played datetime as string in W3C format (YYYY-MM-DDThh:mm:ssTZD).
+ ///
+ /// @return [string] Last played datetime (W3C)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getLastPlayedAsW3C();
+#else
+ String getLastPlayedAsW3C();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getOriginalTitle() }
+ /// To get the original title of the video.
+ ///
+ /// @return [string] Original title
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ ///
+ getOriginalTitle();
+#else
+ String getOriginalTitle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPremiered() }
+ /// To get [premiered](https://en.wikipedia.org/wiki/Premiere) date
+ /// of the video, if available.
+ ///
+ /// @return [string]
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getPremieredAsW3C()** instead.
+ ///
+ getPremiered();
+#else
+ String getPremiered();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getPremieredAsW3C() }
+ /// Get [premiered](https://en.wikipedia.org/wiki/Premiere) date as string in W3C format (YYYY-MM-DD).
+ ///
+ /// @return [string] Premiered date (W3C)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getPremieredAsW3C();
+#else
+ String getPremieredAsW3C();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getFirstAired() }
+ /// Returns first aired date as string from info tag.
+ ///
+ /// @return [string] First aired date
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **getFirstAiredAsW3C()** instead.
+ ///
+ getFirstAired();
+#else
+ String getFirstAired();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getFirstAiredAsW3C() }
+ /// Get first aired date as string in W3C format (YYYY-MM-DD).
+ ///
+ /// @return [string] First aired date (W3C)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getFirstAiredAsW3C();
+#else
+ String getFirstAiredAsW3C();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getTrailer() }
+ /// To get the path where the trailer is stored.
+ ///
+ /// @return [string] Trailer path
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ getTrailer();
+#else
+ String getTrailer();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getArtist() }
+ /// To get the artist name (for musicvideos)
+ ///
+ /// @return [std::vector<std::string>] Artist name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getArtist();
+#else
+ std::vector<std::string> getArtist();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getAlbum() }
+ /// To get the album name (for musicvideos)
+ ///
+ /// @return [string] Album name
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getAlbum();
+#else
+ String getAlbum();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getTrack() }
+ /// To get the track number (for musicvideos)
+ ///
+ /// @return [int] Track number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getTrack();
+#else
+ int getTrack();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getDuration() }
+ /// To get the duration
+ ///
+ /// @return [unsigned int] Duration
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getDuration();
+#else
+ unsigned int getDuration();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getResumeTime()) }
+ /// Gets the resume time of the video item.
+ ///
+ /// @return [double] Resume time
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getResumeTime(...);
+#else
+ double getResumeTime();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getResumeTimeTotal()) }
+ /// Gets the total duration stored with the resume time of the video item.
+ ///
+ /// @return [double] Total duration stored with the resume time
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getResumeTimeTotal(...);
+#else
+ double getResumeTimeTotal();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ getUniqueID(key) }
+ /// Get the unique ID of the given key.
+ /// A unique ID is an identifier used by a (online) video database used to
+ /// identify a video in its database.
+ ///
+ /// @param key string - uniqueID name.
+ /// - Some default uniqueID values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | imdb | string - uniqueid name
+ /// | tvdb | string - uniqueid name
+ /// | tmdb | string - uniqueid name
+ /// | anidb | string - uniqueid name
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getUniqueID(key);
+#else
+ String getUniqueID(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setUniqueID(uniqueid, [type], [isdefault]) }
+ /// Set the given unique ID.
+ /// A unique ID is an identifier used by a (online) video database used to
+ /// identify a video in its database.
+ ///
+ /// @param uniqueid string - value of the unique ID.
+ /// @param type [opt] string - type / label of the unique ID.
+ /// @param isdefault [opt] bool - whether the given unique ID is the default unique ID.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setUniqueID(...);
+#else
+ void setUniqueID(const String& uniqueid, const String& type = "", bool isdefault = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setUniqueIDs(values, defaultuniqueid) }
+ /// Set the given unique IDs.
+ /// A unique ID is an identifier used by a (online) video database used to
+ /// identify a video in its database.
+ ///
+ /// @param values dictionary - pairs of `{ 'label': 'value' }`.
+ /// @param defaultuniqueid [opt] string - the name of default uniqueID.
+ ///
+ /// - Some example values (any string possible):
+ /// | Label | Type |
+ /// |:-------------:|:--------------------------------------------------|
+ /// | imdb | string - uniqueid name
+ /// | tvdb | string - uniqueid name
+ /// | tmdb | string - uniqueid name
+ /// | anidb | string - uniqueid name
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setUniqueIDs(...);
+#else
+ void setUniqueIDs(const std::map<String, String>& uniqueIDs,
+ const String& defaultuniqueid = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setDbId(dbid) }
+ /// Set the database identifier of the video item.
+ ///
+ /// @param dbid integer - Database identifier.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDbId(...);
+#else
+ void setDbId(int dbid);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setYear(year) }
+ /// Set the year of the video item.
+ ///
+ /// @param year integer - Year.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setYear(...);
+#else
+ void setYear(int year);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setEpisode(episode) }
+ /// Set the episode number of the episode.
+ ///
+ /// @param episode integer - Episode number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setEpisode(...);
+#else
+ void setEpisode(int episode);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSeason(season) }
+ /// Set the season number of the video item.
+ ///
+ /// @param season integer - Season number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSeason(...);
+#else
+ void setSeason(int season);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSortEpisode(sortepisode) }
+ /// Set the episode sort number of the episode.
+ ///
+ /// @param sortepisode integer - Episode sort number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSortEpisode(...);
+#else
+ void setSortEpisode(int sortepisode);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSortSeason(sortseason) }
+ /// Set the season sort number of the season.
+ ///
+ /// @param sortseason integer - Season sort number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSortSeason(...);
+#else
+ void setSortSeason(int sortseason);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setEpisodeGuide(episodeguide) }
+ /// Set the episode guide of the video item.
+ ///
+ /// @param episodeguide string - Episode guide.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setEpisodeGuide(...);
+#else
+ void setEpisodeGuide(const String& episodeguide);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTop250(top250) }
+ /// Set the top 250 number of the video item.
+ ///
+ /// @param top250 integer - Top 250 number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTop250(...);
+#else
+ void setTop250(int top250);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSetId(setid) }
+ /// Set the movie set identifier of the video item.
+ ///
+ /// @param setid integer - Set identifier.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSetId(...);
+#else
+ void setSetId(int setid);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTrackNumber(tracknumber) }
+ /// Set the track number of the music video item.
+ ///
+ /// @param tracknumber integer - Track number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTrackNumber(...);
+#else
+ void setTrackNumber(int tracknumber);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setRating(rating, [votes], [type], [isdefault]) }
+ /// Set the rating of the video item.
+ ///
+ /// @param rating float - Rating number.
+ /// @param votes integer - Number of votes.
+ /// @param type string - Type of the rating.
+ /// @param isdefault bool - Whether the rating is the default or not.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setRating(...);
+#else
+ void setRating(float rating, int votes = 0, const String& type = "", bool isdefault = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setRatings(ratings, [defaultrating]) }
+ /// Set the ratings of the video item.
+ ///
+ /// @param ratings dictionary - `{ 'type': (rating, votes) }`.
+ /// @param defaultrating string - Type / Label of the default rating.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setRatings(...);
+#else
+ void setRatings(const std::map<String, Tuple<float, int>>& ratings,
+ const String& defaultrating = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setUserRating(userrating) }
+ /// Set the user rating of the video item.
+ ///
+ /// @param userrating integer - User rating.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setUserRating(...);
+#else
+ void setUserRating(int userrating);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setPlaycount(playcount) }
+ /// Set the playcount of the video item.
+ ///
+ /// @param playcount integer - Playcount.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPlaycount(...);
+#else
+ void setPlaycount(int playcount);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setMpaa(mpaa) }
+ /// Set the MPAA rating of the video item.
+ ///
+ /// @param mpaa string - MPAA rating.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMpaa(...);
+#else
+ void setMpaa(const String& mpaa);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setPlot(plot) }
+ /// Set the plot of the video item.
+ ///
+ /// @param plot string - Plot.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPlot(...);
+#else
+ void setPlot(const String& plot);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setPlotOutline(plotoutline) }
+ /// Set the plot outline of the video item.
+ ///
+ /// @param plotoutline string - Plot outline.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPlotOutline(...);
+#else
+ void setPlotOutline(const String& plotoutline);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTitle(title) }
+ /// Set the title of the video item.
+ ///
+ /// @param title string - Title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTitle(...);
+#else
+ void setTitle(const String& title);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setOriginalTitle(originaltitle) }
+ /// Set the original title of the video item.
+ ///
+ /// @param originaltitle string - Original title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setOriginalTitle(...);
+#else
+ void setOriginalTitle(const String& originaltitle);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSortTitle(sorttitle) }
+ /// Set the sort title of the video item.
+ ///
+ /// @param sorttitle string - Sort title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSortTitle(...);
+#else
+ void setSortTitle(const String& sorttitle);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTagLine(tagline) }
+ /// Set the tagline of the video item.
+ ///
+ /// @param tagline string - Tagline.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTagLine(...);
+#else
+ void setTagLine(const String& tagline);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTvShowTitle(tvshowtitle) }
+ /// Set the TV show title of the video item.
+ ///
+ /// @param tvshowtitle string - TV show title.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTvShowTitle(...);
+#else
+ void setTvShowTitle(const String& tvshowtitle);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTvShowStatus(tvshowstatus) }
+ /// Set the TV show status of the video item.
+ ///
+ /// @param status string - TV show status.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTvShowStatus(...);
+#else
+ void setTvShowStatus(const String& status);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setGenres(genre) }
+ /// Set the genres of the video item.
+ ///
+ /// @param genre list - Genres.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setGenres(...);
+#else
+ void setGenres(std::vector<String> genre);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setCountries(countries) }
+ /// Set the countries of the video item.
+ ///
+ /// @param countries list - Countries.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setCountries(...);
+#else
+ void setCountries(std::vector<String> countries);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setDirectors(directors) }
+ /// Set the directors of the video item.
+ ///
+ /// @param directors list - Directors.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDirectors(...);
+#else
+ void setDirectors(std::vector<String> directors);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setStudios(studios) }
+ /// Set the studios of the video item.
+ ///
+ /// @param studios list - Studios.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setStudios(...);
+#else
+ void setStudios(std::vector<String> studios);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setWriters(writers) }
+ /// Set the writers of the video item.
+ ///
+ /// @param writers list - Writers.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setWriters(...);
+#else
+ void setWriters(std::vector<String> writers);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setDuration(duration) }
+ /// Set the duration of the video item.
+ ///
+ /// @param duration integer - Duration in seconds.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDuration(...);
+#else
+ void setDuration(int duration);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setPremiered(premiered) }
+ /// Set the premiere date of the video item.
+ ///
+ /// @param premiered string - Premiere date.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPremiered(...);
+#else
+ void setPremiered(const String& premiered);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSet(set) }
+ /// Set the movie set (name) of the video item.
+ ///
+ /// @param set string - Movie set (name).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSet(...);
+#else
+ void setSet(const String& set);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setSetOverview(setoverview) }
+ /// Set the movie set overview of the video item.
+ ///
+ /// @param setoverview string - Movie set overview.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setSetOverview(...);
+#else
+ void setSetOverview(const String& setoverview);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTags(tags) }
+ /// Set the tags of the video item.
+ ///
+ /// @param tags list - Tags.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTags(...);
+#else
+ void setTags(std::vector<String> tags);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setProductionCode(const String& productioncode) }
+ /// Set the production code of the video item.
+ ///
+ /// @param productioncode string - Production code.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setProductionCode(...);
+#else
+ void setProductionCode(const String& productioncode);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setFirstAired(firstaired) }
+ /// Set the first aired date of the video item.
+ ///
+ /// @param firstaired string - First aired date.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setFirstAired(...);
+#else
+ void setFirstAired(const String& firstaired);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setLastPlayed(lastplayed) }
+ /// Set the last played date of the video item.
+ ///
+ /// @param lastplayed string - Last played date (YYYY-MM-DD HH:MM:SS).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setLastPlayed(...);
+#else
+ void setLastPlayed(const String& lastplayed);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setAlbum(album) }
+ /// Set the album of the video item.
+ ///
+ /// @param album string - Album.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setAlbum(...);
+#else
+ void setAlbum(const String& album);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setVotes(votes) }
+ /// Set the number of votes of the video item.
+ ///
+ /// @param votes integer - Number of votes.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setVotes(...);
+#else
+ void setVotes(int votes);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setTrailer(trailer) }
+ /// Set the trailer of the video item.
+ ///
+ /// @param trailer string - Trailer.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setTrailer(...);
+#else
+ void setTrailer(const String& trailer);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setPath(path) }
+ /// Set the path of the video item.
+ ///
+ /// @param path string - Path.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setPath(...);
+#else
+ void setPath(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setFilenameAndPath(filenameandpath) }
+ /// Set the filename and path of the video item.
+ ///
+ /// @param filenameandpath string - Filename and path.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setFilenameAndPath(...);
+#else
+ void setFilenameAndPath(const String& filenameandpath);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setIMDBNumber(imdbnumber) }
+ /// Set the IMDb number of the video item.
+ ///
+ /// @param imdbnumber string - IMDb number.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setIMDBNumber(...);
+#else
+ void setIMDBNumber(const String& imdbnumber);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setDateAdded(dateadded) }
+ /// Set the date added of the video item.
+ ///
+ /// @param dateadded string - Date added (YYYY-MM-DD HH:MM:SS).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setDateAdded(...);
+#else
+ void setDateAdded(const String& dateadded);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setMediaType(mediatype) }
+ /// Set the media type of the video item.
+ ///
+ /// @param mediatype string - Media type.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setMediaType(...);
+#else
+ void setMediaType(const String& mediatype);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setShowLinks(showlinks) }
+ /// Set the TV show links of the movie.
+ ///
+ /// @param showlinks list - TV show links.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setShowLinks(...);
+#else
+ void setShowLinks(std::vector<String> showlinks);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setArtists(artists) }
+ /// Set the artists of the music video item.
+ ///
+ /// @param artists list - Artists.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setArtists(...);
+#else
+ void setArtists(std::vector<String> artists);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setCast(actors) }
+ /// Set the cast / actors of the video item.
+ ///
+ /// @param actors list - Cast / Actors.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setCast(...);
+#else
+ void setCast(const std::vector<const Actor*>& actors);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ setResumePoint(time, [totaltime]) }
+ /// Set the resume point of the video item.
+ ///
+ /// @param time float - Resume point in seconds.
+ /// @param totaltime float - Total duration in seconds.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ setResumePoint(...);
+#else
+ void setResumePoint(double time, double totaltime = 0.0);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ addSeason(number, [name]) }
+ /// Add a season with name. It needs at least the season number.
+ ///
+ /// @param number int - the number of the season.
+ /// @param name string - the name of the season. Default "".
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # addSeason(number, name))
+ /// infotagvideo.addSeason(1, "Murder House")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addSeason(...);
+#else
+ void addSeason(int number, std::string name = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ addSeasons(namedseasons) }
+ /// Add named seasons to the TV show.
+ ///
+ /// @param namedseasons list - `[ (season, name) ]`.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ addSeasons(...);
+#else
+ void addSeasons(const std::vector<Tuple<int, std::string>>& namedseasons);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ addVideoStream(stream) }
+ /// Add a video stream to the video item.
+ ///
+ /// @param stream VideoStreamDetail - Video stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ addVideoStream(...);
+#else
+ void addVideoStream(const VideoStreamDetail* stream);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ addAudioStream(stream) }
+ /// Add an audio stream to the video item.
+ ///
+ /// @param stream AudioStreamDetail - Audio stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ addAudioStream(...);
+#else
+ void addAudioStream(const AudioStreamDetail* stream);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ addSubtitleStream(stream) }
+ /// Add a subtitle stream to the video item.
+ ///
+ /// @param stream SubtitleStreamDetail - Subtitle stream.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ addSubtitleStream(...);
+#else
+ void addSubtitleStream(const SubtitleStreamDetail* stream);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_InfoTagVideo
+ /// @brief \python_func{ addAvailableArtwork(images) }
+ /// Add an image to available artworks (needed for video scrapers)
+ ///
+ /// @param url string - image path url
+ /// @param arttype string - image type
+ /// @param preview [opt] string - image preview path url
+ /// @param referrer [opt] string - referrer url
+ /// @param cache [opt] string - filename in cache
+ /// @param post [opt] bool - use post to retrieve the image (default false)
+ /// @param isgz [opt] bool - use gzip to retrieve the image (default false)
+ /// @param season [opt] integer - number of season in case of season thumb
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// infotagvideo.addAvailableArtwork(path_to_image_1, "thumb")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addAvailableArtwork(...);
+#else
+ void addAvailableArtwork(const std::string& url,
+ const std::string& arttype = "",
+ const std::string& preview = "",
+ const std::string& referrer = "",
+ const std::string& cache = "",
+ bool post = false,
+ bool isgz = false,
+ int season = -1);
+#endif
+ /// @}
+
+#ifndef SWIG
+ static void setDbIdRaw(CVideoInfoTag* infoTag, int dbId);
+ static void setUniqueIDRaw(CVideoInfoTag* infoTag,
+ const String& uniqueID,
+ const String& type = "",
+ bool isDefault = false);
+ static void setUniqueIDsRaw(CVideoInfoTag* infoTag,
+ std::map<String, String> uniqueIDs,
+ const String& defaultUniqueID = "");
+ static void setYearRaw(CVideoInfoTag* infoTag, int year);
+ static void setEpisodeRaw(CVideoInfoTag* infoTag, int episode);
+ static void setSeasonRaw(CVideoInfoTag* infoTag, int season);
+ static void setSortEpisodeRaw(CVideoInfoTag* infoTag, int sortEpisode);
+ static void setSortSeasonRaw(CVideoInfoTag* infoTag, int sortSeason);
+ static void setEpisodeGuideRaw(CVideoInfoTag* infoTag, const String& episodeGuide);
+ static void setTop250Raw(CVideoInfoTag* infoTag, int top250);
+ static void setSetIdRaw(CVideoInfoTag* infoTag, int setId);
+ static void setTrackNumberRaw(CVideoInfoTag* infoTag, int trackNumber);
+ static void setRatingRaw(CVideoInfoTag* infoTag,
+ float rating,
+ int votes = 0,
+ const std::string& type = "",
+ bool isDefault = false);
+ static void setRatingsRaw(CVideoInfoTag* infoTag,
+ const std::map<String, Tuple<float, int>>& ratings,
+ const String& defaultRating = "");
+ static void setUserRatingRaw(CVideoInfoTag* infoTag, int userRating);
+ static void setPlaycountRaw(CVideoInfoTag* infoTag, int playcount);
+ static void setMpaaRaw(CVideoInfoTag* infoTag, const String& mpaa);
+ static void setPlotRaw(CVideoInfoTag* infoTag, const String& plot);
+ static void setPlotOutlineRaw(CVideoInfoTag* infoTag, const String& plotOutline);
+ static void setTitleRaw(CVideoInfoTag* infoTag, const String& title);
+ static void setOriginalTitleRaw(CVideoInfoTag* infoTag, const String& originalTitle);
+ static void setSortTitleRaw(CVideoInfoTag* infoTag, const String& sortTitle);
+ static void setTagLineRaw(CVideoInfoTag* infoTag, const String& tagLine);
+ static void setTvShowTitleRaw(CVideoInfoTag* infoTag, const String& tvshowTitle);
+ static void setTvShowStatusRaw(CVideoInfoTag* infoTag, const String& tvshowStatus);
+ static void setGenresRaw(CVideoInfoTag* infoTag, std::vector<String> genre);
+ static void setCountriesRaw(CVideoInfoTag* infoTag, std::vector<String> countries);
+ static void setDirectorsRaw(CVideoInfoTag* infoTag, std::vector<String> directors);
+ static void setStudiosRaw(CVideoInfoTag* infoTag, std::vector<String> studios);
+ static void setWritersRaw(CVideoInfoTag* infoTag, std::vector<String> writers);
+ static void setDurationRaw(CVideoInfoTag* infoTag, int duration);
+ static void setPremieredRaw(CVideoInfoTag* infoTag, const String& premiered);
+ static void setSetRaw(CVideoInfoTag* infoTag, const String& set);
+ static void setSetOverviewRaw(CVideoInfoTag* infoTag, const String& setOverview);
+ static void setTagsRaw(CVideoInfoTag* infoTag, std::vector<String> tags);
+ static void setProductionCodeRaw(CVideoInfoTag* infoTag, const String& productionCode);
+ static void setFirstAiredRaw(CVideoInfoTag* infoTag, const String& firstAired);
+ static void setLastPlayedRaw(CVideoInfoTag* infoTag, const String& lastPlayed);
+ static void setAlbumRaw(CVideoInfoTag* infoTag, const String& album);
+ static void setVotesRaw(CVideoInfoTag* infoTag, int votes);
+ static void setTrailerRaw(CVideoInfoTag* infoTag, const String& trailer);
+ static void setPathRaw(CVideoInfoTag* infoTag, const String& path);
+ static void setFilenameAndPathRaw(CVideoInfoTag* infoTag, const String& filenameAndPath);
+ static void setIMDBNumberRaw(CVideoInfoTag* infoTag, const String& imdbNumber);
+ static void setDateAddedRaw(CVideoInfoTag* infoTag, const String& dateAdded);
+ static void setMediaTypeRaw(CVideoInfoTag* infoTag, const String& mediaType);
+ static void setShowLinksRaw(CVideoInfoTag* infoTag, std::vector<String> showLinks);
+ static void setArtistsRaw(CVideoInfoTag* infoTag, std::vector<String> artists);
+ static void setCastRaw(CVideoInfoTag* infoTag, std::vector<SActorInfo> cast);
+ static void setResumePointRaw(CVideoInfoTag* infoTag, double time, double totalTime = 0.0);
+
+ static void addSeasonRaw(CVideoInfoTag* infoTag, int number, std::string name = "");
+ static void addSeasonsRaw(CVideoInfoTag* infoTag,
+ const std::vector<Tuple<int, std::string>>& namedSeasons);
+
+ static void addStreamRaw(CVideoInfoTag* infoTag, CStreamDetail* stream);
+ static void finalizeStreamsRaw(CVideoInfoTag* infoTag);
+
+ static void addAvailableArtworkRaw(CVideoInfoTag* infoTag,
+ const std::string& url,
+ const std::string& art_type = "",
+ const std::string& preview = "",
+ const std::string& referrer = "",
+ const std::string& cache = "",
+ bool post = false,
+ bool isgz = false,
+ int season = -1);
+#endif
+ };
+ }
+}
diff --git a/xbmc/interfaces/legacy/Keyboard.cpp b/xbmc/interfaces/legacy/Keyboard.cpp
new file mode 100644
index 0000000..2b7e08c
--- /dev/null
+++ b/xbmc/interfaces/legacy/Keyboard.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "Keyboard.h"
+
+#include "LanguageHook.h"
+#include "guilib/GUIKeyboardFactory.h"
+#include "messaging/ApplicationMessenger.h"
+#include "utils/Variant.h"
+
+using namespace KODI::MESSAGING;
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+
+ Keyboard::Keyboard(const String& line /* = nullString*/, const String& heading/* = nullString*/, bool hidden/* = false*/)
+ : strDefault(line), strHeading(heading), bHidden(hidden)
+ {
+ }
+
+ Keyboard::~Keyboard() = default;
+
+ void Keyboard::doModal(int autoclose)
+ {
+ DelayedCallGuard dg(languageHook);
+ // using keyboardfactory method to get native keyboard if there is.
+ strText = strDefault;
+ std::string text(strDefault);
+ bConfirmed = CGUIKeyboardFactory::ShowAndGetInput(text, CVariant{strHeading}, true, bHidden, autoclose * 1000);
+ strText = text;
+ }
+
+ void Keyboard::setDefault(const String& line)
+ {
+ strDefault = line;
+ }
+
+ void Keyboard::setHiddenInput(bool hidden)
+ {
+ bHidden = hidden;
+ }
+
+ void Keyboard::setHeading(const String& heading)
+ {
+ strHeading = heading;
+ }
+
+ String Keyboard::getText()
+ {
+ return strText;
+ }
+
+ bool Keyboard::isConfirmed()
+ {
+ return bConfirmed;
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/Keyboard.h b/xbmc/interfaces/legacy/Keyboard.h
new file mode 100644
index 0000000..94f6421
--- /dev/null
+++ b/xbmc/interfaces/legacy/Keyboard.h
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "AddonString.h"
+#include "Exception.h"
+
+class CGUIDialogKeyboardGeneric;
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(KeyboardException);
+
+ ///
+ /// \defgroup python_keyboard Keyboard
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's keyboard class.**
+ ///
+ /// \python_class{ xbmc.Keyboard([default, heading, hidden]) }
+ ///
+ /// Creates a new Keyboard object with default text
+ /// heading and hidden input flag if supplied.
+ ///
+ /// @param default : [opt] string - default text entry.
+ /// @param heading : [opt] string - keyboard heading.
+ /// @param hidden : [opt] boolean - True for hidden text entry.
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// kb = xbmc.Keyboard('default', 'heading', True)
+ /// kb.setDefault('password') # optional
+ /// kb.setHeading('Enter password') # optional
+ /// kb.setHiddenInput(True) # optional
+ /// kb.doModal()
+ /// if (kb.isConfirmed()):
+ /// text = kb.getText()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ class Keyboard : public AddonClass
+ {
+ public:
+#ifndef SWIG
+ String strDefault;
+ String strHeading;
+ bool bHidden;
+ String strText;
+ bool bConfirmed = false;
+#endif
+
+ Keyboard(const String& line = emptyString, const String& heading = emptyString, bool hidden = false);
+ ~Keyboard() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_keyboard
+ /// @brief \python_func{ doModal([autoclose]) }
+ /// Show keyboard and wait for user action.
+ ///
+ /// @param autoclose [opt] integer - milliseconds to autoclose
+ /// dialog. (default=do not autoclose)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// kb.doModal(30000)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ doModal(...);
+#else
+ void doModal(int autoclose = 0);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ // setDefault() Method
+ ///
+ /// \ingroup python_keyboard
+ /// @brief \python_func{ setDefault(line) }
+ /// Set the default text entry.
+ ///
+ /// @param line string - default text entry.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// kb.setDefault('password')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setDefault(...);
+#else
+ void setDefault(const String& line = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_keyboard
+ /// @brief \python_func{ setHiddenInput(hidden) }
+ /// Allows hidden text entry.
+ ///
+ /// @param hidden boolean - True for hidden text entry.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// kb.setHiddenInput(True)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setHiddenInput(...);
+#else
+ void setHiddenInput(bool hidden = false);
+#endif
+
+ // setHeading() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_keyboard
+ /// @brief \python_func{ setHeading(heading) }
+ /// Set the keyboard heading.
+ ///
+ /// @param heading string - keyboard heading.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// kb.setHeading('Enter password')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setHeading(...);
+#else
+ void setHeading(const String& heading);
+#endif
+
+ // getText() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_keyboard
+ /// @brief \python_func{ getText() }
+ /// Returns the user input as a string.
+ ///
+ /// @note This will always return the text entry even if you cancel the keyboard.
+ /// Use the isConfirmed() method to check if user cancelled the keyboard.
+ ///
+ /// @return get the in keyboard entered text
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// text = kb.getText()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getText();
+#else
+ String getText();
+#endif
+
+ // isConfirmed() Method
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_keyboard
+ /// @brief \python_func{ isConfirmed() }
+ /// Returns False if the user cancelled the input.
+ ///
+ /// @return true if confirmed, if cancelled false
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// if (kb.isConfirmed()):
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ isConfirmed();
+#else
+ bool isConfirmed();
+#endif
+ };
+ //@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/LanguageHook.cpp b/xbmc/interfaces/legacy/LanguageHook.cpp
new file mode 100644
index 0000000..c3b70c6
--- /dev/null
+++ b/xbmc/interfaces/legacy/LanguageHook.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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 "LanguageHook.h"
+
+#include "utils/GlobalsHandling.h"
+
+namespace XBMCAddon
+{
+ // just need a place for the vtab
+ LanguageHook::~LanguageHook() = default;
+
+ static thread_local LanguageHook* addonLanguageHookTls;
+ static bool threadLocalInitialized = false;
+ static xbmcutil::InitFlag initer(threadLocalInitialized);
+
+ void LanguageHook::SetLanguageHook(LanguageHook* languageHook)
+ {
+ XBMC_TRACE;
+ languageHook->Acquire();
+ addonLanguageHookTls = languageHook;
+ }
+
+ LanguageHook* LanguageHook::GetLanguageHook()
+ {
+ return threadLocalInitialized ? addonLanguageHookTls : NULL;
+ }
+
+ void LanguageHook::ClearLanguageHook()
+ {
+ LanguageHook* lh = addonLanguageHookTls;
+ addonLanguageHookTls = NULL;
+ if (lh)
+ lh->Release();
+ }
+}
diff --git a/xbmc/interfaces/legacy/LanguageHook.h b/xbmc/interfaces/legacy/LanguageHook.h
new file mode 100644
index 0000000..86abdac
--- /dev/null
+++ b/xbmc/interfaces/legacy/LanguageHook.h
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "CallbackHandler.h"
+#include "threads/Event.h"
+
+/**
+ * This class is an interface that can be used to define programming language
+ * specific hooks.
+ */
+
+class IPlayerCallback;
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ class Monitor;
+ }
+
+ class LanguageHook : public AddonClass
+ {
+ protected:
+ inline LanguageHook() = default;
+
+ public:
+ ~LanguageHook() override;
+
+ /**
+ * If the scripting language needs special handling for calls
+ * that block or are delayed in any other means, this should
+ * be overloaded.
+ *
+ * In Python when control is passed to a native
+ * method that blocks, you need to allow other threads in
+ * Python to run by using Py_BEGIN_ALLOW_THREADS. This is
+ * the place to put that functionality
+ */
+ virtual void DelayedCallOpen() { }
+
+ /**
+ * If the scripting language needs special handling for calls
+ * that block or are delayed in any other means, this should
+ * be overloaded.
+ *
+ * In Python when control is passed to a native
+ * method that blocks, you need to allow other threads in
+ * Python to run by using Py_BEGIN_ALLOW_THREADS. When that
+ * delayed method ends you need to restore the Python thread
+ * state using Py_END_ALLOW_THREADS. This is the place to put
+ * that functionality
+ */
+ virtual void DelayedCallClose() { }
+
+ virtual void MakePendingCalls() {}
+
+ /**
+ * For scripting languages that need a global callback handler, this
+ * method should be overloaded to supply one.
+ */
+ virtual CallbackHandler* GetCallbackHandler() { return NULL; }
+
+ /**
+ * This is a callback method that can be overridden to receive a callback
+ * when an AddonClass that has this language hook is on is being constructed.
+ * It is called from the constructor of AddonClass so the implementor
+ * cannot assume the subclasses have been built or that calling a
+ * virtual function on the AddonClass will work as expected.
+ */
+ virtual void Constructing(AddonClass* beingConstructed) { }
+
+ /**
+ * This is a callback method that can be overridden to receive a callback
+ * when an AddonClass that has this language hook is on is being destructed.
+ * It is called from the destructor of AddonClass so the implementor
+ * should assume the subclasses have been torn down and that calling a
+ * virtual function on the AddonClass will not work as expected.
+ */
+ virtual void Destructing(AddonClass* beingDestructed) { }
+
+ /**
+ * This method should be done a different way but since the only other way
+ * I can think to do it requires an InheritableThreadLocal C++ equivalent,
+ * I'm going to defer to this technique for now.
+ *
+ * Currently (for python) the scripting language has the Addon id injected
+ * into it as a global variable. Therefore the only way to retrieve it is
+ * to use scripting language specific calls. So until I figure out a
+ * better way to do this, this is how I need to retrieve it.
+ */
+ virtual String GetAddonId() { return emptyString; }
+ virtual String GetAddonVersion() { return emptyString; }
+ virtual long GetInvokerId() { return -1; }
+
+ virtual void RegisterPlayerCallback(IPlayerCallback* player) = 0;
+ virtual void UnregisterPlayerCallback(IPlayerCallback* player) = 0;
+ virtual void RegisterMonitorCallback(XBMCAddon::xbmc::Monitor* player) = 0;
+ virtual void UnregisterMonitorCallback(XBMCAddon::xbmc::Monitor* player) = 0;
+ virtual bool WaitForEvent(CEvent& hEvent, unsigned int milliseconds) = 0;
+
+ static void SetLanguageHook(LanguageHook* languageHook);
+ static LanguageHook* GetLanguageHook();
+ static void ClearLanguageHook();
+ };
+
+ /**
+ * This class can be used to access the language hook's DelayedCallOpen
+ * and DelayedCallClose. It should be used whenever an API method
+ * is written such that it can block for an indefinite amount of time
+ * since certain scripting languages (like Python) need to do extra
+ * work for delayed calls (like free the python locks and handle
+ * callbacks).
+ */
+ class DelayedCallGuard
+ {
+ LanguageHook* languageHook;
+ bool clearOnExit = false;
+
+ public:
+ inline explicit DelayedCallGuard(LanguageHook* languageHook_) : languageHook(languageHook_)
+ { if (languageHook) languageHook->DelayedCallOpen(); }
+
+ inline DelayedCallGuard() : languageHook(LanguageHook::GetLanguageHook())
+ { if (languageHook) languageHook->DelayedCallOpen(); }
+
+ inline ~DelayedCallGuard()
+ {
+ if (clearOnExit) LanguageHook::ClearLanguageHook();
+ if (languageHook) languageHook->DelayedCallClose();
+ }
+
+ inline LanguageHook* getLanguageHook() { return languageHook; }
+ };
+
+ class SetLanguageHookGuard
+ {
+ public:
+ inline explicit SetLanguageHookGuard(LanguageHook* languageHook) { LanguageHook::SetLanguageHook(languageHook); }
+ inline ~SetLanguageHookGuard() { LanguageHook::ClearLanguageHook(); }
+ };
+
+}
+
diff --git a/xbmc/interfaces/legacy/List.h b/xbmc/interfaces/legacy/List.h
new file mode 100644
index 0000000..932fa4e
--- /dev/null
+++ b/xbmc/interfaces/legacy/List.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <list>
+
+namespace XBMCAddon
+{
+ template <class T> class List : public std::list<T>
+ {
+ public:
+ static List<T> nullList;
+ };
+}
diff --git a/xbmc/interfaces/legacy/ListItem.cpp b/xbmc/interfaces/legacy/ListItem.cpp
new file mode 100644
index 0000000..64410ad
--- /dev/null
+++ b/xbmc/interfaces/legacy/ListItem.cpp
@@ -0,0 +1,1056 @@
+/*
+ * 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 "ListItem.h"
+
+#include "AddonUtils.h"
+#include "ServiceBroker.h"
+#include "Util.h"
+#include "games/GameTypes.h"
+#include "games/tags/GameInfoTag.h"
+#include "music/tags/MusicInfoTag.h"
+#include "pictures/PictureInfoTag.h"
+#include "settings/AdvancedSettings.h"
+#include "settings/SettingsComponent.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+#include "utils/log.h"
+#include "video/VideoInfoTag.h"
+
+#include <cstdlib>
+#include <sstream>
+#include <utility>
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ ListItem::ListItem(const String& label,
+ const String& label2,
+ const String& path,
+ bool offscreen) :
+ m_offscreen(offscreen)
+ {
+ item.reset();
+
+ // create CFileItem
+ item.reset(new CFileItem());
+ if (!item) // not sure if this is really possible
+ return;
+
+ if (!label.empty())
+ item->SetLabel( label );
+ if (!label2.empty())
+ item->SetLabel2( label2 );
+ if (!path.empty())
+ item->SetPath(path);
+ }
+
+ ListItem::~ListItem()
+ {
+ item.reset();
+ }
+
+ String ListItem::getLabel()
+ {
+ if (!item) return "";
+
+ String ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ ret = item->GetLabel();
+ }
+
+ return ret;
+ }
+
+ String ListItem::getLabel2()
+ {
+ if (!item) return "";
+
+ String ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ ret = item->GetLabel2();
+ }
+
+ return ret;
+ }
+
+ void ListItem::setLabel(const String& label)
+ {
+ if (!item) return;
+ // set label
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->SetLabel(label);
+ }
+ }
+
+ void ListItem::setLabel2(const String& label)
+ {
+ if (!item) return;
+ // set label
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->SetLabel2(label);
+ }
+ }
+
+ String ListItem::getDateTime()
+ {
+ if (!item)
+ return "";
+
+ String ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ if (item->m_dateTime.IsValid())
+ ret = item->m_dateTime.GetAsW3CDateTime();
+ }
+
+ return ret;
+ }
+
+ void ListItem::setDateTime(const String& dateTime)
+ {
+ if (!item)
+ return;
+ // set datetime
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setDateTimeRaw(dateTime);
+ }
+ }
+
+ void ListItem::setArt(const Properties& dictionary)
+ {
+ if (!item) return;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ for (const auto& it : dictionary)
+ addArtRaw(it.first, it.second);
+ }
+ }
+
+ void ListItem::setIsFolder(bool isFolder)
+ {
+ if (!item)
+ return;
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setIsFolderRaw(isFolder);
+ }
+ }
+
+ void ListItem::setUniqueIDs(const Properties& dictionary, const String& defaultrating /* = "" */)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "ListItem.setUniqueIDs() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.setUniqueIDs().");
+
+ if (!item)
+ return;
+
+ std::map<String, String> uniqueIDs;
+ for (const auto& it : dictionary)
+ uniqueIDs.emplace(it.first, it.second);
+
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::setUniqueIDsRaw(GetVideoInfoTag(), uniqueIDs, defaultrating);
+ }
+ }
+
+ void ListItem::setRating(const std::string& type,
+ float rating,
+ int votes /* = 0 */,
+ bool defaultt /* = false */)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.setRating() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.setRating().");
+
+ if (!item) return;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::setRatingRaw(GetVideoInfoTag(), rating, votes, type, defaultt);
+ }
+
+ void ListItem::addSeason(int number, std::string name /* = "" */)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.addSeason() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.addSeason().");
+
+ if (!item) return;
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::addSeasonRaw(GetVideoInfoTag(), number, std::move(name));
+ }
+
+ void ListItem::select(bool selected)
+ {
+ if (!item) return;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->Select(selected);
+ }
+ }
+
+
+ bool ListItem::isSelected()
+ {
+ if (!item) return false;
+
+ bool ret;
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ ret = item->IsSelected();
+ }
+
+ return ret;
+ }
+
+ void ListItem::setProperty(const char * key, const String& value)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ String lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+ if (lowerKey == "startoffset")
+ { // special case for start offset - don't actually store in a property
+ setStartOffsetRaw(strtod(value.c_str(), nullptr));
+ }
+ else if (lowerKey == "mimetype")
+ { // special case for mime type - don't actually stored in a property,
+ item->SetMimeType(value);
+ }
+ else if (lowerKey == "totaltime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.setProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.setResumePoint().",
+ lowerKey);
+
+ CBookmark resumePoint(GetVideoInfoTag()->GetResumePoint());
+ resumePoint.totalTimeInSeconds = atof(value.c_str());
+ GetVideoInfoTag()->SetResumePoint(resumePoint);
+ }
+ else if (lowerKey == "resumetime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.setProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.setResumePoint().",
+ lowerKey);
+
+ xbmc::InfoTagVideo::setResumePointRaw(GetVideoInfoTag(), atof(value.c_str()));
+ }
+ else if (lowerKey == "specialsort")
+ setSpecialSortRaw(value);
+ else if (lowerKey == "fanart_image")
+ item->SetArt("fanart", value);
+ else
+ addPropertyRaw(lowerKey, value);
+ }
+
+ void ListItem::setProperties(const Properties& dictionary)
+ {
+ for (const auto& it : dictionary)
+ setProperty(it.first.c_str(), it.second);
+ }
+
+ String ListItem::getProperty(const char* key)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ String lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+ std::string value;
+ if (lowerKey == "startoffset")
+ { // special case for start offset - don't actually store in a property,
+ // we store it in item.m_lStartOffset instead
+ value = StringUtils::Format("{:f}", CUtil::ConvertMilliSecsToSecs(item->GetStartOffset()));
+ }
+ else if (lowerKey == "totaltime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.getProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.getResumeTimeTotal().",
+ lowerKey);
+
+ value = StringUtils::Format("{:f}", GetVideoInfoTag()->GetResumePoint().totalTimeInSeconds);
+ }
+ else if (lowerKey == "resumetime")
+ {
+ CLog::Log(LOGWARNING,
+ "\"{}\" in ListItem.getProperty() is deprecated and might be removed in future "
+ "Kodi versions. Please use InfoTagVideo.getResumeTime().",
+ lowerKey);
+
+ value = StringUtils::Format("{:f}", GetVideoInfoTag()->GetResumePoint().timeInSeconds);
+ }
+ else if (lowerKey == "fanart_image")
+ value = item->GetArt("fanart");
+ else
+ value = item->GetProperty(lowerKey).asString();
+
+ return value;
+ }
+
+ String ListItem::getArt(const char* key)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return item->GetArt(key);
+ }
+
+ bool ListItem::isFolder() const
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return item->m_bIsFolder;
+ }
+
+ String ListItem::getUniqueID(const char* key)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "ListItem.getUniqueID() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getUniqueID().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return GetVideoInfoTag()->GetUniqueID(key);
+ }
+
+ float ListItem::getRating(const char* key)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.getRating() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getRating().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return GetVideoInfoTag()->GetRating(key).rating;
+ }
+
+ int ListItem::getVotes(const char* key)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.getVotes() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.getVotesAsInt().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return GetVideoInfoTag()->GetRating(key).votes;
+ }
+
+ void ListItem::setPath(const String& path)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setPathRaw(path);
+ }
+
+ void ListItem::setMimeType(const String& mimetype)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setMimeTypeRaw(mimetype);
+ }
+
+ void ListItem::setContentLookup(bool enable)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ setContentLookupRaw(enable);
+ }
+
+ String ListItem::getPath()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return item->GetPath();
+ }
+
+ void ListItem::setInfo(const char* type, const InfoLabelDict& infoLabels)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+
+ bool hasDeprecatedInfoLabel = false;
+ if (StringUtils::CompareNoCase(type, "video") == 0)
+ {
+ using InfoTagVideo = xbmc::InfoTagVideo;
+ auto videotag = GetVideoInfoTag();
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const InfoLabelValue& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ if (key == "count")
+ setCountRaw(strtol(value.c_str(), nullptr, 10));
+ else if (key == "size")
+ setSizeRaw(static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10)));
+ else if (key == "overlay")
+ {
+ long overlay = strtol(value.c_str(), nullptr, 10);
+ if (overlay >= 0 && overlay <= 8)
+ item->SetOverlayImage(static_cast<CGUIListItem::GUIIconOverlay>(overlay));
+ }
+ else if (key == "date")
+ setDateTimeRaw(value);
+ else
+ {
+ hasDeprecatedInfoLabel = true;
+
+ if (key == "dbid")
+ InfoTagVideo::setDbIdRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "year")
+ InfoTagVideo::setYearRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "episode")
+ InfoTagVideo::setEpisodeRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "season")
+ InfoTagVideo::setSeasonRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "sortepisode")
+ InfoTagVideo::setSortEpisodeRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "sortseason")
+ InfoTagVideo::setSortSeasonRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "episodeguide")
+ InfoTagVideo::setEpisodeGuideRaw(videotag, value);
+ else if (key == "showlink")
+ InfoTagVideo::setShowLinksRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "top250")
+ InfoTagVideo::setTop250Raw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "setid")
+ InfoTagVideo::setSetIdRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "tracknumber")
+ InfoTagVideo::setTrackNumberRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "rating")
+ InfoTagVideo::setRatingRaw(videotag,
+ static_cast<float>(strtod(value.c_str(), nullptr)));
+ else if (key == "userrating")
+ InfoTagVideo::setUserRatingRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "watched") // backward compat - do we need it?
+ InfoTagVideo::setPlaycountRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "playcount")
+ InfoTagVideo::setPlaycountRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "cast" || key == "castandrole")
+ {
+ if (alt.which() != second)
+ throw WrongTypeException("When using \"cast\" or \"castandrole\" you need to "
+ "supply a list of tuples for the value in the dictionary");
+
+ std::vector<SActorInfo> cast;
+ cast.reserve(alt.later().size());
+ for (const auto& castEntry : alt.later())
+ {
+ // castEntry can be a string meaning it's the actor or it can be a tuple meaning it's the
+ // actor and the role.
+ const String& actor =
+ castEntry.which() == first ? castEntry.former() : castEntry.later().first();
+ SActorInfo info;
+ info.strName = actor;
+ if (castEntry.which() == second)
+ info.strRole = static_cast<const String&>(castEntry.later().second());
+ cast.push_back(std::move(info));
+ }
+ InfoTagVideo::setCastRaw(videotag, std::move(cast));
+ }
+ else if (key == "artist")
+ {
+ if (alt.which() != second)
+ throw WrongTypeException("When using \"artist\" you need to supply a list of "
+ "strings for the value in the dictionary");
+
+ std::vector<String> artists;
+ artists.reserve(alt.later().size());
+ for (const auto& castEntry : alt.later())
+ {
+ auto actor =
+ castEntry.which() == first ? castEntry.former() : castEntry.later().first();
+ artists.push_back(std::move(actor));
+ }
+ InfoTagVideo::setArtistsRaw(videotag, artists);
+ }
+ else if (key == "genre")
+ InfoTagVideo::setGenresRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "country")
+ InfoTagVideo::setCountriesRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "director")
+ InfoTagVideo::setDirectorsRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "mpaa")
+ InfoTagVideo::setMpaaRaw(videotag, value);
+ else if (key == "plot")
+ InfoTagVideo::setPlotRaw(videotag, value);
+ else if (key == "plotoutline")
+ InfoTagVideo::setPlotOutlineRaw(videotag, value);
+ else if (key == "title")
+ InfoTagVideo::setTitleRaw(videotag, value);
+ else if (key == "originaltitle")
+ InfoTagVideo::setOriginalTitleRaw(videotag, value);
+ else if (key == "sorttitle")
+ InfoTagVideo::setSortTitleRaw(videotag, value);
+ else if (key == "duration")
+ InfoTagVideo::setDurationRaw(videotag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "studio")
+ InfoTagVideo::setStudiosRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "tagline")
+ InfoTagVideo::setTagLineRaw(videotag, value);
+ else if (key == "writer" || key == "credits")
+ InfoTagVideo::setWritersRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "tvshowtitle")
+ InfoTagVideo::setTvShowTitleRaw(videotag, value);
+ else if (key == "premiered")
+ InfoTagVideo::setPremieredRaw(videotag, value);
+ else if (key == "status")
+ InfoTagVideo::setTvShowStatusRaw(videotag, value);
+ else if (key == "set")
+ InfoTagVideo::setSetRaw(videotag, value);
+ else if (key == "setoverview")
+ InfoTagVideo::setSetOverviewRaw(videotag, value);
+ else if (key == "tag")
+ InfoTagVideo::setTagsRaw(videotag, getVideoStringArray(alt, key, value));
+ else if (key == "imdbnumber")
+ InfoTagVideo::setIMDBNumberRaw(videotag, value);
+ else if (key == "code")
+ InfoTagVideo::setProductionCodeRaw(videotag, value);
+ else if (key == "aired")
+ InfoTagVideo::setFirstAiredRaw(videotag, value);
+ else if (key == "lastplayed")
+ InfoTagVideo::setLastPlayedRaw(videotag, value);
+ else if (key == "album")
+ InfoTagVideo::setAlbumRaw(videotag, value);
+ else if (key == "votes")
+ InfoTagVideo::setVotesRaw(videotag, StringUtils::ReturnDigits(value));
+ else if (key == "trailer")
+ InfoTagVideo::setTrailerRaw(videotag, value);
+ else if (key == "path")
+ InfoTagVideo::setPathRaw(videotag, value);
+ else if (key == "filenameandpath")
+ InfoTagVideo::setFilenameAndPathRaw(videotag, value);
+ else if (key == "dateadded")
+ InfoTagVideo::setDateAddedRaw(videotag, value);
+ else if (key == "mediatype")
+ InfoTagVideo::setMediaTypeRaw(videotag, value);
+ else
+ CLog::Log(LOGERROR, "NEWADDON Unknown Video Info Key \"{}\"", key);
+ }
+ }
+
+ if (hasDeprecatedInfoLabel)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "Setting most video properties through ListItem.setInfo() is deprecated and might be "
+ "removed in future Kodi versions. Please use the respective setter in InfoTagVideo.");
+ }
+ }
+ else if (StringUtils::CompareNoCase(type, "music") == 0)
+ {
+ String mediaType;
+ int dbId = -1;
+
+ using InfoTagMusic = xbmc::InfoTagMusic;
+ auto musictag = GetMusicInfoTag();
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const auto& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ //! @todo add the rest of the infolabels
+ if (key == "count")
+ setCountRaw(strtol(value.c_str(), nullptr, 10));
+ else if (key == "size")
+ setSizeRaw(static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10)));
+ else if (key == "date")
+ setDateTimeRaw(value);
+ else
+ {
+ hasDeprecatedInfoLabel = true;
+
+ if (key == "dbid")
+ dbId = static_cast<int>(strtol(value.c_str(), NULL, 10));
+ else if (key == "mediatype")
+ mediaType = value;
+ else if (key == "tracknumber")
+ InfoTagMusic::setTrackRaw(musictag, strtol(value.c_str(), NULL, 10));
+ else if (key == "discnumber")
+ InfoTagMusic::setDiscRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "duration")
+ InfoTagMusic::setDurationRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "year")
+ InfoTagMusic::setYearRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "listeners")
+ InfoTagMusic::setListenersRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "playcount")
+ InfoTagMusic::setPlayCountRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "genre")
+ InfoTagMusic::setGenresRaw(musictag, getMusicStringArray(alt, key, value));
+ else if (key == "album")
+ InfoTagMusic::setAlbumRaw(musictag, value);
+ else if (key == "artist")
+ InfoTagMusic::setArtistRaw(musictag, value);
+ else if (key == "title")
+ InfoTagMusic::setTitleRaw(musictag, value);
+ else if (key == "rating")
+ InfoTagMusic::setRatingRaw(musictag,
+ static_cast<float>(strtod(value.c_str(), nullptr)));
+ else if (key == "userrating")
+ InfoTagMusic::setUserRatingRaw(musictag, strtol(value.c_str(), nullptr, 10));
+ else if (key == "lyrics")
+ InfoTagMusic::setLyricsRaw(musictag, value);
+ else if (key == "lastplayed")
+ InfoTagMusic::setLastPlayedRaw(musictag, value);
+ else if (key == "musicbrainztrackid")
+ InfoTagMusic::setMusicBrainzTrackIDRaw(musictag, value);
+ else if (key == "musicbrainzartistid")
+ InfoTagMusic::setMusicBrainzArtistIDRaw(musictag,
+ getMusicStringArray(alt, key, value));
+ else if (key == "musicbrainzalbumid")
+ InfoTagMusic::setMusicBrainzAlbumIDRaw(musictag, value);
+ else if (key == "musicbrainzalbumartistid")
+ InfoTagMusic::setMusicBrainzAlbumArtistIDRaw(musictag,
+ getMusicStringArray(alt, key, value));
+ else if (key == "comment")
+ InfoTagMusic::setCommentRaw(musictag, value);
+ else
+ CLog::Log(LOGERROR, "NEWADDON Unknown Music Info Key \"{}\"", key);
+ }
+
+ // This should probably be set outside of the loop but since the original
+ // implementation set it inside of the loop, I'll leave it that way. - Jim C.
+ musictag->SetLoaded(true);
+ }
+
+ if (dbId > 0 && !mediaType.empty())
+ InfoTagMusic::setDbIdRaw(musictag, dbId, mediaType);
+
+ if (hasDeprecatedInfoLabel)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "Setting most music properties through ListItem.setInfo() is deprecated and might be "
+ "removed in future Kodi versions. Please use the respective setter in InfoTagMusic.");
+ }
+ }
+ else if (StringUtils::CompareNoCase(type, "pictures") == 0)
+ {
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const auto& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ if (key == "count")
+ setCountRaw(strtol(value.c_str(), nullptr, 10));
+ else if (key == "size")
+ setSizeRaw(static_cast<int64_t>(strtoll(value.c_str(), nullptr, 10)));
+ else if (key == "title")
+ setTitleRaw(value);
+ else if (key == "picturepath")
+ setPathRaw(value);
+ else if (key == "date")
+ setDateTimeRaw(value);
+ else
+ {
+ hasDeprecatedInfoLabel = true;
+
+ String exifkey = key;
+ if (!StringUtils::StartsWithNoCase(exifkey, "exif:") || exifkey.length() < 6)
+ {
+ CLog::Log(LOGWARNING, "ListItem.setInfo: unknown pictures info key \"{}\"", key);
+ continue;
+ }
+
+ exifkey = StringUtils::Mid(exifkey, 5);
+ if (exifkey == "resolution")
+ xbmc::InfoTagPicture::setResolutionRaw(item->GetPictureInfoTag(), value);
+ else if (exifkey == "exiftime")
+ xbmc::InfoTagPicture::setDateTimeTakenRaw(item->GetPictureInfoTag(), value);
+ else
+ CLog::Log(LOGWARNING, "ListItem.setInfo: unknown pictures info key \"{}\"", key);
+ }
+ }
+
+ if (hasDeprecatedInfoLabel)
+ {
+ CLog::Log(LOGWARNING, "Setting most picture properties through ListItem.setInfo() is "
+ "deprecated and might be removed in future Kodi versions. Please "
+ "use the respective setter in InfoTagPicture.");
+ }
+ }
+ else if (StringUtils::EqualsNoCase(type, "game"))
+ {
+ auto gametag = item->GetGameInfoTag();
+ for (const auto& it : infoLabels)
+ {
+ const auto key = StringUtils::ToLower(it.first);
+ const auto& alt = it.second;
+ const String value(alt.which() == first ? alt.former() : emptyString);
+
+ if (key == "title")
+ {
+ setTitleRaw(value);
+ xbmc::InfoTagGame::setTitleRaw(gametag, value);
+ }
+ else if (key == "platform")
+ xbmc::InfoTagGame::setPlatformRaw(gametag, value);
+ else if (key == "genres")
+ xbmc::InfoTagGame::setGenresRaw(gametag, getStringArray(alt, key, value, ","));
+ else if (key == "publisher")
+ xbmc::InfoTagGame::setPublisherRaw(gametag, value);
+ else if (key == "developer")
+ xbmc::InfoTagGame::setDeveloperRaw(gametag, value);
+ else if (key == "overview")
+ xbmc::InfoTagGame::setOverviewRaw(gametag, value);
+ else if (key == "year")
+ xbmc::InfoTagGame::setYearRaw(gametag, strtoul(value.c_str(), nullptr, 10));
+ else if (key == "gameclient")
+ xbmc::InfoTagGame::setGameClientRaw(gametag, value);
+ }
+
+ if (!infoLabels.empty())
+ {
+ CLog::Log(
+ LOGWARNING,
+ "Setting game properties through ListItem.setInfo() is deprecated and might be "
+ "removed in future Kodi versions. Please use the respective setter in InfoTagGame.");
+ }
+ }
+ else
+ CLog::Log(LOGWARNING, "ListItem.setInfo: unknown \"type\" parameter value: {}", type);
+ } // end ListItem::setInfo
+
+ void ListItem::setCast(const std::vector<Properties>& actors)
+ {
+ CLog::Log(LOGWARNING,
+ "ListItem.setCast() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.setCast().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ std::vector<SActorInfo> cast;
+ cast.reserve(actors.size());
+ for (const auto& dictionary : actors)
+ {
+ SActorInfo info;
+ for (auto it = dictionary.begin(); it != dictionary.end(); ++it)
+ {
+ const String& key = it->first;
+ const String& value = it->second;
+ if (key == "name")
+ info.strName = value;
+ else if (key == "role")
+ info.strRole = value;
+ else if (key == "thumbnail")
+ {
+ info.thumbUrl = CScraperUrl(value);
+ if (!info.thumbUrl.GetFirstThumbUrl().empty())
+ info.thumb = CScraperUrl::GetThumbUrl(info.thumbUrl.GetFirstUrlByType());
+ }
+ else if (key == "order")
+ info.order = strtol(value.c_str(), nullptr, 10);
+ }
+ cast.push_back(std::move(info));
+ }
+ xbmc::InfoTagVideo::setCastRaw(GetVideoInfoTag(), std::move(cast));
+ }
+
+ void ListItem::setAvailableFanart(const std::vector<Properties>& images)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ auto infoTag = GetVideoInfoTag();
+ infoTag->m_fanart.Clear();
+ for (const auto& dictionary : images)
+ {
+ std::string image;
+ std::string preview;
+ std::string colors;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String& value = it.second;
+ if (key == "image")
+ image = value;
+ else if (key == "preview")
+ preview = value;
+ else if (key == "colors")
+ colors = value;
+ }
+ infoTag->m_fanart.AddFanart(image, preview, colors);
+ }
+ infoTag->m_fanart.Pack();
+ }
+
+ void ListItem::addAvailableArtwork(const std::string& url,
+ const std::string& art_type,
+ const std::string& preview,
+ const std::string& referrer,
+ const std::string& cache,
+ bool post,
+ bool isgz,
+ int season)
+ {
+ CLog::Log(LOGWARNING, "ListItem.addAvailableArtwork() is deprecated and might be removed in "
+ "future Kodi versions. Please use InfoTagVideo.addAvailableArtwork().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ xbmc::InfoTagVideo::addAvailableArtworkRaw(GetVideoInfoTag(), url, art_type, preview,
+ referrer, cache, post, isgz, season);
+ }
+
+ void ListItem::addStreamInfo(const char* cType, const Properties& dictionary)
+ {
+ CLog::Log(
+ LOGWARNING,
+ "ListItem.addStreamInfo() is deprecated and might be removed in future Kodi versions. "
+ "Please use InfoTagVideo.addVideoStream(), InfoTagVideo.addAudioStream() and "
+ "InfoTagVideo.addSubtitleStream().");
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+
+ auto infoTag = GetVideoInfoTag();
+ if (StringUtils::CompareNoCase(cType, "video") == 0)
+ {
+ CStreamDetailVideo* video = new CStreamDetailVideo;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String value(it.second.c_str());
+
+ if (key == "codec")
+ video->m_strCodec = value;
+ else if (key == "aspect")
+ video->m_fAspect = static_cast<float>(atof(value.c_str()));
+ else if (key == "width")
+ video->m_iWidth = strtol(value.c_str(), nullptr, 10);
+ else if (key == "height")
+ video->m_iHeight = strtol(value.c_str(), nullptr, 10);
+ else if (key == "duration")
+ video->m_iDuration = strtol(value.c_str(), nullptr, 10);
+ else if (key == "stereomode")
+ video->m_strStereoMode = value;
+ else if (key == "language")
+ video->m_strLanguage = value;
+ }
+ xbmc::InfoTagVideo::addStreamRaw(infoTag, video);
+ }
+ else if (StringUtils::CompareNoCase(cType, "audio") == 0)
+ {
+ CStreamDetailAudio* audio = new CStreamDetailAudio;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String& value = it.second;
+
+ if (key == "codec")
+ audio->m_strCodec = value;
+ else if (key == "language")
+ audio->m_strLanguage = value;
+ else if (key == "channels")
+ audio->m_iChannels = strtol(value.c_str(), nullptr, 10);
+ }
+ xbmc::InfoTagVideo::addStreamRaw(infoTag, audio);
+ }
+ else if (StringUtils::CompareNoCase(cType, "subtitle") == 0)
+ {
+ CStreamDetailSubtitle* subtitle = new CStreamDetailSubtitle;
+ for (const auto& it : dictionary)
+ {
+ const String& key = it.first;
+ const String& value = it.second;
+
+ if (key == "language")
+ subtitle->m_strLanguage = value;
+ }
+ xbmc::InfoTagVideo::addStreamRaw(infoTag, subtitle);
+ }
+ xbmc::InfoTagVideo::finalizeStreamsRaw(infoTag);
+ } // end ListItem::addStreamInfo
+
+ void ListItem::addContextMenuItems(const std::vector<Tuple<String,String> >& items, bool replaceItems /* = false */)
+ {
+ for (size_t i = 0; i < items.size(); ++i)
+ {
+ auto& tuple = items[i];
+ if (tuple.GetNumValuesSet() != 2)
+ throw ListItemException("Must pass in a list of tuples of pairs of strings. One entry in the list only has %d elements.",tuple.GetNumValuesSet());
+
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ item->SetProperty(StringUtils::Format("contextmenulabel({})", i), tuple.first());
+ item->SetProperty(StringUtils::Format("contextmenuaction({})", i), tuple.second());
+ }
+ }
+
+ void ListItem::setSubtitles(const std::vector<String>& paths)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ addSubtitlesRaw(paths);
+ }
+
+ xbmc::InfoTagVideo* ListItem::getVideoInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagVideo(GetVideoInfoTag(), m_offscreen);
+ }
+
+ xbmc::InfoTagMusic* ListItem::getMusicInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagMusic(GetMusicInfoTag(), m_offscreen);
+ }
+
+ xbmc::InfoTagPicture* ListItem::getPictureInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagPicture(item->GetPictureInfoTag(), m_offscreen);
+ }
+
+ xbmc::InfoTagGame* ListItem::getGameInfoTag()
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, m_offscreen);
+ return new xbmc::InfoTagGame(item->GetGameInfoTag(), m_offscreen);
+ }
+
+ std::vector<std::string> ListItem::getStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value,
+ const std::string& separator)
+ {
+ if (alt.which() == first)
+ {
+ if (value.empty())
+ value = alt.former();
+ return StringUtils::Split(value, separator);
+ }
+
+ std::vector<std::string> els;
+ for (const auto& el : alt.later())
+ {
+ if (el.which() == second)
+ throw WrongTypeException("When using \"%s\" you need to supply a string or list of strings for the value in the dictionary", tag.c_str());
+ els.emplace_back(el.former());
+ }
+ return els;
+ }
+
+ std::vector<std::string> ListItem::getVideoStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value /* = "" */)
+ {
+ return getStringArray(
+ alt, tag, std::move(value),
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoItemSeparator);
+ }
+
+ std::vector<std::string> ListItem::getMusicStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value /* = "" */)
+ {
+ return getStringArray(
+ alt, tag, std::move(value),
+ CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_musicItemSeparator);
+ }
+
+ CVideoInfoTag* ListItem::GetVideoInfoTag()
+ {
+ return item->GetVideoInfoTag();
+ }
+
+ const CVideoInfoTag* ListItem::GetVideoInfoTag() const
+ {
+ return item->GetVideoInfoTag();
+ }
+
+ MUSIC_INFO::CMusicInfoTag* ListItem::GetMusicInfoTag()
+ {
+ return item->GetMusicInfoTag();
+ }
+
+ const MUSIC_INFO::CMusicInfoTag* ListItem::GetMusicInfoTag() const
+ {
+ return item->GetMusicInfoTag();
+ }
+
+ void ListItem::setTitleRaw(std::string title)
+ {
+ item->m_strTitle = std::move(title);
+ }
+
+ void ListItem::setPathRaw(const std::string& path)
+ {
+ item->SetPath(path);
+ }
+
+ void ListItem::setCountRaw(int count)
+ {
+ item->m_iprogramCount = count;
+ }
+
+ void ListItem::setSizeRaw(int64_t size)
+ {
+ item->m_dwSize = size;
+ }
+
+ void ListItem::setDateTimeRaw(const std::string& dateTime)
+ {
+ if (dateTime.length() == 10)
+ {
+ int year = strtol(dateTime.substr(dateTime.size() - 4).c_str(), nullptr, 10);
+ int month = strtol(dateTime.substr(3, 4).c_str(), nullptr, 10);
+ int day = strtol(dateTime.substr(0, 2).c_str(), nullptr, 10);
+ item->m_dateTime.SetDate(year, month, day);
+ }
+ else
+ item->m_dateTime.SetFromW3CDateTime(dateTime);
+ }
+
+ void ListItem::setIsFolderRaw(bool isFolder)
+ {
+ item->m_bIsFolder = isFolder;
+ }
+
+ void ListItem::setStartOffsetRaw(double startOffset)
+ {
+ // we store the offset in frames, or 1/75th of a second
+ item->SetStartOffset(CUtil::ConvertSecsToMilliSecs(startOffset));
+ }
+
+ void ListItem::setMimeTypeRaw(const std::string& mimetype)
+ {
+ item->SetMimeType(mimetype);
+ }
+
+ void ListItem::setSpecialSortRaw(std::string specialSort)
+ {
+ StringUtils::ToLower(specialSort);
+
+ if (specialSort == "bottom")
+ item->SetSpecialSort(SortSpecialOnBottom);
+ else if (specialSort == "top")
+ item->SetSpecialSort(SortSpecialOnTop);
+ }
+
+ void ListItem::setContentLookupRaw(bool enable)
+ {
+ item->SetContentLookup(enable);
+ }
+
+ void ListItem::addArtRaw(std::string type, const std::string& url)
+ {
+ StringUtils::ToLower(type);
+ item->SetArt(type, url);
+ }
+
+ void ListItem::addPropertyRaw(std::string type, const CVariant& value)
+ {
+ StringUtils::ToLower(type);
+ item->SetProperty(type, value);
+ }
+
+ void ListItem::addSubtitlesRaw(const std::vector<std::string>& subtitles)
+ {
+ for (size_t i = 0; i < subtitles.size(); ++i)
+ // subtitle:{} index starts from 1
+ addPropertyRaw(StringUtils::Format("subtitle:{}", i + 1), subtitles[i]);
+ }
+ }
+}
diff --git a/xbmc/interfaces/legacy/ListItem.h b/xbmc/interfaces/legacy/ListItem.h
new file mode 100644
index 0000000..82513e0
--- /dev/null
+++ b/xbmc/interfaces/legacy/ListItem.h
@@ -0,0 +1,1291 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "AddonString.h"
+#include "Alternative.h"
+#include "Dictionary.h"
+#include "FileItem.h"
+#include "InfoTagGame.h"
+#include "InfoTagMusic.h"
+#include "InfoTagPicture.h"
+#include "InfoTagVideo.h"
+#include "ListItem.h"
+#include "Tuple.h"
+#include "commons/Exception.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(ListItemException);
+
+ // This is a type that represents either a String or a String Tuple
+ typedef Alternative<StringOrInt,Tuple<String, StringOrInt> > InfoLabelStringOrTuple;
+
+ // This type is either a String or a list of InfoLabelStringOrTuple types
+ typedef Alternative<StringOrInt, std::vector<InfoLabelStringOrTuple> > InfoLabelValue;
+
+ // The type contains the dictionary values for the ListItem::setInfo call.
+ // The values in the dictionary can be either a String, or a list of items.
+ // If it's a list of items then the items can be either a String or a Tuple.
+ typedef Dictionary<InfoLabelValue> InfoLabelDict;
+
+ //
+ /// \defgroup python_xbmcgui_listitem ListItem
+ /// \ingroup python_xbmcgui
+ /// @{
+ /// @brief **Selectable window list item.**
+ ///
+ class ListItem : public AddonClass
+ {
+ public:
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ CFileItemPtr item;
+ bool m_offscreen;
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief Selectable window list item.
+ ///
+ /// The list item control is used for creating item lists in Kodi
+ ///
+ /// \python_class{ ListItem([label, label2, path, offscreen]) }
+ ///
+ /// @param label [opt] string (default `""`) - the label to display on the item
+ /// @param label2 [opt] string (default `""`) - the label2 of the item
+ /// @param path [opt] string (default `""`) - the path for the item
+ /// @param offscreen [opt] bool (default `False`) - if GUI based locks should be
+ /// avoided. Most of the times listitems are created
+ /// offscreen and added later to a container
+ /// for display (e.g. plugins) or they are not
+ /// even displayed (e.g. python scrapers).
+ /// In such cases, there is no need to lock the
+ /// GUI when creating the items (increasing your addon
+ /// performance).
+ /// Note however, that if you are creating listitems
+ /// and managing the container itself (e.g using
+ /// WindowXML or WindowXMLDialog classes) subsquent
+ /// modifications to the item will require locking.
+ /// Thus, in such cases, use the default value (`False`).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v16 **iconImage** and **thumbnailImage** are deprecated. Use **setArt()**.
+ /// @python_v18 Added **offscreen** argument.
+ /// @python_v19 Removed **iconImage** and **thumbnailImage**. Use **setArt()**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem = xbmcgui.ListItem('Casino Royale')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ ListItem([label, label2, path, offscreen]);
+#else
+ ListItem(const String& label = emptyString,
+ const String& label2 = emptyString,
+ const String& path = emptyString,
+ bool offscreen = false);
+#endif
+
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ inline explicit ListItem(CFileItemPtr pitem) : item(std::move(pitem)), m_offscreen(false) {}
+
+ static inline AddonClass::Ref<ListItem> fromString(const String& str)
+ {
+ AddonClass::Ref<ListItem> ret = AddonClass::Ref<ListItem>(new ListItem());
+ ret->item.reset(new CFileItem(str));
+ return ret;
+ }
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ ~ListItem() override;
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getLabel() }
+ /// Returns the listitem label.
+ ///
+ /// @return Label of item
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getLabel()
+ /// label = listitem.getLabel()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getLabel();
+#else
+ String getLabel();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getLabel2() }
+ /// Returns the second listitem label.
+ ///
+ /// @return Second label of item
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getLabel2()
+ /// label = listitem.getLabel2()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getLabel2();
+#else
+ String getLabel2();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setLabel(label) }
+ /// Sets the listitem's label.
+ ///
+ /// @param label string or unicode - text string.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setLabel(label)
+ /// listitem.setLabel('Casino Royale')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setLabel(...);
+#else
+ void setLabel(const String& label);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setLabel2(label) }
+ /// Sets the listitem's label2.
+ ///
+ /// @param label string or unicode - text string.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setLabel2(label)
+ /// listitem.setLabel2('Casino Royale')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setLabel2(...);
+#else
+ void setLabel2(const String& label);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getDateTime() }
+ /// Returns the list item's datetime in W3C format (YYYY-MM-DDThh:mm:ssTZD).
+ ///
+ /// @return string or unicode - datetime string (W3C).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # getDateTime()
+ /// strDateTime = listitem.getDateTime()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getDateTime();
+#else
+ String getDateTime();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setDateTime(dateTime) }
+ /// Sets the list item's datetime in W3C format.
+ /// The following formats are supported:
+ /// - YYYY
+ /// - YYYY-MM-DD
+ /// - YYYY-MM-DDThh:mm[TZD]
+ /// - YYYY-MM-DDThh:mm:ss[TZD]
+ /// where the timezone (TZD) is always optional and can be in one of the
+ /// following formats:
+ /// - Z (for UTC)
+ /// - +hh:mm
+ /// - -hh:mm
+ ///
+ /// @param label string or unicode - datetime string (W3C).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setDate(dateTime)
+ /// listitem.setDateTime('2021-03-09T12:30:00Z')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setDateTime(...);
+#else
+ void setDateTime(const String& dateTime);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setArt(values) }
+ /// Sets the listitem's art
+ ///
+ /// @param values dictionary - pairs of `{ label: value }`.
+ /// - Some default art values (any string possible):
+ /// | Label | Type |
+ /// |:-------------:|:--------------------------------------------------|
+ /// | thumb | string - image filename
+ /// | poster | string - image filename
+ /// | banner | string - image filename
+ /// | fanart | string - image filename
+ /// | clearart | string - image filename
+ /// | clearlogo | string - image filename
+ /// | landscape | string - image filename
+ /// | icon | string - image filename
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13 New function added.
+ /// @python_v16 Added new label **icon**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setArt(values)
+ /// listitem.setArt({ 'poster': 'poster.png', 'banner' : 'banner.png' })
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setArt(...);
+#else
+ void setArt(const Properties& dictionary);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setIsFolder(isFolder) }
+ /// Sets if this listitem is a folder.
+ ///
+ /// @param isFolder bool - True=folder / False=not a folder (default).
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setIsFolder(isFolder)
+ /// listitem.setIsFolder(True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setIsFolder(...);
+#else
+ void setIsFolder(bool isFolder);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setUniqueIDs(values, defaultrating) }
+ /// Sets the listitem's uniqueID
+ ///
+ /// @param values dictionary - pairs of `{ label: value }`.
+ /// @param defaultrating [opt] string - the name of default rating.
+ ///
+ /// - Some example values (any string possible):
+ /// | Label | Type |
+ /// |:-------------:|:--------------------------------------------------|
+ /// | imdb | string - uniqueid name
+ /// | tvdb | string - uniqueid name
+ /// | tmdb | string - uniqueid name
+ /// | anidb | string - uniqueid name
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **InfoTagVideo.setUniqueIDs()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setUniqueIDs(values, defaultrating)
+ /// listitem.setUniqueIDs({ 'imdb': 'tt8938399', 'tmdb' : '9837493' }, "imdb")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setUniqueIDs(...);
+#else
+ void setUniqueIDs(const Properties& dictionary, const String& defaultrating = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setRating(type, rating, votes = 0, defaultt = False) }
+ /// Sets a listitem's rating. It needs at least type and rating param
+ ///
+ /// @param type string - the type of the rating. Any string.
+ /// @param rating float - the value of the rating.
+ /// @param votes int - the number of votes. Default 0.
+ /// @param defaultt bool - is the default rating?. Default False.
+ /// - Some example type (any string possible):
+ /// | Label | Type |
+ /// |:-------------:|:--------------------------------------------------|
+ /// | imdb | string - rating type
+ /// | tvdb | string - rating type
+ /// | tmdb | string - rating type
+ /// | anidb | string - rating type
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **InfoTagVideo.setRating()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setRating(type, rating, votes, defaultt))
+ /// listitem.setRating("imdb", 4.6, 8940, True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setRating(...);
+#else
+ void setRating(const std::string& type, float rating, int votes = 0, bool defaultt = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ addSeason(number, name = "") }
+ /// Add a season with name to a listitem. It needs at least the season number
+ ///
+ /// @param number int - the number of the season.
+ /// @param name string - the name of the season. Default "".
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// @python_v18 New function added.
+ /// @python_v20 Deprecated. Use **InfoTagVideo.addSeason()** or **InfoTagVideo.addSeasons()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # addSeason(number, name))
+ /// listitem.addSeason(1, "Murder House")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addSeason(...);
+#else
+ void addSeason(int number, std::string name = "");
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getArt(key) }
+ /// Returns a listitem art path as a string, similar to an infolabel.\n
+ ///
+ /// @param key string - art name.
+ /// - Some default art values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | thumb | string - image path
+ /// | poster | string - image path
+ /// | banner | string - image path
+ /// | fanart | string - image path
+ /// | clearart | string - image path
+ /// | clearlogo | string - image path
+ /// | landscape | string - image path
+ /// | icon | string - image path
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// poster = listitem.getArt('poster')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getArt(key);
+#else
+ String getArt(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ isFolder() }
+ /// Returns whether the item is a folder or not.
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// isFolder = listitem.isFolder()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ isFolder();
+#else
+ bool isFolder() const;
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getUniqueID(key) }
+ /// Returns a listitem uniqueID as a string, similar to an infolabel.\n
+ ///
+ /// @param key string - uniqueID name.
+ /// - Some default uniqueID values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | imdb | string - uniqueid name
+ /// | tvdb | string - uniqueid name
+ /// | tmdb | string - uniqueid name
+ /// | anidb | string - uniqueid name
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **InfoTagVideo.getUniqueID()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// uniqueID = listitem.getUniqueID('imdb')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getUniqueID(key);
+#else
+ String getUniqueID(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getRating(key) }
+ /// Returns a listitem rating as a float.\n
+ ///
+ /// @param key string - rating type.
+ /// - Some default key values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | imdb | string - type name
+ /// | tvdb | string - type name
+ /// | tmdb | string - type name
+ /// | anidb | string - type name
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **InfoTagVideo.getRating()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// rating = listitem.getRating('imdb')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getRating(key);
+#else
+ float getRating(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getVotes(key) }
+ /// Returns a listitem votes as a integer.\n
+ ///
+ /// @param key string - rating type.
+ /// - Some default key values (any string possible):
+ /// | Label | Type |
+ /// |---------------|--------------------------------------------------|
+ /// | imdb | string - type name
+ /// | tvdb | string - type name
+ /// | tmdb | string - type name
+ /// | anidb | string - type name
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **InfoTagVideo.getVotesAsInt()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// votes = listitem.getVotes('imdb')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getVotes(key);
+#else
+ int getVotes(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ select(selected) }
+ /// Sets the listitem's selected status.
+ ///
+ /// @param selected bool - True=selected/False=not selected
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # select(selected)
+ /// listitem.select(True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ select(...);
+#else
+ void select(bool selected);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ isSelected() }
+ /// Returns the listitem's selected status.
+ ///
+ ///
+ /// @return bool - true if selected, otherwise false
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # isSelected()
+ /// selected = listitem.isSelected()
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ isSelected();
+#else
+ bool isSelected();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setInfo(type, infoLabels) }
+ /// Sets the listitem's infoLabels.
+ ///
+ /// @param type string - type of info labels
+ /// @param infoLabels dictionary - pairs of `{ label: value }`
+ ///
+ /// __Available types__
+ /// | Command name | Description |
+ /// |:------------:|:----------------------|
+ /// | video | Video information
+ /// | music | Music information
+ /// | pictures | Pictures informanion
+ /// | game | Game information
+ ///
+ /// @note To set pictures exif info, prepend `exif:` to the label. Exif values must be passed
+ /// as strings, separate value pairs with a comma. <b>(eg. <c>{'exif:resolution': '720,480'}</c></b>
+ /// See \ref kodi_pictures_infotag for valid strings.\n
+ /// \n
+ /// You can use the above as keywords for arguments and skip certain optional arguments.
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ /// __General Values__ (that apply to all types):
+ /// | Info label | Description |
+ /// |--------------:|:---------------------------------------------------|
+ /// | count | integer (12) - can be used to store an id for later, or for sorting purposes
+ /// | size | long (1024) - size in bytes
+ /// | date | string (%d.%m.%Y / 01.01.2009) - file date
+ ///
+ /// __Video Values__:
+ /// | Info label | Description |
+ /// |--------------:|:---------------------------------------------------|
+ /// | genre | string (Comedy) or list of strings (["Comedy", "Animation", "Drama"])
+ /// | country | string (Germany) or list of strings (["Germany", "Italy", "France"])
+ /// | year | integer (2009)
+ /// | episode | integer (4)
+ /// | season | integer (1)
+ /// | sortepisode | integer (4)
+ /// | sortseason | integer (1)
+ /// | episodeguide | string (Episode guide)
+ /// | showlink | string (Battlestar Galactica) or list of strings (["Battlestar Galactica", "Caprica"])
+ /// | top250 | integer (192)
+ /// | setid | integer (14)
+ /// | tracknumber | integer (3)
+ /// | rating | float (6.4) - range is 0..10
+ /// | userrating | integer (9) - range is 1..10 (0 to reset)
+ /// | watched | deprecated - use playcount instead
+ /// | playcount | integer (2) - number of times this item has been played
+ /// | overlay | integer (2) - range is `0..7`. See \ref kodi_guilib_listitem_iconoverlay "Overlay icon types" for values
+ /// | cast | list (["Michal C. Hall","Jennifer Carpenter"]) - if provided a list of tuples cast will be interpreted as castandrole
+ /// | castandrole | list of tuples ([("Michael C. Hall","Dexter"),("Jennifer Carpenter","Debra")])
+ /// | director | string (Dagur Kari) or list of strings (["Dagur Kari", "Quentin Tarantino", "Chrstopher Nolan"])
+ /// | mpaa | string (PG-13)
+ /// | plot | string (Long Description)
+ /// | plotoutline | string (Short Description)
+ /// | title | string (Big Fan)
+ /// | originaltitle | string (Big Fan)
+ /// | sorttitle | string (Big Fan)
+ /// | duration | integer (245) - duration in seconds
+ /// | studio | string (Warner Bros.) or list of strings (["Warner Bros.", "Disney", "Paramount"])
+ /// | tagline | string (An awesome movie) - short description of movie
+ /// | writer | string (Robert D. Siegel) or list of strings (["Robert D. Siegel", "Jonathan Nolan", "J.K. Rowling"])
+ /// | tvshowtitle | string (Heroes)
+ /// | premiered | string (2005-03-04)
+ /// | status | string (Continuing) - status of a TVshow
+ /// | set | string (Batman Collection) - name of the collection
+ /// | setoverview | string (All Batman movies) - overview of the collection
+ /// | tag | string (cult) or list of strings (["cult", "documentary", "best movies"]) - movie tag
+ /// | imdbnumber | string (tt0110293) - IMDb code
+ /// | code | string (101) - Production code
+ /// | aired | string (2008-12-07)
+ /// | credits | string (Andy Kaufman) or list of strings (["Dagur Kari", "Quentin Tarantino", "Chrstopher Nolan"]) - writing credits
+ /// | lastplayed | string (%Y-%m-%d %h:%m:%s = 2009-04-05 23:16:04)
+ /// | album | string (The Joshua Tree)
+ /// | artist | list (['U2'])
+ /// | votes | string (12345 votes)
+ /// | path | string (/home/user/movie.avi)
+ /// | trailer | string (/home/user/trailer.avi)
+ /// | dateadded | string (%Y-%m-%d %h:%m:%s = 2009-04-05 23:16:04)
+ /// | mediatype | string - "video", "movie", "tvshow", "season", "episode" or "musicvideo"
+ /// | dbid | integer (23) - Only add this for items which are part of the local db. You also need to set the correct 'mediatype'!
+ ///
+ /// __Music Values__:
+ /// | Info label | Description |
+ /// |-------------------------:|:---------------------------------------------------|
+ /// | tracknumber | integer (8)
+ /// | discnumber | integer (2)
+ /// | duration | integer (245) - duration in seconds
+ /// | year | integer (1998)
+ /// | genre | string (Rock)
+ /// | album | string (Pulse)
+ /// | artist | string (Muse)
+ /// | title | string (American Pie)
+ /// | rating | float - range is between 0 and 10
+ /// | userrating | integer - range is 1..10
+ /// | lyrics | string (On a dark desert highway...)
+ /// | playcount | integer (2) - number of times this item has been played
+ /// | lastplayed | string (%Y-%m-%d %h:%m:%s = 2009-04-05 23:16:04)
+ /// | mediatype | string - "music", "song", "album", "artist"
+ /// | dbid | integer (23) - Only add this for items which are part of the local db. You also need to set the correct 'mediatype'!
+ /// | listeners | integer (25614)
+ /// | musicbrainztrackid | string (cd1de9af-0b71-4503-9f96-9f5efe27923c)
+ /// | musicbrainzartistid | string (d87e52c5-bb8d-4da8-b941-9f4928627dc8)
+ /// | musicbrainzalbumid | string (24944755-2f68-3778-974e-f572a9e30108)
+ /// | musicbrainzalbumartistid | string (d87e52c5-bb8d-4da8-b941-9f4928627dc8)
+ /// | comment | string (This is a great song)
+ ///
+ /// __Picture Values__:
+ /// | Info label | Description |
+ /// |--------------:|:---------------------------------------------------|
+ /// | title | string (In the last summer-1)
+ /// | picturepath | string (`/home/username/pictures/img001.jpg`)
+ /// | exif* | string (See \ref kodi_pictures_infotag for valid strings)
+ ///
+ /// __Game Values__:
+ /// | Info label | Description |
+ /// |--------------:|:---------------------------------------------------|
+ /// | title | string (Super Mario Bros.)
+ /// | platform | string (Atari 2600)
+ /// | genres | list (["Action","Strategy"])
+ /// | publisher | string (Nintendo)
+ /// | developer | string (Square)
+ /// | overview | string (Long Description)
+ /// | year | integer (1980)
+ /// | gameclient | string (game.libretro.fceumm)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 Added new label **discnumber**.
+ /// @python_v15 **duration** has to be set in seconds.
+ /// @python_v16 Added new label **mediatype**.
+ /// @python_v17
+ /// Added labels **setid**, **set**, **imdbnumber**, **code**, **dbid** (video), **path** and **userrating**.
+ /// Expanded the possible infoLabels for the option **mediatype**.
+ /// @python_v18 Added new **game** type and associated infolabels.
+ /// Added labels **dbid** (music), **setoverview**, **tag**, **sortepisode**, **sortseason**, **episodeguide**, **showlink**.
+ /// Extended labels **genre**, **country**, **director**, **studio**, **writer**, **tag**, **credits** to also use a list of strings.
+ /// @python_v20 Partially deprecated. Use explicit setters in **InfoTagVideo**, **InfoTagMusic**, **InfoTagPicture** or **InfoTagGame** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.setInfo('video', { 'genre': 'Comedy' })
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setInfo(...);
+#else
+ void setInfo(const char* type, const InfoLabelDict& infoLabels);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setCast(actors) }
+ /// Set cast including thumbnails
+ ///
+ /// @param actors list of dictionaries (see below for relevant keys)
+ ///
+ /// - Keys:
+ /// | Label | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | name | string (Michael C. Hall)
+ /// | role | string (Dexter)
+ /// | thumbnail | string (http://www.someurl.com/someimage.png)
+ /// | order | integer (1)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ /// @python_v20 Deprecated. Use **InfoTagVideo.setCast()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// actors = [{"name": "Actor 1", "role": "role 1"}, {"name": "Actor 2", "role": "role 2"}]
+ /// listitem.setCast(actors)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setCast(...);
+#else
+ void setCast(const std::vector<Properties>& actors);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setAvailableFanart(images) }
+ /// Set available images (needed for video scrapers)
+ ///
+ /// @param images list of dictionaries (see below for relevant keys)
+ ///
+ /// - Keys:
+ /// | Label | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | image | string (http://www.someurl.com/someimage.png)
+ /// | preview | [opt] string (http://www.someurl.com/somepreviewimage.png)
+ /// | colors | [opt] string (either comma separated Kodi hex values ("FFFFFFFF,DDDDDDDD") or TVDB RGB Int Triplets ("|68,69,59|69,70,58|78,78,68|"))
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// fanart = [{"image": path_to_image_1, "preview": path_to_preview_1}, {"image": path_to_image_2, "preview": path_to_preview_2}]
+ /// listitem.setAvailableFanart(fanart)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setAvailableFanart(...);
+#else
+ void setAvailableFanart(const std::vector<Properties>& images);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ addAvailableArtwork(images) }
+ /// Add an image to available artworks (needed for video scrapers)
+ ///
+ /// @param url string (image path url)
+ /// @param art_type string (image type)
+ /// @param preview [opt] string (image preview path url)
+ /// @param referrer [opt] string (referrer url)
+ /// @param cache [opt] string (filename in cache)
+ /// @param post [opt] bool (use post to retrieve the image, default false)
+ /// @param isgz [opt] bool (use gzip to retrieve the image, default false)
+ /// @param season [opt] integer (number of season in case of season thumb)
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ /// @python_v19 New param added (preview).
+ /// @python_v20 Deprecated. Use **InfoTagVideo.addAvailableArtwork()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.addAvailableArtwork(path_to_image_1, "thumb")
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addAvailableArtwork(...);
+#else
+ void addAvailableArtwork(const std::string& url,
+ const std::string& art_type = "",
+ const std::string& preview = "",
+ const std::string& referrer = "",
+ const std::string& cache = "",
+ bool post = false,
+ bool isgz = false,
+ int season = -1);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ addStreamInfo(type, values) }
+ /// Add a stream with details.
+ ///
+ /// @param type string - type of stream(video/audio/subtitle).
+ /// @param values dictionary - pairs of { label: value }.
+ ///
+ /// - Video Values:
+ /// | Label | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | codec | string (h264)
+ /// | aspect | float (1.78)
+ /// | width | integer (1280)
+ /// | height | integer (720)
+ /// | duration | integer (seconds)
+ ///
+ /// - Audio Values:
+ /// | Label | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | codec | string (dts)
+ /// | language | string (en)
+ /// | channels | integer (2)
+ ///
+ /// - Subtitle Values:
+ /// | Label | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | language | string (en)
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 Deprecated. Use **InfoTagVideo.addVideoStream()**, **InfoTagVideo.addAudioStream()** or **InfoTagVideo.addSubtitleStream()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.addStreamInfo('video', { 'codec': 'h264', 'width' : 1280 })
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addStreamInfo(...);
+#else
+ void addStreamInfo(const char* cType, const Properties& dictionary);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ addContextMenuItems([(label, action),*]) }
+ /// Adds item(s) to the context menu for media lists.
+ ///
+ /// @param items list - [(label, action),*] A list of tuples consisting of label and action pairs.
+ /// - label string or unicode - item's label.
+ /// - action string or unicode - any available \link page_List_of_built_in_functions built-in function \endlink .
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 Completely removed previously available argument **replaceItems**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.addContextMenuItems([('Theater Showtimes', 'RunScript(script.myaddon,title=Iron Man)')])
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ addContextMenuItems(...);
+#else
+ void addContextMenuItems(const std::vector<Tuple<String,String> >& items, bool replaceItems = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setProperty(key, value) }
+ /// Sets a listitem property, similar to an infolabel.
+ ///
+ /// @param key string - property name.
+ /// @param value string or unicode - value of property.
+ ///
+ /// @note Key is NOT case sensitive.\n
+ /// You can use the above as keywords for arguments and skip certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.\n
+ /// \n
+ /// Some of these are treated internally by Kodi, such as the 'StartOffset' property, which is
+ /// the offset in seconds at which to start playback of an item. Others may be used in the skin
+ /// to add extra information, such as 'WatchedCount' for tvshow items
+ ///
+ /// - **Internal Properties**
+ /// | Key | Description |
+ /// |--------------:|:------------------------------------------------|
+ /// | inputstream | string (inputstream.adaptive) - Set the inputstream add-on that will be used to play the item
+ /// | IsPlayable | string - "true", "false" - Mark the item as playable, **mandatory for playable items**
+ /// | MimeType | string (application/x-mpegURL) - Set the MimeType of the item before playback
+ /// | ResumeTime | float (1962.0) - Set the resume point of the item in seconds
+ /// | SpecialSort | string - "top", "bottom" - The item will remain at the top or bottom of the current list
+ /// | StartOffset | float (60.0) - Set the offset in seconds at which to start playback of the item
+ /// | StartPercent | float (15.0) - Set the percentage at which to start playback of the item
+ /// | StationName | string ("My Station Name") - Used to enforce/override MusicPlayer.StationName infolabel from addons (e.g. in radio addons)
+ /// | TotalTime | float (7848.0) - Set the total time of the item in seconds
+ /// | OverrideInfotag | string - "true", "false" - When true will override all info from previous listitem
+ /// | ForceResolvePlugin | string - "true", "false" - When true ensures that a plugin will always receive callbacks to resolve paths (useful for playlist cases)
+ /// | rtsp_transport | string - "udp", "udp_multicast" or "tcp" - Allow to force the rtsp transport mode for rtsp streams
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 OverrideInfotag property added
+ /// @python_v20 **ResumeTime** and **TotalTime** deprecated. Use **InfoTagVideo.setResumePoint()** instead.
+ /// @python_v20 ForceResolvePlugin property added
+ /// @python_v20 rtsp_transport property added
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.setProperty('AspectRatio', '1.85 : 1')
+ /// listitem.setProperty('StartOffset', '256.4')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setProperty(...);
+#else
+ void setProperty(const char * key, const String& value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setProperties(values) }
+ /// Sets multiple properties for listitem's
+ ///
+ /// @param values dictionary - pairs of `{ label: value }`.
+ ///
+ /// @python_v18 New function added.
+ ///
+ ///-----------------------------------------------------------------------
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// # setProperties(values)
+ /// listitem.setProperties({ 'AspectRatio': '1.85', 'StartOffset' : '256.4' })
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setProperties(...);
+#else
+ void setProperties(const Properties& dictionary);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getProperty(key) }
+ /// Returns a listitem property as a string, similar to an infolabel.
+ ///
+ /// @param key string - property name.
+ ///
+ /// @note Key is NOT case sensitive.\n
+ /// You can use the above as keywords for arguments and skip certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 **ResumeTime** and **TotalTime** deprecated. Use **InfoTagVideo.getResumeTime()** and **InfoTagVideo.getResumeTimeTotal()** instead.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// AspectRatio = listitem.getProperty('AspectRatio')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ getProperty(...);
+#else
+ String getProperty(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setPath(path) }
+ /// Sets the listitem's path.
+ ///
+ /// @param path string or unicode - path, activated when item is clicked.
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.setPath(path='/path/to/some/file.ext')
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setPath(...);
+#else
+ void setPath(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setMimeType(mimetype) }
+ /// Sets the listitem's mimetype if known.
+ ///
+ /// @param mimetype string or unicode - mimetype
+ ///
+ /// If known prehand, this can (but does not have to) avoid HEAD requests
+ /// being sent to HTTP servers to figure out file type.
+ ///
+ setMimeType(...);
+#else
+ void setMimeType(const String& mimetype);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setContentLookup(enable) }
+ /// Enable or disable content lookup for item.
+ ///
+ /// If disabled, HEAD requests to e.g determine mime type will not be sent.
+ ///
+ /// @param enable bool to enable content lookup
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v16 New function added.
+ ///
+ setContentLookup(...);
+#else
+ void setContentLookup(bool enable);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ setSubtitles(subtitleFiles) }
+ /// Sets subtitles for this listitem.
+ ///
+ /// @param subtitleFiles list with path to subtitle files
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem.setSubtitles(['special://temp/example.srt', 'http://example.com/example.srt'])
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ setSubtitles(...);
+#else
+ void setSubtitles(const std::vector<String>& subtitleFiles);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getPath() }
+ /// Returns the path of this listitem.
+ ///
+ /// @return [string] filename
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 New function added.
+ ///
+ ///
+ getPath();
+#else
+ String getPath();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getVideoInfoTag() }
+ /// Returns the VideoInfoTag for this item.
+ ///
+ /// @return video info tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v15 New function added.
+ ///
+ getVideoInfoTag();
+#else
+ xbmc::InfoTagVideo* getVideoInfoTag();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getMusicInfoTag() }
+ /// Returns the MusicInfoTag for this item.
+ ///
+ /// @return music info tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v15 New function added.
+ ///
+ getMusicInfoTag();
+#else
+ xbmc::InfoTagMusic* getMusicInfoTag();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getPictureInfoTag() }
+ /// Returns the InfoTagPicture for this item.
+ ///
+ /// @return picture info tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getPictureInfoTag();
+#else
+ xbmc::InfoTagPicture* getPictureInfoTag();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_listitem
+ /// @brief \python_func{ getGameInfoTag() }
+ /// Returns the InfoTagGame for this item.
+ ///
+ /// @return game info tag
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getGameInfoTag();
+#else
+ xbmc::InfoTagGame* getGameInfoTag();
+#endif
+
+private:
+ std::vector<std::string> getStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value,
+ const std::string& separator);
+ std::vector<std::string> getVideoStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value = "");
+ std::vector<std::string> getMusicStringArray(const InfoLabelValue& alt,
+ const std::string& tag,
+ std::string value = "");
+
+ CVideoInfoTag* GetVideoInfoTag();
+ const CVideoInfoTag* GetVideoInfoTag() const;
+
+ MUSIC_INFO::CMusicInfoTag* GetMusicInfoTag();
+ const MUSIC_INFO::CMusicInfoTag* GetMusicInfoTag() const;
+
+ void setTitleRaw(std::string title);
+ void setPathRaw(const std::string& path);
+ void setCountRaw(int count);
+ void setSizeRaw(int64_t size);
+ void setDateTimeRaw(const std::string& dateTime);
+ void setIsFolderRaw(bool isFolder);
+ void setStartOffsetRaw(double startOffset);
+ void setMimeTypeRaw(const std::string& mimetype);
+ void setSpecialSortRaw(std::string specialSort);
+ void setContentLookupRaw(bool enable);
+ void addArtRaw(std::string type, const std::string& url);
+ void addPropertyRaw(std::string type, const CVariant& value);
+ void addSubtitlesRaw(const std::vector<std::string>& subtitles);
+ };
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ typedef std::vector<ListItem*> ListItemList;
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp
new file mode 100644
index 0000000..b9e4c05
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp
@@ -0,0 +1,600 @@
+/*
+ * 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.
+ */
+
+//! @todo Need a uniform way of returning an error status
+
+#include "ModuleXbmc.h"
+
+#include "AddonUtils.h"
+#include "FileItem.h"
+#include "GUIInfoManager.h"
+#include "LangInfo.h"
+#include "LanguageHook.h"
+#include "ServiceBroker.h"
+#include "Util.h"
+#include "aojsonrpc.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPowerHandling.h"
+#include "cores/AudioEngine/Interfaces/AE.h"
+#include "guilib/GUIAudioManager.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/LocalizeStrings.h"
+#include "guilib/TextureManager.h"
+#include "input/WindowTranslator.h"
+#include "messaging/ApplicationMessenger.h"
+#include "network/Network.h"
+#include "network/NetworkServices.h"
+#include "playlists/PlayListTypes.h"
+#include "settings/Settings.h"
+#include "settings/SettingsComponent.h"
+#include "storage/MediaManager.h"
+#include "storage/discs/IDiscDriveHandler.h"
+#include "threads/SystemClock.h"
+#include "utils/Crc32.h"
+#include "utils/ExecString.h"
+#include "utils/FileExtensionProvider.h"
+#include "utils/FileUtils.h"
+#include "utils/LangCodeExpander.h"
+#include "utils/MemUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/SystemInfo.h"
+#include "utils/XTimeUtils.h"
+#include "utils/log.h"
+
+#include <vector>
+
+using namespace KODI;
+
+namespace XBMCAddon
+{
+
+ namespace xbmc
+ {
+ /*****************************************************************
+ * start of xbmc methods
+ *****************************************************************/
+ void log(const char* msg, int level)
+ {
+ // check for a valid loglevel
+ if (level < LOGDEBUG || level > LOGNONE)
+ level = LOGDEBUG;
+ CLog::Log(level, "{}", msg);
+ }
+
+ void shutdown()
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_SHUTDOWN);
+ }
+
+ void restart()
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_RESTART);
+ }
+
+ void executescript(const char* script)
+ {
+ XBMC_TRACE;
+ if (! script)
+ return;
+
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_EXECUTE_SCRIPT, -1, -1, nullptr, script);
+ }
+
+ void executebuiltin(const char* function, bool wait /* = false*/)
+ {
+ XBMC_TRACE;
+ if (! function)
+ return;
+
+ // builtins is no anarchy
+ // enforce some rules here
+ // DialogBusy must not be activated, it is modal dialog
+ const CExecString exec(function);
+ if (!exec.IsValid())
+ return;
+
+ const std::string execute = exec.GetFunction();
+ const std::vector<std::string> params = exec.GetParams();
+
+ if (StringUtils::EqualsNoCase(execute, "activatewindow") ||
+ StringUtils::EqualsNoCase(execute, "closedialog"))
+ {
+ int win = CWindowTranslator::TranslateWindow(params[0]);
+ if (win == WINDOW_DIALOG_BUSY)
+ {
+ CLog::Log(LOGWARNING, "addons must not activate DialogBusy");
+ return;
+ }
+ }
+
+ if (wait)
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr,
+ function);
+ else
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr,
+ function);
+ }
+
+ String executeJSONRPC(const char* jsonrpccommand)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg;
+ String ret;
+
+ if (! jsonrpccommand)
+ return ret;
+
+ // String method = jsonrpccommand;
+
+ CAddOnTransport transport;
+ CAddOnTransport::CAddOnClient client;
+
+ return JSONRPC::CJSONRPC::MethodCall(/*method*/ jsonrpccommand, &transport, &client);
+ }
+
+ void sleep(long timemillis)
+ {
+ XBMC_TRACE;
+
+ XbmcThreads::EndTime<> endTime{std::chrono::milliseconds(timemillis)};
+ while (!endTime.IsTimePast())
+ {
+ LanguageHook* lh = NULL;
+ {
+ DelayedCallGuard dcguard;
+ lh = dcguard.getLanguageHook(); // borrow this
+ long nextSleep = endTime.GetTimeLeft().count();
+ if (nextSleep > 100)
+ nextSleep = 100; // only sleep for 100 millis
+ KODI::TIME::Sleep(std::chrono::milliseconds(nextSleep));
+ }
+ if (lh != NULL)
+ lh->MakePendingCalls();
+ }
+ }
+
+ String getLocalizedString(int id)
+ {
+ XBMC_TRACE;
+ String label;
+ if (id >= 30000 && id <= 30999)
+ label = g_localizeStringsTemp.Get(id);
+ else if (id >= 32000 && id <= 32999)
+ label = g_localizeStringsTemp.Get(id);
+ else
+ label = g_localizeStrings.Get(id);
+
+ return label;
+ }
+
+ String getSkinDir()
+ {
+ XBMC_TRACE;
+ return CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOOKANDFEEL_SKIN);
+ }
+
+ String getLanguage(int format /* = CLangCodeExpander::ENGLISH_NAME */, bool region /*= false*/)
+ {
+ XBMC_TRACE;
+ std::string lang = g_langInfo.GetEnglishLanguageName();
+
+ switch (format)
+ {
+ case CLangCodeExpander::ENGLISH_NAME:
+ {
+ if (region)
+ {
+ std::string region = "-" + g_langInfo.GetCurrentRegion();
+ return (lang += region);
+ }
+ return lang;
+ }
+ case CLangCodeExpander::ISO_639_1:
+ {
+ std::string langCode;
+ g_LangCodeExpander.ConvertToISO6391(lang, langCode);
+ if (region)
+ {
+ std::string region = g_langInfo.GetRegionLocale();
+ std::string region2Code;
+ g_LangCodeExpander.ConvertToISO6391(region, region2Code);
+ region2Code = "-" + region2Code;
+ return (langCode += region2Code);
+ }
+ return langCode;
+ }
+ case CLangCodeExpander::ISO_639_2:
+ {
+ std::string langCode;
+ g_LangCodeExpander.ConvertToISO6392B(lang, langCode);
+ if (region)
+ {
+ std::string region = g_langInfo.GetRegionLocale();
+ std::string region3Code;
+ g_LangCodeExpander.ConvertToISO6392B(region, region3Code);
+ region3Code = "-" + region3Code;
+ return (langCode += region3Code);
+ }
+
+ return langCode;
+ }
+ default:
+ return "";
+ }
+ }
+
+ String getIPAddress()
+ {
+ XBMC_TRACE;
+ char cTitleIP[32];
+ sprintf(cTitleIP, "127.0.0.1");
+ CNetworkInterface* iface = CServiceBroker::GetNetwork().GetFirstConnectedInterface();
+ if (iface)
+ return iface->GetCurrentIPAddress();
+
+ return cTitleIP;
+ }
+
+ long getDVDState()
+ {
+ XBMC_TRACE;
+ return static_cast<long>(CServiceBroker::GetMediaManager().GetDriveStatus());
+ }
+
+ long getFreeMem()
+ {
+ XBMC_TRACE;
+ KODI::MEMORY::MemoryStatus stat;
+ KODI::MEMORY::GetMemoryStatus(&stat);
+ return static_cast<long>(stat.availPhys / ( 1024 * 1024 ));
+ }
+
+ // getCpuTemp() method
+ // ## Doesn't work right, use getInfoLabel('System.CPUTemperature') instead.
+ /*PyDoc_STRVAR(getCpuTemp__doc__,
+ "getCpuTemp() -- Returns the current cpu temperature as an integer."
+ ""
+ "example:"
+ " - cputemp = xbmc.getCpuTemp()");
+
+ PyObject* XBMC_GetCpuTemp(PyObject *self, PyObject *args)
+ {
+ unsigned short cputemp;
+ unsigned short cpudec;
+
+ _outp(0xc004, (0x4c<<1)|0x01);
+ _outp(0xc008, 0x01);
+ _outpw(0xc000, _inpw(0xc000));
+ _outp(0xc002, (0) ? 0x0b : 0x0a);
+ while ((_inp(0xc000) & 8));
+ cputemp = _inpw(0xc006);
+
+ _outp(0xc004, (0x4c<<1)|0x01);
+ _outp(0xc008, 0x10);
+ _outpw(0xc000, _inpw(0xc000));
+ _outp(0xc002, (0) ? 0x0b : 0x0a);
+ while ((_inp(0xc000) & 8));
+ cpudec = _inpw(0xc006);
+
+ if (cpudec<10) cpudec = cpudec * 100;
+ if (cpudec<100) cpudec = cpudec *10;
+
+ return PyInt_FromLong((long)(cputemp + cpudec / 1000.0f));
+ }*/
+
+ String getInfoLabel(const char* cLine)
+ {
+ XBMC_TRACE;
+ if (!cLine)
+ {
+ String ret;
+ return ret;
+ }
+
+ CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
+ int ret = infoMgr.TranslateString(cLine);
+ //doesn't seem to be a single InfoTag?
+ //try full blown GuiInfoLabel then
+ if (ret == 0)
+ return GUILIB::GUIINFO::CGUIInfoLabel::GetLabel(cLine, INFO::DEFAULT_CONTEXT);
+ else
+ return infoMgr.GetLabel(ret, INFO::DEFAULT_CONTEXT);
+ }
+
+ String getInfoImage(const char * infotag)
+ {
+ XBMC_TRACE;
+ if (!infotag)
+ {
+ String ret;
+ return ret;
+ }
+
+ CGUIInfoManager& infoMgr = CServiceBroker::GetGUI()->GetInfoManager();
+ int ret = infoMgr.TranslateString(infotag);
+ return infoMgr.GetImage(ret, WINDOW_INVALID);
+ }
+
+ void playSFX(const char* filename, bool useCached)
+ {
+ XBMC_TRACE;
+ if (!filename)
+ return;
+
+ CGUIComponent* gui = CServiceBroker::GetGUI();
+ if (CFileUtils::Exists(filename) && gui)
+ {
+ gui->GetAudioManager().PlayPythonSound(filename,useCached);
+ }
+ }
+
+ void stopSFX()
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg;
+ CGUIComponent* gui = CServiceBroker::GetGUI();
+ if (gui)
+ gui->GetAudioManager().Stop();
+ }
+
+ void enableNavSounds(bool yesNo)
+ {
+ XBMC_TRACE;
+ CGUIComponent* gui = CServiceBroker::GetGUI();
+ if (gui)
+ gui->GetAudioManager().Enable(yesNo);
+ }
+
+ bool getCondVisibility(const char *condition)
+ {
+ XBMC_TRACE;
+ if (!condition)
+ return false;
+
+ bool ret;
+ {
+ XBMCAddonUtils::GuiLock lock(nullptr, false);
+
+ int id = CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog();
+ if (id == WINDOW_INVALID)
+ id = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
+ ret = CServiceBroker::GetGUI()->GetInfoManager().EvaluateBool(condition,id);
+ }
+
+ return ret;
+ }
+
+ int getGlobalIdleTime()
+ {
+ XBMC_TRACE;
+ auto& components = CServiceBroker::GetAppComponents();
+ const auto appPower = components.GetComponent<CApplicationPowerHandling>();
+ return appPower->GlobalIdleTime();
+ }
+
+ String getCacheThumbName(const String& path)
+ {
+ XBMC_TRACE;
+ auto crc = Crc32::ComputeFromLowerCase(path);
+ return StringUtils::Format("{:08x}.tbn", crc);
+ }
+
+ Tuple<String,String> getCleanMovieTitle(const String& path, bool usefoldername)
+ {
+ XBMC_TRACE;
+ CFileItem item(path, false);
+ std::string strName = item.GetMovieName(usefoldername);
+
+ std::string strTitleAndYear;
+ std::string strTitle;
+ std::string strYear;
+ CUtil::CleanString(strName, strTitle, strTitleAndYear, strYear, usefoldername);
+ return Tuple<String,String>(strTitle,strYear);
+ }
+
+ String getRegion(const char* id)
+ {
+ XBMC_TRACE;
+ std::string result;
+
+ if (StringUtils::CompareNoCase(id, "datelong") == 0)
+ {
+ result = g_langInfo.GetDateFormat(true);
+ StringUtils::Replace(result, "DDDD", "%A");
+ StringUtils::Replace(result, "MMMM", "%B");
+ StringUtils::Replace(result, "D", "%d");
+ StringUtils::Replace(result, "YYYY", "%Y");
+ }
+ else if (StringUtils::CompareNoCase(id, "dateshort") == 0)
+ {
+ result = g_langInfo.GetDateFormat(false);
+ StringUtils::Replace(result, "MM", "%m");
+ StringUtils::Replace(result, "DD", "%d");
+#ifdef TARGET_WINDOWS
+ StringUtils::Replace(result, "M", "%#m");
+ StringUtils::Replace(result, "D", "%#d");
+#else
+ StringUtils::Replace(result, "M", "%-m");
+ StringUtils::Replace(result, "D", "%-d");
+#endif
+ StringUtils::Replace(result, "YYYY", "%Y");
+ }
+ else if (StringUtils::CompareNoCase(id, "tempunit") == 0)
+ result = g_langInfo.GetTemperatureUnitString();
+ else if (StringUtils::CompareNoCase(id, "speedunit") == 0)
+ result = g_langInfo.GetSpeedUnitString();
+ else if (StringUtils::CompareNoCase(id, "time") == 0)
+ {
+ result = g_langInfo.GetTimeFormat();
+ if (StringUtils::StartsWith(result, "HH"))
+ StringUtils::Replace(result, "HH", "%H");
+ else
+ StringUtils::Replace(result, "H", "%H");
+ StringUtils::Replace(result, "h", "%I");
+ StringUtils::Replace(result, "mm", "%M");
+ StringUtils::Replace(result, "ss", "%S");
+ StringUtils::Replace(result, "xx", "%p");
+ }
+ else if (StringUtils::CompareNoCase(id, "meridiem") == 0)
+ result = StringUtils::Format("{}/{}", g_langInfo.GetMeridiemSymbol(MeridiemSymbolAM),
+ g_langInfo.GetMeridiemSymbol(MeridiemSymbolPM));
+
+ return result;
+ }
+
+ //! @todo Add a mediaType enum
+ String getSupportedMedia(const char* mediaType)
+ {
+ XBMC_TRACE;
+ String result;
+ if (StringUtils::CompareNoCase(mediaType, "video") == 0)
+ result = CServiceBroker::GetFileExtensionProvider().GetVideoExtensions();
+ else if (StringUtils::CompareNoCase(mediaType, "music") == 0)
+ result = CServiceBroker::GetFileExtensionProvider().GetMusicExtensions();
+ else if (StringUtils::CompareNoCase(mediaType, "picture") == 0)
+ result = CServiceBroker::GetFileExtensionProvider().GetPictureExtensions();
+
+ //! @todo implement
+ // else
+ // return an error
+
+ return result;
+ }
+
+ bool skinHasImage(const char* image)
+ {
+ XBMC_TRACE;
+ return CServiceBroker::GetGUI()->GetTextureManager().HasTexture(image);
+ }
+
+
+ bool startServer(int iTyp, bool bStart)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg;
+ return CServiceBroker::GetNetwork().GetServices().StartServer(
+ static_cast<CNetworkServices::ESERVERS>(iTyp), bStart != 0);
+ }
+
+ void audioSuspend()
+ {
+ IAE *ae = CServiceBroker::GetActiveAE();
+ if (ae)
+ ae->Suspend();
+ }
+
+ void audioResume()
+ {
+ IAE *ae = CServiceBroker::GetActiveAE();
+ if (ae)
+ ae->Resume();
+ }
+
+ String convertLanguage(const char* language, int format)
+ {
+ std::string convertedLanguage;
+ switch (format)
+ {
+ case CLangCodeExpander::ENGLISH_NAME:
+ {
+ g_LangCodeExpander.Lookup(language, convertedLanguage);
+ // maybe it's a check whether the language exists or not
+ if (convertedLanguage.empty())
+ {
+ g_LangCodeExpander.ConvertToISO6392B(language, convertedLanguage);
+ g_LangCodeExpander.Lookup(convertedLanguage, convertedLanguage);
+ }
+ break;
+ }
+ case CLangCodeExpander::ISO_639_1:
+ g_LangCodeExpander.ConvertToISO6391(language, convertedLanguage);
+ break;
+ case CLangCodeExpander::ISO_639_2:
+ g_LangCodeExpander.ConvertToISO6392B(language, convertedLanguage);
+ break;
+ default:
+ return "";
+ }
+ return convertedLanguage;
+ }
+
+ String getUserAgent()
+ {
+ return CSysInfo::GetUserAgent();
+ }
+
+ int getSERVER_WEBSERVER()
+ {
+ return CNetworkServices::ES_WEBSERVER;
+ }
+ int getSERVER_AIRPLAYSERVER()
+ {
+ return CNetworkServices::ES_AIRPLAYSERVER;
+ }
+ int getSERVER_UPNPSERVER()
+ {
+ return CNetworkServices::ES_UPNPSERVER;
+ }
+ int getSERVER_UPNPRENDERER()
+ {
+ return CNetworkServices::ES_UPNPRENDERER;
+ }
+ int getSERVER_EVENTSERVER()
+ {
+ return CNetworkServices::ES_EVENTSERVER;
+ }
+ int getSERVER_JSONRPCSERVER()
+ {
+ return CNetworkServices::ES_JSONRPCSERVER;
+ }
+ int getSERVER_ZEROCONF()
+ {
+ return CNetworkServices::ES_ZEROCONF;
+ }
+
+ int getPLAYLIST_MUSIC()
+ {
+ return PLAYLIST::TYPE_MUSIC;
+ }
+ int getPLAYLIST_VIDEO()
+ {
+ return PLAYLIST::TYPE_VIDEO;
+ }
+ int getTRAY_OPEN()
+ {
+ return static_cast<int>(TrayState::OPEN);
+ }
+ int getDRIVE_NOT_READY()
+ {
+ return static_cast<int>(DriveState::NOT_READY);
+ }
+ int getTRAY_CLOSED_NO_MEDIA()
+ {
+ return static_cast<int>(TrayState::CLOSED_NO_MEDIA);
+ }
+ int getTRAY_CLOSED_MEDIA_PRESENT()
+ {
+ return static_cast<int>(TrayState::CLOSED_MEDIA_PRESENT);
+ }
+ int getLOGDEBUG() { return LOGDEBUG; }
+ int getLOGINFO() { return LOGINFO; }
+ int getLOGWARNING() { return LOGWARNING; }
+ int getLOGERROR() { return LOGERROR; }
+ int getLOGFATAL() { return LOGFATAL; }
+ int getLOGNONE() { return LOGNONE; }
+
+ // language string formats
+ int getISO_639_1() { return CLangCodeExpander::ISO_639_1; }
+ int getISO_639_2(){ return CLangCodeExpander::ISO_639_2; }
+ int getENGLISH_NAME() { return CLangCodeExpander::ENGLISH_NAME; }
+
+ const int lLOGDEBUG = LOGDEBUG;
+ }
+}
diff --git a/xbmc/interfaces/legacy/ModuleXbmc.h b/xbmc/interfaces/legacy/ModuleXbmc.h
new file mode 100644
index 0000000..0720d8a
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmc.h
@@ -0,0 +1,898 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonString.h"
+#include "Tuple.h"
+
+#include "utils/LangCodeExpander.h"
+#include "swighelper.h"
+#include <vector>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+#ifndef SWIG
+ // This is a bit of a hack to get around a SWIG problem
+ extern const int lLOGDEBUG;
+#endif
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+ //
+ /// \defgroup python_xbmc Library - xbmc
+ /// @{
+ /// @brief **General functions on Kodi.**
+ ///
+ /// Offers classes and functions that provide information about the media
+ /// currently playing and that allow manipulation of the media player (such
+ /// as starting a new song). You can also find system information using the
+ /// functions available in this library.
+ //
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.log(msg[, level]) }
+ /// Write a string to Kodi's log file and the debug window.
+ ///
+ /// @param msg string - text to output.
+ /// @param level [opt] integer - log level to output at.
+ /// <em>(default=LOGDEBUG)</em>
+ /// | Value: | Description: |
+ /// |----------------:|---------------------------------------------------|
+ /// | xbmc.LOGDEBUG | In depth information about the status of Kodi. This information can pretty much only be deciphered by a developer or long time Kodi power user.
+ /// | xbmc.LOGINFO | Something has happened. It's not a problem, we just thought you might want to know. Fairly excessive output that most people won't care about.
+ /// | xbmc.LOGWARNING | Something potentially bad has happened. If Kodi did something you didn't expect, this is probably why. Watch for errors to follow.
+ /// | xbmc.LOGERROR | This event is bad. Something has failed. You likely noticed problems with the application be it skin artifacts, failure of playback a crash, etc.
+ /// | xbmc.LOGFATAL | We're screwed. Kodi is about to crash.
+ ///
+ /// @note Addon developers are advised to keep `LOGDEBUG` as the default
+ /// logging level and to use conservative logging (log only if needed).
+ /// Excessive logging makes it harder to debug kodi itself.
+ ///
+ /// Logging in kodi has a global configuration level that controls how text
+ /// is written to the log. This global logging behaviour can be changed in
+ /// the GUI (**Settings -> System -> Logging**) (debug toggle) or furthered
+ /// configured in advancedsettings (loglevel setting).
+ ///
+ /// Text is written to the log for the following conditions:
+ /// - loglevel == -1 (NONE, nothing at all is logged to the log)
+ /// - loglevel == 0 (NORMAL, shows `LOGINFO`, `LOGWARNING`, `LOGERROR` and `LOGFATAL`) - Default kodi behaviour
+ /// - loglevel == 1 (DEBUG, shows all) - Behaviour if you toggle debug log in the GUI
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v17 Default level changed from `LOGNOTICE` to `LOGDEBUG`
+ /// @python_v19 Removed `LOGNOTICE` (use `LOGINFO`) and `LOGSEVERE` (use `LOGFATAL`)
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.log(msg='This is a test string.', level=xbmc.LOGDEBUG);
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ log(...);
+#else
+ void log(const char* msg, int level = lLOGDEBUG);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.shutdown() }
+ /// Shutdown the htpc.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.shutdown()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ shutdown();
+#else
+ void shutdown();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.restart() }
+ /// Restart the htpc.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.restart()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ restart();
+#else
+ void restart();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.executescript(script) }
+ /// Execute a python script.
+ ///
+ /// @param script string - script filename to execute.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.executescript('special://home/scripts/update.py')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ executescript(...);
+#else
+ void executescript(const char* script);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.executebuiltin(function) }
+ /// Execute a built in Kodi function.
+ ///
+ /// @param function string - builtin function to execute.
+ /// @param wait [opt] bool - If Kodi should wait for the
+ /// builtin function execution to finish
+ /// (default False)
+ ///
+ ///
+ /// \ref page_List_of_built_in_functions "List of builtin functions"
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.executebuiltin('Skin.SetString(abc,def)')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ executebuiltin(...);
+#else
+ void executebuiltin(const char* function, bool wait = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.executeJSONRPC(jsonrpccommand) }
+ /// Execute an JSONRPC command.
+ ///
+ /// @param jsonrpccommand string - jsonrpc command to execute.
+ /// @return jsonrpc return string
+ ///
+ ///
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// response = xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "method": "JSONRPC.Introspect", "id": 1 }')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ executeJSONRPC(...);
+#else
+ String executeJSONRPC(const char* jsonrpccommand);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.sleep(time) }
+ /// Sleeps for 'time' (msec).
+ /// \anchor xbmc_Sleep
+ ///
+ /// @param time integer - number of msec to sleep.
+ ///
+ /// @throws PyExc_TypeError If time is not an integer.
+ ///
+ /// @warning This is useful if you need to sleep for a small amount of time
+ /// (milisecond range) somewhere in your addon logic. Please note that Kodi
+ /// will attempt to stop any running scripts when signaled to exit and wait for a maximum
+ /// of 5 seconds before trying to force stop your script. If your addon makes use
+ /// of \ref xbmc_Sleep "xbmc.sleep()" incorrectly (long periods of time, e.g. that exceed
+ /// the force stop waiting time) it may lead to Kodi hanging on shutdown.
+ /// In case your addon needs long sleep/idle periods use
+ /// \ref xbmc_Monitor_waitForAbort "xbmc.Monitor().waitForAbort(secs)"
+ /// instead.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.sleep(2000) # sleeps for 2 seconds
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ sleep(...);
+#else
+ void sleep(long timemillis);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getLocalizedString(id) }
+ /// Get a localized 'unicode string'.
+ ///
+ /// @param id integer - id# for string you want to
+ /// localize.
+ /// @return Localized 'unicode string'
+ ///
+ /// @note See strings.po in `\language\{yourlanguage}\` for which id
+ /// you need for a string.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// locstr = xbmc.getLocalizedString(6)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getLocalizedString(...);
+#else
+ String getLocalizedString(int id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getSkinDir() }
+ /// Get the active skin directory.
+ ///
+ /// @return The active skin directory as a string
+ ///
+ ///
+ /// @note This is not the full path like 'special://home/addons/MediaCenter',
+ /// but only 'MediaCenter'.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// skindir = xbmc.getSkinDir()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSkinDir();
+#else
+ String getSkinDir();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getLanguage([format], [region]) }
+ /// Get the active language.
+ ///
+ /// @param format [opt] format of the returned language
+ /// string
+ /// | Value | Description
+ /// |------------------:|:-------------------------------------------------|
+ /// | xbmc.ISO_639_1 | Two letter code as defined in ISO 639-1
+ /// | xbmc.ISO_639_2 | Three letter code as defined in ISO 639-2/T or ISO 639-2/B
+ /// | xbmc.ENGLISH_NAME | Full language name in English (default)
+ /// @param region [opt] append the region delimited by "-"
+ /// of the language (setting) to the
+ /// returned language string
+ /// @return The active language as a string
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v13 Added new options **format** and **region**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// language = xbmc.getLanguage(xbmc.ENGLISH_NAME)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getLanguage(...);
+#else
+ String getLanguage(int format = CLangCodeExpander::ENGLISH_NAME, bool region = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getIPAddress() }
+ /// Get the current ip address.
+ ///
+ /// @return The current ip address as a string
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// ip = xbmc.getIPAddress()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getIPAddress();
+#else
+ String getIPAddress();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getDVDState() }
+ /// Returns the dvd state as an integer.
+ ///
+ /// @return Values for state are:
+ /// | Value | Name |
+ /// |------:|:-------------------------------|
+ /// | 1 | xbmc.DRIVE_NOT_READY
+ /// | 16 | xbmc.TRAY_OPEN
+ /// | 64 | xbmc.TRAY_CLOSED_NO_MEDIA
+ /// | 96 | xbmc.TRAY_CLOSED_MEDIA_PRESENT
+ ///
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dvdstate = xbmc.getDVDState()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getDVDState();
+#else
+ long getDVDState();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getFreeMem() }
+ /// Get amount of free memory in MB.
+ ///
+ /// @return The amount of free memory in MB as an integer
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// freemem = xbmc.getFreeMem()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getFreeMem();
+#else
+ long getFreeMem();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getInfoLabel(infotag) }
+ /// Get a info label
+ ///
+ /// @param infotag string - infoTag for value you want
+ /// returned.
+ /// @return InfoLabel as a string
+ ///
+ /// \ref modules__infolabels_boolean_conditions "List of InfoTags"
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// label = xbmc.getInfoLabel('Weather.Conditions')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getInfoLabel(...);
+#else
+ String getInfoLabel(const char* cLine);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getInfoImage(infotag) }
+ /// Get filename including path to the InfoImage's thumbnail.
+ ///
+ /// @param infotag string - infotag for value you want
+ /// returned
+ /// @return Filename including path to the
+ /// InfoImage's thumbnail as a string
+ ///
+ ///
+ /// List of InfoTags - http://kodi.wiki/view/InfoLabels
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// filename = xbmc.getInfoImage('Weather.Conditions')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getInfoImage(...);
+#else
+ String getInfoImage(const char * infotag);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.playSFX(filename,[useCached]) }
+ /// Plays a wav file by filename
+ ///
+ /// @param filename string - filename of the wav file to
+ /// play
+ /// @param useCached [opt] bool - False = Dump any
+ /// previously cached wav associated with
+ /// filename
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v14 Added new option **useCached**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.playSFX('special://xbmc/scripts/dingdong.wav')
+ /// xbmc.playSFX('special://xbmc/scripts/dingdong.wav',False)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ playSFX(...);
+#else
+ void playSFX(const char* filename, bool useCached = true);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.stopSFX() }
+ /// Stops wav file
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.stopSFX()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ stopSFX();
+#else
+ void stopSFX();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.enableNavSounds(yesNo) }
+ /// Enables/Disables nav sounds
+ ///
+ /// @param yesNo bool - enable (True) or disable
+ /// (False) nav sounds
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.enableNavSounds(True)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ enableNavSounds(...);
+#else
+ void enableNavSounds(bool yesNo);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getCondVisibility(condition) }
+ /// Get visibility conditions
+ ///
+ /// @param condition string - condition to check
+ /// @return True (if the condition is verified) or False (otherwise)
+ ///
+ /// \ref modules__infolabels_boolean_conditions "List of boolean conditions"
+ ///
+ /// @note You can combine two (or more) of the above settings by using <b>"+"</b> as an AND operator,
+ /// <b>"|"</b> as an OR operator, <b>"!"</b> as a NOT operator, and <b>"["</b> and <b>"]"</b> to bracket expressions.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// visible = xbmc.getCondVisibility('[Control.IsVisible(41) + !Control.IsVisible(12)]')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCondVisibility(...);
+#else
+ bool getCondVisibility(const char *condition);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getGlobalIdleTime() }
+ /// Get the elapsed idle time in seconds.
+ ///
+ /// @return Elapsed idle time in seconds as an integer
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// t = xbmc.getGlobalIdleTime()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getGlobalIdleTime();
+#else
+ int getGlobalIdleTime();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getCacheThumbName(path) }
+ /// Get thumb cache filename.
+ ///
+ /// @param path string - path to file
+ /// @return Thumb cache filename
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// thumb = xbmc.getCacheThumbName('f:\\videos\\movie.avi')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCacheThumbName(...);
+#else
+ String getCacheThumbName(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getCleanMovieTitle(path[, usefoldername]) }
+ /// Get clean movie title and year string if available.
+ ///
+ /// @param path string - String to clean
+ /// @param usefoldername [opt] bool - use folder names (defaults
+ /// to false)
+ /// @return Clean movie title and year string if
+ /// available.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// title, year = xbmc.getCleanMovieTitle('/path/to/moviefolder/test.avi', True)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCleanMovieTitle(...);
+#else
+ Tuple<String,String> getCleanMovieTitle(const String& path, bool usefoldername = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getRegion(id) }
+ /// Returns your regions setting as a string for the specified id.
+ ///
+ /// @param id string - id of setting to return
+ /// @return Region setting
+ ///
+ /// @note choices are (dateshort, datelong, time, meridiem, tempunit, speedunit)
+ /// You can use the above as keywords for arguments.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// date_long_format = xbmc.getRegion('datelong')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getRegion(...);
+#else
+ String getRegion(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getSupportedMedia(media) }
+ /// Get the supported file types for the specific media.
+ ///
+ /// @param media string - media type
+ /// @return Supported file types for the specific
+ /// media as a string
+ ///
+ ///
+ /// @note Media type can be (video, music, picture).
+ /// The return value is a pipe separated string of filetypes
+ /// (eg. '.mov |.avi').\n
+ /// You can use the above as keywords for arguments.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// mTypes = xbmc.getSupportedMedia('video')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSupportedMedia(...);
+#else
+ String getSupportedMedia(const char* mediaType);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.skinHasImage(image) }
+ /// Check skin for presence of Image.
+ ///
+ /// @param image string - image filename
+ /// @return True if the image file exists in the skin
+ ///
+ ///
+ /// @note If the media resides in a subfolder include it. (eg. home-myfiles\\home-myfiles2.png).
+ /// You can use the above as keywords for arguments.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// exists = xbmc.skinHasImage('ButtonFocusedTexture.png')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ skinHasImage(...);
+#else
+ bool skinHasImage(const char* image);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmc
+ ///
+ /// @brief \python_func{ xbmc.startServer(typ, bStart, bWait) }
+ /// Start or stop a server.
+ ///
+ /// @param typ integer - use SERVER_* constants
+ /// - Used format of the returned language string
+ /// | Value | Description |
+ /// |--------------------------:|------------------------------------------------------------|
+ /// | xbmc.SERVER_WEBSERVER | [To control Kodi's builtin webserver](http://kodi.wiki/view/Webserver)
+ /// | xbmc.SERVER_AIRPLAYSERVER | [AirPlay is a proprietary protocol stack/suite developed by Apple Inc.](http://kodi.wiki/view/AirPlay)
+ /// | xbmc.SERVER_JSONRPCSERVER | [Control JSON-RPC HTTP/TCP socket-based interface](http://kodi.wiki/view/JSON-RPC_API)
+ /// | xbmc.SERVER_UPNPRENDERER | [UPnP client (aka UPnP renderer)](http://kodi.wiki/view/UPnP/Client)
+ /// | xbmc.SERVER_UPNPSERVER | [Control built-in UPnP A/V media server (UPnP-server)](http://kodi.wiki/view/UPnP/Server)
+ /// | xbmc.SERVER_EVENTSERVER | [Set eventServer part that accepts remote device input on all platforms](http://kodi.wiki/view/EventServer)
+ /// | xbmc.SERVER_ZEROCONF | [Control Kodi's Avahi Zeroconf](http://kodi.wiki/view/Zeroconf)
+ /// @param bStart bool - start (True) or stop (False) a server
+ /// @return bool - True or False
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v20 Removed option **bWait**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.startServer(xbmc.SERVER_AIRPLAYSERVER, False)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ startServer(...);
+#else
+ bool startServer(int iTyp, bool bStart);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.audioSuspend() }
+ /// Suspend Audio engine.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.audioSuspend()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ audioSuspend();
+#else
+ void audioSuspend();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.audioResume() }
+ /// Resume Audio engine.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.audioResume()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ audioResume();
+#else
+ void audioResume();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.getUserAgent() }
+ /// @brief Returns Kodi's HTTP UserAgent string
+ ///
+ /// @return HTTP user agent
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmc.getUserAgent()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ /// example output:
+ /// Kodi/17.0-ALPHA1 (X11; Linux x86_64) Ubuntu/15.10 App_Bitness/64 Version/17.0-ALPHA1-Git:2015-12-23-5770d28
+ ///
+ getUserAgent();
+#else
+ String getUserAgent();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc
+ /// @brief \python_func{ xbmc.convertLanguage(language, format) }
+ /// @brief Returns the given language converted to the given format as a
+ /// string.
+ ///
+ /// @param language string either as name in English, two
+ /// letter code (ISO 639-1), or three
+ /// letter code (ISO 639-2/T(B)
+ /// @param format format of the returned language string
+ /// | Value | Description
+ /// |------------------:|:-------------------------------------------------|
+ /// | xbmc.ISO_639_1 | Two letter code as defined in ISO 639-1
+ /// | xbmc.ISO_639_2 | Three letter code as defined in ISO 639-2/T or ISO 639-2/B
+ /// | xbmc.ENGLISH_NAME | Full language name in English (default)
+ /// @return Converted Language string
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v13 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// language = xbmc.convertLanguage(English, xbmc.ISO_639_2)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ convertLanguage(...);
+#else
+ String convertLanguage(const char* language, int format);
+#endif
+ //@}
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_WEBSERVER);
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_AIRPLAYSERVER);
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_UPNPSERVER);
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_UPNPRENDERER);
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_EVENTSERVER);
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_JSONRPCSERVER);
+ SWIG_CONSTANT_FROM_GETTER(int, SERVER_ZEROCONF);
+
+ SWIG_CONSTANT_FROM_GETTER(int, PLAYLIST_MUSIC);
+ SWIG_CONSTANT_FROM_GETTER(int, PLAYLIST_VIDEO);
+ SWIG_CONSTANT_FROM_GETTER(int, TRAY_OPEN);
+ SWIG_CONSTANT_FROM_GETTER(int, DRIVE_NOT_READY);
+ SWIG_CONSTANT_FROM_GETTER(int, TRAY_CLOSED_NO_MEDIA);
+ SWIG_CONSTANT_FROM_GETTER(int, TRAY_CLOSED_MEDIA_PRESENT);
+ SWIG_CONSTANT_FROM_GETTER(int, LOGDEBUG);
+ SWIG_CONSTANT_FROM_GETTER(int, LOGINFO);
+ SWIG_CONSTANT_FROM_GETTER(int, LOGWARNING);
+ SWIG_CONSTANT_FROM_GETTER(int, LOGERROR);
+ SWIG_CONSTANT_FROM_GETTER(int, LOGFATAL);
+ SWIG_CONSTANT_FROM_GETTER(int, LOGNONE);
+
+ SWIG_CONSTANT_FROM_GETTER(int, ISO_639_1);
+ SWIG_CONSTANT_FROM_GETTER(int, ISO_639_2);
+ SWIG_CONSTANT_FROM_GETTER(int, ENGLISH_NAME);
+#if 0
+ void registerMonitor(Monitor* monitor);
+ void unregisterMonitor(Monitor* monitor);
+#endif
+ }
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/xbmc/interfaces/legacy/ModuleXbmcgui.cpp b/xbmc/interfaces/legacy/ModuleXbmcgui.cpp
new file mode 100644
index 0000000..104a755
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmcgui.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "ModuleXbmcgui.h"
+
+#include "LanguageHook.h"
+#include "ServiceBroker.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "windowing/GraphicContext.h"
+
+#include <mutex>
+
+#define NOTIFICATION_INFO "info"
+#define NOTIFICATION_WARNING "warning"
+#define NOTIFICATION_ERROR "error"
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ long getCurrentWindowId()
+ {
+ DelayedCallGuard dg;
+ std::unique_lock<CCriticalSection> gl(CServiceBroker::GetWinSystem()->GetGfxContext());
+ return CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
+ }
+
+ long getCurrentWindowDialogId()
+ {
+ DelayedCallGuard dg;
+ std::unique_lock<CCriticalSection> gl(CServiceBroker::GetWinSystem()->GetGfxContext());
+ return CServiceBroker::GetGUI()->GetWindowManager().GetTopmostModalDialog();
+ }
+
+ long getScreenHeight()
+ {
+ XBMC_TRACE;
+ return CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight();
+ }
+
+ long getScreenWidth()
+ {
+ XBMC_TRACE;
+ return CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth();
+ }
+
+ const char* getNOTIFICATION_INFO() { return NOTIFICATION_INFO; }
+ const char* getNOTIFICATION_WARNING() { return NOTIFICATION_WARNING; }
+ const char* getNOTIFICATION_ERROR() { return NOTIFICATION_ERROR; }
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/ModuleXbmcgui.h b/xbmc/interfaces/legacy/ModuleXbmcgui.h
new file mode 100644
index 0000000..d2d9558
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmcgui.h
@@ -0,0 +1,149 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "guilib/GUIEditControl.h"
+#include "swighelper.h"
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+ //
+ /// \defgroup python_xbmcgui Library - xbmcgui
+ /// @{
+ /// @brief **GUI functions on Kodi.**
+ ///
+ /// Offers classes and functions that manipulate the Graphical User
+ /// Interface through windows, dialogs, and various control widgets.
+ //
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui
+ /// @brief \python_func{ xbmcgui.getCurrentWindowId() }
+ /// Returns the id for the current 'active' window as an integer.
+ ///
+ /// @return The currently active window Id
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// wid = xbmcgui.getCurrentWindowId()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCurrentWindowId();
+#else
+ long getCurrentWindowId();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui
+ /// @brief \python_func{ xbmcgui.getCurrentWindowDialogId() }
+ /// Returns the id for the current 'active' dialog as an integer.
+ ///
+ /// @return The currently active dialog Id
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// wid = xbmcgui.getCurrentWindowDialogId()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCurrentWindowDialogId();
+#else
+ long getCurrentWindowDialogId();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui
+ /// @brief \python_func{ getScreenHeight() }
+ /// Returns the height of this screen.
+ ///
+ /// @return Screen height
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getScreenHeight();
+#else
+ long getScreenHeight();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui
+ /// @brief \python_func{ getScreenWidth() }
+ /// Returns the width of this screen.
+ ///
+ /// @return Screen width
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ getScreenWidth();
+#else
+ long getScreenWidth();
+#endif
+ ///@}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ SWIG_CONSTANT2(int, ICON_OVERLAY_NONE, CGUIListItem::ICON_OVERLAY_NONE);
+ SWIG_CONSTANT2(int, ICON_OVERLAY_RAR, CGUIListItem::ICON_OVERLAY_RAR);
+ SWIG_CONSTANT2(int, ICON_OVERLAY_ZIP, CGUIListItem::ICON_OVERLAY_ZIP);
+ SWIG_CONSTANT2(int, ICON_OVERLAY_LOCKED, CGUIListItem::ICON_OVERLAY_LOCKED);
+ SWIG_CONSTANT2(int, ICON_OVERLAY_UNWATCHED, CGUIListItem::ICON_OVERLAY_UNWATCHED);
+ SWIG_CONSTANT2(int, ICON_OVERLAY_WATCHED, CGUIListItem::ICON_OVERLAY_WATCHED);
+ SWIG_CONSTANT2(int, ICON_OVERLAY_HD, CGUIListItem::ICON_OVERLAY_HD);
+
+ SWIG_CONSTANT2(int, INPUT_TYPE_TEXT, CGUIEditControl::INPUT_TYPE_TEXT);
+ SWIG_CONSTANT2(int, INPUT_TYPE_NUMBER, CGUIEditControl::INPUT_TYPE_NUMBER);
+ SWIG_CONSTANT2(int, INPUT_TYPE_DATE, CGUIEditControl::INPUT_TYPE_DATE);
+ SWIG_CONSTANT2(int, INPUT_TYPE_TIME, CGUIEditControl::INPUT_TYPE_TIME);
+ SWIG_CONSTANT2(int, INPUT_TYPE_IPADDRESS, CGUIEditControl::INPUT_TYPE_IPADDRESS);
+ SWIG_CONSTANT2(int, INPUT_TYPE_PASSWORD, CGUIEditControl::INPUT_TYPE_PASSWORD);
+ SWIG_CONSTANT2(int, INPUT_TYPE_PASSWORD_MD5, CGUIEditControl::INPUT_TYPE_PASSWORD_MD5);
+ SWIG_CONSTANT2(int, INPUT_TYPE_SECONDS, CGUIEditControl::INPUT_TYPE_SECONDS);
+ SWIG_CONSTANT2(int, INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW, CGUIEditControl::INPUT_TYPE_PASSWORD_NUMBER_VERIFY_NEW);
+
+ SWIG_CONSTANT_FROM_GETTER(const char*, NOTIFICATION_INFO);
+ SWIG_CONSTANT_FROM_GETTER(const char*, NOTIFICATION_WARNING);
+ SWIG_CONSTANT_FROM_GETTER(const char*, NOTIFICATION_ERROR);
+
+ SWIG_CONSTANT(int, INPUT_ALPHANUM);
+ SWIG_CONSTANT(int, INPUT_NUMERIC);
+ SWIG_CONSTANT(int, INPUT_DATE);
+ SWIG_CONSTANT(int, INPUT_TIME);
+ SWIG_CONSTANT(int, INPUT_IPADDRESS);
+ SWIG_CONSTANT(int, INPUT_PASSWORD);
+
+ SWIG_CONSTANT(int, HORIZONTAL);
+ SWIG_CONSTANT(int, VERTICAL);
+
+ SWIG_CONSTANT(int, PASSWORD_VERIFY);
+ SWIG_CONSTANT(int, ALPHANUM_HIDE_INPUT);
+
+ }
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp b/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp
new file mode 100644
index 0000000..0af97b7
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmcplugin.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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 "ModuleXbmcplugin.h"
+
+#include "FileItem.h"
+#include "filesystem/PluginDirectory.h"
+
+namespace XBMCAddon
+{
+
+ namespace xbmcplugin
+ {
+ bool addDirectoryItem(int handle, const String& url, const xbmcgui::ListItem* listItem,
+ bool isFolder, int totalItems)
+ {
+ if (listItem == nullptr)
+ throw new XBMCAddon::WrongTypeException("None not allowed as argument for listitem");
+ AddonClass::Ref<xbmcgui::ListItem> pListItem(listItem);
+ pListItem->item->SetPath(url);
+ pListItem->item->m_bIsFolder = isFolder;
+
+ // call the directory class to add our item
+ return XFILE::CPluginDirectory::AddItem(handle, pListItem->item.get(), totalItems);
+ }
+
+ bool addDirectoryItems(int handle,
+ const std::vector<Tuple<String,const XBMCAddon::xbmcgui::ListItem*,bool> >& items,
+ int totalItems)
+ {
+ CFileItemList fitems;
+ for (const auto& item : items)
+ {
+ const String& url = item.first();
+ const XBMCAddon::xbmcgui::ListItem* pListItem = item.second();
+ bool bIsFolder = item.GetNumValuesSet() > 2 ? item.third() : false;
+ pListItem->item->SetPath(url);
+ pListItem->item->m_bIsFolder = bIsFolder;
+ fitems.Add(pListItem->item);
+ }
+
+ // call the directory class to add our items
+ return XFILE::CPluginDirectory::AddItems(handle, &fitems, totalItems);
+ }
+
+ void endOfDirectory(int handle, bool succeeded, bool updateListing,
+ bool cacheToDisc)
+ {
+ // tell the directory class that we're done
+ XFILE::CPluginDirectory::EndOfDirectory(handle, succeeded, updateListing, cacheToDisc);
+ }
+
+ void setResolvedUrl(int handle, bool succeeded, const xbmcgui::ListItem* listItem)
+ {
+ if (listItem == nullptr)
+ throw new XBMCAddon::WrongTypeException("None not allowed as argument for listitem");
+ AddonClass::Ref<xbmcgui::ListItem> pListItem(listItem);
+ XFILE::CPluginDirectory::SetResolvedUrl(handle, succeeded, pListItem->item.get());
+ }
+
+ void addSortMethod(int handle, int sortMethod, const String& clabelMask, const String& clabel2Mask)
+ {
+ String labelMask;
+ if (sortMethod == SORT_METHOD_TRACKNUM)
+ labelMask = (clabelMask.empty() ? "[%N. ]%T" : clabelMask.c_str());
+ else if (sortMethod == SORT_METHOD_EPISODE || sortMethod == SORT_METHOD_PRODUCTIONCODE)
+ labelMask = (clabelMask.empty() ? "%H. %T" : clabelMask.c_str());
+ else
+ labelMask = (clabelMask.empty() ? "%T" : clabelMask.c_str());
+
+ String label2Mask;
+ label2Mask = (clabel2Mask.empty() ? "%D" : clabel2Mask.c_str());
+
+ // call the directory class to add the sort method.
+ if (sortMethod >= SORT_METHOD_NONE && sortMethod < SORT_METHOD_MAX)
+ XFILE::CPluginDirectory::AddSortMethod(handle, (SORT_METHOD)sortMethod, labelMask, label2Mask);
+ }
+
+ String getSetting(int handle, const char* id)
+ {
+ return XFILE::CPluginDirectory::GetSetting(handle, id);
+ }
+
+ void setSetting(int handle, const String& id, const String& value)
+ {
+ XFILE::CPluginDirectory::SetSetting(handle, id, value);
+ }
+
+ void setContent(int handle, const char* content)
+ {
+ XFILE::CPluginDirectory::SetContent(handle, content);
+ }
+
+ void setPluginCategory(int handle, const String& category)
+ {
+ XFILE::CPluginDirectory::SetProperty(handle, "plugincategory", category);
+ }
+
+ void setPluginFanart(int handle, const char* image,
+ const char* color1,
+ const char* color2,
+ const char* color3)
+ {
+ if (image)
+ XFILE::CPluginDirectory::SetProperty(handle, "fanart_image", image);
+ if (color1)
+ XFILE::CPluginDirectory::SetProperty(handle, "fanart_color1", color1);
+ if (color2)
+ XFILE::CPluginDirectory::SetProperty(handle, "fanart_color2", color2);
+ if (color3)
+ XFILE::CPluginDirectory::SetProperty(handle, "fanart_color3", color3);
+ }
+
+ void setProperty(int handle, const char* key, const String& value)
+ {
+ XFILE::CPluginDirectory::SetProperty(handle, key, value);
+ }
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/ModuleXbmcplugin.h b/xbmc/interfaces/legacy/ModuleXbmcplugin.h
new file mode 100644
index 0000000..1aa458c
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmcplugin.h
@@ -0,0 +1,489 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonString.h"
+#include "ListItem.h"
+#include "Tuple.h"
+#include "swighelper.h"
+
+#include <vector>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+namespace XBMCAddon
+{
+ namespace xbmcplugin
+ {
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+ //
+ /// \defgroup python_xbmcplugin Library - xbmcplugin
+ /// @{
+ /// @brief <b>Plugin functions on Kodi.</b>
+ ///
+ /// Offers classes and functions that allow a developer to present
+ /// information through Kodi's standard menu structure. While plugins don't
+ /// have the same flexibility as scripts, they boast significantly quicker
+ /// development time and a more consistent user experience.
+ //
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.addDirectoryItem(handle, url, listitem [,isFolder, totalItems]) }
+ /// Callback function to pass directory contents back to Kodi.
+ ///
+ /// @param handle integer - handle the plugin was started
+ /// with.
+ /// @param url string - url of the entry. would be
+ /// `plugin://` for another virtual directory
+ /// @param listitem ListItem - item to add.
+ /// @param isFolder [opt] bool - True=folder / False=not a
+ /// folder(default).
+ /// @param totalItems [opt] integer - total number of items
+ /// that will be passed.(used for progressbar)
+ /// @return Returns a bool for successful completion.
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain
+ /// optional arguments. Once you use a keyword, all following arguments
+ /// require the keyword.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// if not xbmcplugin.addDirectoryItem(int(sys.argv[1]), 'F:\\Trailers\\300.mov', listitem, totalItems=50): break
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ addDirectoryItem(...);
+#else
+ bool addDirectoryItem(int handle, const String& url, const XBMCAddon::xbmcgui::ListItem* listitem,
+ bool isFolder = false, int totalItems = 0);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.addDirectoryItems(handle, items[, totalItems]) }
+ /// Callback function to pass directory contents back to Kodi as a list.
+ ///
+ /// @param handle integer - handle the plugin was started
+ /// with.
+ /// @param items List - list of (url, listitem[, isFolder])
+ /// as a tuple to add.
+ /// @param totalItems [opt] integer - total number of items
+ /// that will be passed.(used for progressbar)
+ /// @return Returns a bool for successful completion.
+ ///
+ /// @remark Large lists benefit over using the standard addDirectoryItem().
+ /// You may call this more than once to add items in chunks.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// if not xbmcplugin.addDirectoryItems(int(sys.argv[1]), [(url, listitem, False,)]: raise
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ addDirectoryItems(...);
+#else
+ bool addDirectoryItems(int handle,
+ const std::vector<Tuple<String,const XBMCAddon::xbmcgui::ListItem*,bool> >& items,
+ int totalItems = 0);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.endOfDirectory(handle[, succeeded, updateListing, cacheToDisc]) }
+ /// Callback function to tell Kodi that the end of the directory listing in
+ /// a virtualPythonFolder module is reached.
+ ///
+ /// @param handle integer - handle the plugin was started
+ /// with.
+ /// @param succeeded [opt] bool - True=script completed
+ /// successfully(Default)/False=Script did not.
+ /// @param updateListing [opt] bool - True=this folder should
+ /// update the current listing/False=Folder
+ /// is a subfolder(Default).
+ /// @param cacheToDisc [opt] bool - True=Folder will cache if
+ /// extended time(default)/False=this folder
+ /// will never cache to disc.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.endOfDirectory(int(sys.argv[1]), cacheToDisc=False)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ endOfDirectory(...);
+#else
+ void endOfDirectory(int handle, bool succeeded = true, bool updateListing = false,
+ bool cacheToDisc = true);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.setResolvedUrl(handle, succeeded, listitem) }
+ /// Callback function to tell Kodi that the file plugin has been resolved to
+ /// a url
+ ///
+ /// @param handle integer - handle the plugin was started
+ /// with.
+ /// @param succeeded bool - True=script completed
+ /// successfully/False=Script did not.
+ /// @param listitem ListItem - item the file plugin resolved
+ /// to for playback.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setResolvedUrl(...);
+#else
+ void setResolvedUrl(int handle, bool succeeded, const XBMCAddon::xbmcgui::ListItem* listitem);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.addSortMethod(handle, sortMethod [,labelMask, label2Mask]) }
+ ///-------------------------------------------------------------------------
+ /// Adds a sorting method for the media list.
+ ///
+ /// @param handle integer - handle the plugin was started
+ /// with.
+ /// @param sortMethod integer - see available sort methods at
+ /// the bottom (or see \ref List_of_sort_methods "SortUtils").
+ /// | Value | Description |
+ /// |----------------------------------------------|-----------------------|
+ /// | xbmcplugin.SORT_METHOD_NONE | Do not sort
+ /// | xbmcplugin.SORT_METHOD_LABEL | Sort by label
+ /// | xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE | Sort by the label and ignore "The" before
+ /// | xbmcplugin.SORT_METHOD_DATE | Sort by the date
+ /// | xbmcplugin.SORT_METHOD_SIZE | Sort by the size
+ /// | xbmcplugin.SORT_METHOD_FILE | Sort by the file
+ /// | xbmcplugin.SORT_METHOD_DRIVE_TYPE | Sort by the drive type
+ /// | xbmcplugin.SORT_METHOD_TRACKNUM | Sort by the track number
+ /// | xbmcplugin.SORT_METHOD_DURATION | Sort by the duration
+ /// | xbmcplugin.SORT_METHOD_TITLE | Sort by the title
+ /// | xbmcplugin.SORT_METHOD_TITLE_IGNORE_THE | Sort by the title and ignore "The" before
+ /// | xbmcplugin.SORT_METHOD_ARTIST | Sort by the artist
+ /// | xbmcplugin.SORT_METHOD_ARTIST_IGNORE_THE | Sort by the artist and ignore "The" before
+ /// | xbmcplugin.SORT_METHOD_ALBUM | Sort by the album
+ /// | xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE | Sort by the album and ignore "The" before
+ /// | xbmcplugin.SORT_METHOD_GENRE | Sort by the genre
+ /// | xbmcplugin.SORT_SORT_METHOD_VIDEO_YEAR, xbmcplugin.SORT_METHOD_YEAR | Sort by the year
+ /// | xbmcplugin.SORT_METHOD_VIDEO_RATING | Sort by the video rating
+ /// | xbmcplugin.SORT_METHOD_PROGRAM_COUNT | Sort by the program count
+ /// | xbmcplugin.SORT_METHOD_PLAYLIST_ORDER | Sort by the playlist order
+ /// | xbmcplugin.SORT_METHOD_EPISODE | Sort by the episode
+ /// | xbmcplugin.SORT_METHOD_VIDEO_TITLE | Sort by the video title
+ /// | xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE | Sort by the video sort title
+ /// | xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE | Sort by the video sort title and ignore "The" before
+ /// | xbmcplugin.SORT_METHOD_PRODUCTIONCODE | Sort by the production code
+ /// | xbmcplugin.SORT_METHOD_SONG_RATING | Sort by the song rating
+ /// | xbmcplugin.SORT_METHOD_MPAA_RATING | Sort by the mpaa rating
+ /// | xbmcplugin.SORT_METHOD_VIDEO_RUNTIME | Sort by video runtime
+ /// | xbmcplugin.SORT_METHOD_STUDIO | Sort by the studio
+ /// | xbmcplugin.SORT_METHOD_STUDIO_IGNORE_THE | Sort by the studio and ignore "The" before
+ /// | xbmcplugin.SORT_METHOD_UNSORTED | Use list not sorted
+ /// | xbmcplugin.SORT_METHOD_BITRATE | Sort by the bitrate
+ /// | xbmcplugin.SORT_METHOD_LISTENERS | Sort by the listeners
+ /// | xbmcplugin.SORT_METHOD_COUNTRY | Sort by the country
+ /// | xbmcplugin.SORT_METHOD_DATEADDED | Sort by the added date
+ /// | xbmcplugin.SORT_METHOD_FULLPATH | Sort by the full path name
+ /// | xbmcplugin.SORT_METHOD_LABEL_IGNORE_FOLDERS | Sort by the label names and ignore related folder names
+ /// | xbmcplugin.SORT_METHOD_LASTPLAYED | Sort by last played date
+ /// | xbmcplugin.SORT_METHOD_PLAYCOUNT | Sort by the play count
+ /// | xbmcplugin.SORT_METHOD_CHANNEL | Sort by the channel
+ /// | xbmcplugin.SORT_METHOD_DATE_TAKEN | Sort by the taken date
+ /// | xbmcplugin.SORT_METHOD_VIDEO_USER_RATING | Sort by the rating of the user of video
+ /// | xbmcplugin.SORT_METHOD_SONG_USER_RATING | Sort by the rating of the user of song
+ /// @param labelMask [opt] string - the label mask to use for
+ /// the first label.
+ /// - applies to:
+ /// | sortMethod | labelMask |
+ /// |---------------------------------------|-----------------------------|
+ /// | SORT_METHOD_TRACKNUM | Defaults to `[%%N. ]%%T` |
+ /// | SORT_METHOD_EPISODE | Defaults to `%%H. %%T` |
+ /// | SORT_METHOD_PRODUCTIONCODE | Defaults to `%%H. %%T` |
+ /// | All other sort methods | Defaults to `%%T` |
+ ///
+ ///
+ /// @param label2Mask [opt] string - the label mask to use for
+ /// the second label. Defaults to `%%D`
+ /// - applies to:
+ /// | | | |
+ /// |-----------------------------------------|-----------------------------|-----------------------------------------|
+ /// | SORT_METHOD_NONE | SORT_METHOD_UNSORTED | SORT_METHOD_VIDEO_TITLE |
+ /// | SORT_METHOD_TRACKNUM | SORT_METHOD_FILE | SORT_METHOD_TITLE |
+ /// | SORT_METHOD_TITLE_IGNORE_THE | SORT_METHOD_LABEL | SORT_METHOD_LABEL_IGNORE_THE |
+ /// | SORT_METHOD_VIDEO_SORT_TITLE | SORT_METHOD_FULLPATH | SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE |
+ /// | SORT_METHOD_LABEL_IGNORE_FOLDERS | SORT_METHOD_CHANNEL | |
+ /// @note to add multiple sort methods just call the method multiple times.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v13 Added new sort **SORT_METHOD_DATE_TAKEN**, **SORT_METHOD_COUNTRY**,
+ /// **SORT_METHOD_DATEADDED**, **SORT_METHOD_FULLPATH**, **SORT_METHOD_LABEL_IGNORE_FOLDERS**,
+ /// **SORT_METHOD_LASTPLAYED**, **SORT_METHOD_PLAYCOUNT**, **SORT_METHOD_CHANNEL**.
+ /// @python_v17 Added new sort **SORT_METHOD_VIDEO_USER_RATING**.
+ /// @python_v19 Added new option **labelMask**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORTMETHOD_DATEADDED)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ addSortMethod(...);
+#else
+ void addSortMethod(int handle, int sortMethod, const String& labelMask = emptyString, const String& label2Mask = emptyString);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.getSetting(handle, id) }
+ /// Returns the value of a setting as a string.
+ ///
+ /// @param handle integer - handle the plugin was started
+ /// with.
+ /// @param id string - id of the setting that the
+ /// module needs to access.
+ /// @return Setting value as string
+ ///
+ /// @note You can use the above as a keyword.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// apikey = xbmcplugin.getSetting(int(sys.argv[1]), 'apikey')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getSetting(...);
+#else
+ String getSetting(int handle, const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.setSetting(handle, id, value) }
+ /// Sets a plugin setting for the current running plugin.
+ ///
+ /// @param handle integer - handle the plugin was started with.
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value string or unicode - value of the setting.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.setSetting(int(sys.argv[1]), id='username', value='teamxbmc')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setSetting(...);
+#else
+ void setSetting(int handle, const String& id, const String& value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.setContent(handle, content) }
+ /// Sets the plugins content.
+ ///
+ /// @param handle integer - handle the plugin was started with.
+ /// @param content string - content type (eg. movies)
+ ///
+ /// @par Available content strings
+ /// | | | | |
+ /// |:--------:|:--------:|:--------:|:-----------:|
+ /// | files | songs | artists | albums |
+ /// | movies | tvshows | episodes | musicvideos |
+ /// | videos | images | games | -- |
+ ///
+ /// @remark Use **videos** for all videos which do not apply to the
+ /// more specific mentioned ones like "movies", "episodes" etc.
+ /// A good example is youtube.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v18 Added new **games** content
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.setContent(int(sys.argv[1]), 'movies')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setContent(...);
+#else
+ void setContent(int handle, const char* content);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.setPluginCategory(handle, category) }
+ /// Sets the plugins name for skins to display.
+ ///
+ /// @param handle integer - handle the plugin was started with.
+ /// @param category string or unicode - plugins sub category.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.setPluginCategory(int(sys.argv[1]), 'Comedy')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setPluginCategory(...);
+#else
+ void setPluginCategory(int handle, const String& category);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.setPluginFanart(handle, image, color1, color2, color3) }
+ /// Sets the plugins fanart and color for skins to display.
+ ///
+ /// @param handle integer - handle the plugin was started with.
+ /// @param image [opt] string - path to fanart image.
+ /// @param color1 [opt] hexstring - color1. (e.g. '0xFFFFFFFF')
+ /// @param color2 [opt] hexstring - color2. (e.g. '0xFFFF3300')
+ /// @param color3 [opt] hexstring - color3. (e.g. '0xFF000000')
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.setPluginFanart(int(sys.argv[1]), 'special://home/addons/plugins/video/Apple movie trailers II/fanart.png', color2='0xFFFF3300')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setPluginFanart(...);
+#else
+ void setPluginFanart(int handle, const char* image = NULL,
+ const char* color1 = NULL,
+ const char* color2 = NULL,
+ const char* color3 = NULL);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcplugin
+ /// @brief \python_func{ xbmcplugin.setProperty(handle, key, value) }
+ /// Sets a container property for this plugin.
+ ///
+ /// @param handle integer - handle the plugin was started with.
+ /// @param key string - property name.
+ /// @param value string or unicode - value of property.
+ ///
+ /// @note Key is NOT case sensitive.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcplugin.setProperty(int(sys.argv[1]), 'Emulator', 'M.A.M.E.')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setProperty(...);
+ ///@}
+#else
+ void setProperty(int handle, const char* key, const String& value);
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ SWIG_CONSTANT(int, SORT_METHOD_NONE);
+ SWIG_CONSTANT(int, SORT_METHOD_LABEL);
+ SWIG_CONSTANT(int, SORT_METHOD_LABEL_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_DATE);
+ SWIG_CONSTANT(int, SORT_METHOD_SIZE);
+ SWIG_CONSTANT(int, SORT_METHOD_FILE);
+ SWIG_CONSTANT(int, SORT_METHOD_DRIVE_TYPE);
+ SWIG_CONSTANT(int, SORT_METHOD_TRACKNUM);
+ SWIG_CONSTANT(int, SORT_METHOD_DURATION);
+ SWIG_CONSTANT(int, SORT_METHOD_TITLE);
+ SWIG_CONSTANT(int, SORT_METHOD_TITLE_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_ARTIST);
+ SWIG_CONSTANT(int, SORT_METHOD_ARTIST_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_ALBUM);
+ SWIG_CONSTANT(int, SORT_METHOD_ALBUM_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_GENRE);
+ SWIG_CONSTANT2(int, SORT_METHOD_VIDEO_YEAR,SORT_METHOD_YEAR);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_RATING);
+ SWIG_CONSTANT(int, SORT_METHOD_PROGRAM_COUNT);
+ SWIG_CONSTANT(int, SORT_METHOD_PLAYLIST_ORDER);
+ SWIG_CONSTANT(int, SORT_METHOD_EPISODE);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_TITLE);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_SORT_TITLE);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_ORIGINAL_TITLE);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_ORIGINAL_TITLE_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_PRODUCTIONCODE);
+ SWIG_CONSTANT(int, SORT_METHOD_SONG_RATING);
+ SWIG_CONSTANT(int, SORT_METHOD_MPAA_RATING);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_RUNTIME);
+ SWIG_CONSTANT(int, SORT_METHOD_STUDIO);
+ SWIG_CONSTANT(int, SORT_METHOD_STUDIO_IGNORE_THE);
+ SWIG_CONSTANT(int, SORT_METHOD_UNSORTED);
+ SWIG_CONSTANT(int, SORT_METHOD_BITRATE);
+ SWIG_CONSTANT(int, SORT_METHOD_LISTENERS);
+ SWIG_CONSTANT(int, SORT_METHOD_COUNTRY);
+ SWIG_CONSTANT(int, SORT_METHOD_DATEADDED);
+ SWIG_CONSTANT(int, SORT_METHOD_FULLPATH);
+ SWIG_CONSTANT(int, SORT_METHOD_LABEL_IGNORE_FOLDERS);
+ SWIG_CONSTANT(int, SORT_METHOD_LASTPLAYED);
+ SWIG_CONSTANT(int, SORT_METHOD_PLAYCOUNT);
+ SWIG_CONSTANT(int, SORT_METHOD_CHANNEL);
+ SWIG_CONSTANT(int, SORT_METHOD_DATE_TAKEN);
+ SWIG_CONSTANT(int, SORT_METHOD_VIDEO_USER_RATING);
+ SWIG_CONSTANT(int, SORT_METHOD_SONG_USER_RATING);
+ }
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp b/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp
new file mode 100644
index 0000000..c6858e3
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmcvfs.cpp
@@ -0,0 +1,137 @@
+/*
+ * 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 "ModuleXbmcvfs.h"
+
+#include "FileItem.h"
+#include "LanguageHook.h"
+#include "URL.h"
+#include "Util.h"
+#include "filesystem/Directory.h"
+#include "filesystem/File.h"
+#include "filesystem/SpecialProtocol.h"
+#include "utils/FileUtils.h"
+#include "utils/URIUtils.h"
+
+namespace XBMCAddon
+{
+
+ namespace xbmcvfs
+ {
+ bool copy(const String& strSource, const String& strDestination)
+ {
+ DelayedCallGuard dg;
+ return XFILE::CFile::Copy(strSource, strDestination);
+ }
+
+ // delete a file
+ bool deleteFile(const String& strSource)
+ {
+ DelayedCallGuard dg;
+ return XFILE::CFile::Delete(strSource);
+ }
+
+ // rename a file
+ bool rename(const String& file, const String& newFile)
+ {
+ DelayedCallGuard dg;
+ return XFILE::CFile::Rename(file,newFile);
+ }
+
+ // check for a file or folder existence, mimics Pythons os.path.exists()
+ bool exists(const String& path)
+ {
+ DelayedCallGuard dg;
+ if (URIUtils::HasSlashAtEnd(path, true))
+ return XFILE::CDirectory::Exists(path, false);
+ return XFILE::CFile::Exists(path, false);
+ }
+
+ // make legal file name
+ String makeLegalFilename(const String& filename)
+ {
+ XBMC_TRACE;
+ return CUtil::MakeLegalPath(filename);
+ }
+
+ // translate path
+ String translatePath(const String& path)
+ {
+ XBMC_TRACE;
+ return CSpecialProtocol::TranslatePath(path);
+ }
+
+ // validate path
+ String validatePath(const String& path)
+ {
+ XBMC_TRACE;
+ return CUtil::ValidatePath(path, true);
+ }
+
+ // make a directory
+ bool mkdir(const String& path)
+ {
+ DelayedCallGuard dg;
+ return XFILE::CDirectory::Create(path);
+ }
+
+ // make all directories along the path
+ bool mkdirs(const String& path)
+ {
+ DelayedCallGuard dg;
+ return CUtil::CreateDirectoryEx(path);
+ }
+
+ bool rmdir(const String& path, bool force)
+ {
+ DelayedCallGuard dg;
+
+ if (force)
+ return CFileUtils::DeleteItem(path);
+ else
+ return XFILE::CDirectory::Remove(path);
+ }
+
+ Tuple<std::vector<String>, std::vector<String> > listdir(const String& path)
+ {
+ DelayedCallGuard dg;
+ CFileItemList items;
+ std::string strSource;
+ strSource = path;
+ XFILE::CDirectory::GetDirectory(strSource, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS);
+
+ Tuple<std::vector<String>, std::vector<String> > ret;
+ // initialize the Tuple to two values
+ ret.second();
+
+ for (int i=0; i < items.Size(); i++)
+ {
+ std::string itemPath = items[i]->GetPath();
+
+ if (URIUtils::HasSlashAtEnd(itemPath)) // folder
+ {
+ URIUtils::RemoveSlashAtEnd(itemPath);
+ std::string strFileName = URIUtils::GetFileName(itemPath);
+ if (strFileName.empty())
+ {
+ CURL url(itemPath);
+ strFileName = url.GetHostName();
+ }
+ ret.first().push_back(strFileName);
+ }
+ else // file
+ {
+ std::string strFileName = URIUtils::GetFileName(itemPath);
+ ret.second().push_back(strFileName);
+ }
+ }
+
+ return ret;
+ }
+ }
+}
diff --git a/xbmc/interfaces/legacy/ModuleXbmcvfs.h b/xbmc/interfaces/legacy/ModuleXbmcvfs.h
new file mode 100644
index 0000000..30e768f
--- /dev/null
+++ b/xbmc/interfaces/legacy/ModuleXbmcvfs.h
@@ -0,0 +1,334 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonString.h"
+#include "Tuple.h"
+
+#include <vector>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+namespace XBMCAddon
+{
+ namespace xbmcvfs
+ {
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
+ //
+ /// \defgroup python_xbmcvfs Library - xbmcvfs
+ /// @{
+ /// @brief **Virtual file system functions on Kodi.**
+ ///
+ /// Offers classes and functions offers access to the Virtual File Server
+ /// (VFS) which you can use to manipulate files and folders.
+ //
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.copy(source, destination) }
+ /// Copy file to destination, returns true/false.
+ ///
+ /// @param source file to copy.
+ /// @param destination destination file
+ /// @return True if successed
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// success = xbmcvfs.copy(source, destination)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ copy(...);
+#else
+ bool copy(const String& strSource, const String& strDestination);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.delete(file) }
+ /// Delete a file
+ ///
+ /// @param file File to delete
+ /// @return True if successed
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// xbmcvfs.delete(file)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ delete(...);
+#else
+ bool deleteFile(const String& file);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.rename(file, newFileName) }
+ /// Rename a file
+ ///
+ /// @param file File to rename
+ /// @param newFileName New filename, including the full path
+ /// @return True if successed
+ ///
+ /// @note Moving files between different filesystem (eg. local to nfs://) is not possible on
+ /// all platforms. You may have to do it manually by using the copy and deleteFile functions.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// success = xbmcvfs.rename(file,newFileName)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ rename(...);
+#else
+ bool rename(const String& file, const String& newFile);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.exists(path) }
+ /// Check for a file or folder existence
+ ///
+ /// @param path File or folder (folder must end with
+ /// slash or backslash)
+ /// @return True if successed
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// success = xbmcvfs.exists(path)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ exists(...);
+#else
+ bool exists(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.makeLegalFilename(filename) }
+ /// Returns a legal filename or path as a string.
+ ///
+ /// @param filename string - filename/path to make legal
+ /// @return Legal filename or path as a string
+ ///
+ ///
+ /// @note The returned value is platform-specific. This is due to the fact that
+ /// the chars that need to be replaced to make a path legal depend on the
+ /// underlying OS filesystem. This is useful, for example, if you want to create
+ /// a file or folder based on data over which you have no control (e.g. an external API).
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ /// @python_v19 New function added (replaces old **xbmc.makeLegalFilename**)
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # windows
+ /// >> xbmcvfs.makeLegalFilename('C://Trailers/Ice Age: The Meltdown.avi')
+ /// C:\Trailers\Ice Age_ The Meltdown.avi
+ /// # non-windows
+ /// >> xbmcvfs.makeLegalFilename("///\\jk???lj????.mpg")
+ /// /jk___lj____.mpg
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ makeLegalFilename(...);
+#else
+ String makeLegalFilename(const String& filename);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.translatePath(path) }
+ /// Returns the translated path.
+ ///
+ /// @param path string - Path to format
+ /// @return Translated path
+ ///
+ /// @note Only useful if you are coding for both Linux and Windows.
+ /// e.g. Converts 'special://home' -> '/home/[username]/.kodi'
+ /// on Linux.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v19 New function added (replaces old **xbmc.translatePath**)
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// fpath = xbmcvfs.translatePath('special://home')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ translatePath(...);
+#else
+ String translatePath(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.validatePath(path) }
+ /// Returns the validated path.
+ ///
+ /// @param path string - Path to format
+ /// @return Validated path
+ ///
+ /// @note The result is platform-specific. Only useful if you are coding
+ /// for multiple platfforms for fixing slash problems
+ /// (e.g. Corrects 'Z://something' -> 'Z:\something').
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v19 New function added (replaces old **xbmc.validatePath**)
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// fpath = xbmcvfs.validatePath(somepath)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ validatePath(...);
+#else
+ String validatePath(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.mkdir(path) }
+ /// Create a folder.
+ ///
+ /// @param path Folder to create
+ /// @return True if successed
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// success = xbmcvfs.mkdir(path)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ mkdir(...);
+#else
+ bool mkdir(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.mkdirs(path) }
+ /// Make all directories along the path
+ ///
+ /// Create folder(s) - it will create all folders in the path.
+ ///
+ /// @param path Folders to create
+ /// @return True if successed
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// success = xbmcvfs.mkdirs(path)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ mkdirs(...);
+#else
+ bool mkdirs(const String& path);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.rmdir(path, [force]) }
+ /// Remove a folder.
+ ///
+ /// @param path string - Folder to remove
+ /// @param force [opt] bool - Force directory removal
+ /// (default False). This can be useful
+ /// if the directory is not empty.
+ /// @return bool - True if successful, False
+ /// otherwise
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// success = xbmcvfs.rmdir(path)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ rmdir(...);
+#else
+ bool rmdir(const String& path, bool force = false);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcvfs
+ /// @brief \python_func{ xbmcvfs.listdir(path) }
+ /// Lists content of a folder.
+ ///
+ /// @param path Folder to get list from
+ /// @return Directory content list
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dirs, files = xbmcvfs.listdir(path)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ listdir(...);
+#else
+ Tuple<std::vector<String>, std::vector<String> > listdir(const String& path);
+#endif
+ //@}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ }
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/xbmc/interfaces/legacy/Monitor.cpp b/xbmc/interfaces/legacy/Monitor.cpp
new file mode 100644
index 0000000..34d0553
--- /dev/null
+++ b/xbmc/interfaces/legacy/Monitor.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "Monitor.h"
+
+#include "threads/SystemClock.h"
+
+#include <algorithm>
+#include <math.h>
+
+using namespace std::chrono_literals;
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ Monitor::Monitor(): abortEvent(true)
+ {
+ XBMC_TRACE;
+ if (languageHook)
+ {
+ Id = languageHook->GetAddonId();
+ invokerId = languageHook->GetInvokerId();
+ languageHook->RegisterMonitorCallback(this);
+ }
+ }
+
+ void Monitor::AbortNotify()
+ {
+ XBMC_TRACE;
+ abortEvent.Set();
+ }
+
+ bool Monitor::waitForAbort(double timeout)
+ {
+ XBMC_TRACE;
+ int timeoutMS = ceil(timeout * 1000);
+ XbmcThreads::EndTime<> endTime{std::chrono::milliseconds(timeoutMS)};
+
+ if (timeoutMS <= 0)
+ endTime.SetInfinite();
+
+ while (!endTime.IsTimePast())
+ {
+ {
+ DelayedCallGuard dg(languageHook);
+ auto timeout = std::min(endTime.GetTimeLeft(), 100ms);
+ if (abortEvent.Wait(timeout))
+ return true;
+ }
+ if (languageHook)
+ languageHook->MakePendingCalls();
+ }
+ return false;
+ }
+
+ bool Monitor::abortRequested()
+ {
+ XBMC_TRACE;
+ return abortEvent.Signaled();
+ }
+
+ Monitor::~Monitor()
+ {
+ XBMC_TRACE;
+ deallocating();
+ DelayedCallGuard dg(languageHook);
+ // we're shutting down so unregister me.
+ if (languageHook)
+ {
+ DelayedCallGuard dc;
+ languageHook->UnregisterMonitorCallback(this);
+ }
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/Monitor.h b/xbmc/interfaces/legacy/Monitor.h
new file mode 100644
index 0000000..0d3d831
--- /dev/null
+++ b/xbmc/interfaces/legacy/Monitor.h
@@ -0,0 +1,311 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonCallback.h"
+#include "AddonString.h"
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+
+ ///
+ /// \ingroup python_xbmc
+ /// \defgroup python_monitor Monitor
+ /// @{
+ /// @brief **Kodi's monitor class.**
+ ///
+ /// \python_class{ xbmc.Monitor() }
+ ///
+ /// Creates a new monitor to notify addon about changes.
+ ///
+ class Monitor : public AddonCallback
+ {
+ String Id;
+ long invokerId;
+ CEvent abortEvent;
+ public:
+ Monitor();
+
+#ifndef SWIG
+ inline void OnSettingsChanged() { XBMC_TRACE; invokeCallback(new CallbackFunction<Monitor>(this,&Monitor::onSettingsChanged)); }
+ inline void OnScreensaverActivated() { XBMC_TRACE; invokeCallback(new CallbackFunction<Monitor>(this,&Monitor::onScreensaverActivated)); }
+ inline void OnScreensaverDeactivated() { XBMC_TRACE; invokeCallback(new CallbackFunction<Monitor>(this,&Monitor::onScreensaverDeactivated)); }
+ inline void OnDPMSActivated() { XBMC_TRACE; invokeCallback(new CallbackFunction<Monitor>(this,&Monitor::onDPMSActivated)); }
+ inline void OnDPMSDeactivated() { XBMC_TRACE; invokeCallback(new CallbackFunction<Monitor>(this,&Monitor::onDPMSDeactivated)); }
+ inline void OnScanStarted(const String &library)
+ {
+ XBMC_TRACE;
+ invokeCallback(
+ new CallbackFunction<Monitor, const String>(this, &Monitor::onScanStarted, library));
+ }
+ inline void OnScanFinished(const String &library)
+ {
+ XBMC_TRACE;
+ invokeCallback(
+ new CallbackFunction<Monitor, const String>(this, &Monitor::onScanFinished, library));
+ }
+ inline void OnCleanStarted(const String& library)
+ {
+ XBMC_TRACE;
+ invokeCallback(
+ new CallbackFunction<Monitor, const String>(this, &Monitor::onCleanStarted, library));
+ }
+ inline void OnCleanFinished(const String& library)
+ {
+ XBMC_TRACE;
+ invokeCallback(
+ new CallbackFunction<Monitor, const String>(this, &Monitor::onCleanFinished, library));
+ }
+ inline void OnNotification(const String& sender, const String& method, const String& data)
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Monitor, const String, const String, const String>(
+ this, &Monitor::onNotification, sender, method, data));
+ }
+
+ inline const String& GetId() { return Id; }
+ inline long GetInvokerId() { return invokerId; }
+
+ /**
+ * Called from XBPython to notify registered monitors that a script is aborting/ending.
+ */
+ void AbortNotify();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onSettingsChanged() }
+ /// onSettingsChanged method.
+ ///
+ /// Will be called when addon settings are changed
+ ///
+ onSettingsChanged();
+#else
+ virtual void onSettingsChanged() { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onScreensaverActivated() }
+ /// onScreensaverActivated method.
+ ///
+ /// Will be called when screensaver kicks in
+ ///
+ onScreensaverActivated();
+#else
+ virtual void onScreensaverActivated() { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onScreensaverDeactivated() }
+ /// onScreensaverDeactivated method.
+ ///
+ /// Will be called when screensaver goes off
+ ///
+ onScreensaverDeactivated();
+#else
+ virtual void onScreensaverDeactivated() { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onDPMSActivated() }
+ /// onDPMSActivated method.
+ ///
+ /// Will be called when energysaving/DPMS gets active
+ ///
+ onDPMSActivated();
+#else
+ virtual void onDPMSActivated() { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onDPMSDeactivated() }
+ /// onDPMSDeactivated method.
+ ///
+ /// Will be called when energysaving/DPMS is turned off
+ ///
+ onDPMSDeactivated();
+#else
+ virtual void onDPMSDeactivated() { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onScanStarted(library) }
+ /// onScanStarted method.
+ ///
+ /// @param library Video / music as string
+ ///
+ ///
+ /// @note Will be called when library clean has ended and return video or
+ /// music to indicate which library is being scanned
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ onScanStarted(...);
+#else
+ virtual void onScanStarted(const String library) { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onScanFinished(library) }
+ /// onScanFinished method.
+ ///
+ /// @param library Video / music as string
+ ///
+ ///
+ /// @note Will be called when library clean has ended and return video or
+ /// music to indicate which library has been scanned
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ onScanFinished(...);
+#else
+ virtual void onScanFinished(const String library) { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onCleanStarted(library) }
+ /// onCleanStarted method.
+ ///
+ /// @param library Video / music as string
+ ///
+ ///
+ /// @note Will be called when library clean has ended and return video or
+ /// music to indicate which library has been cleaned
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ onCleanStarted(...);
+#else
+ virtual void onCleanStarted(const String library) { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onCleanFinished(library) }
+ /// onCleanFinished method.
+ ///
+ /// @param library Video / music as string
+ ///
+ ///
+ /// @note Will be called when library clean has ended and return video or
+ /// music to indicate which library has been finished
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ onCleanFinished(...);
+#else
+ virtual void onCleanFinished(const String library) { XBMC_TRACE; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_monitor
+ /// @brief \python_func{ onNotification(sender, method, data) }
+ /// onNotification method.
+ ///
+ /// @param sender Sender of the notification
+ /// @param method Name of the notification
+ /// @param data JSON-encoded data of the notification
+ ///
+ /// @note Will be called when Kodi receives or sends a notification
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v13 New function added.
+ ///
+ onNotification(...);
+#else
+ virtual void onNotification(const String sender, const String method, const String data)
+ {
+ XBMC_TRACE;
+ }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_monitor
+ /// @brief \python_func{ waitForAbort([timeout]) }
+ /// Wait for Abort
+ /// \anchor xbmc_Monitor_waitForAbort
+ ///
+ /// Block until abort is requested, or until timeout occurs. If an
+ /// abort requested have already been made, return immediately.
+ ///
+ /// @param timeout [opt] float - timeout in seconds.
+ /// Default: no timeout.
+ ///
+ /// @return True when abort have been requested,
+ /// False if a timeout is given and the
+ /// operation times out.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// monitor = xbmc.Monitor()
+ /// # do something
+ /// monitor.waitForAbort(10) # sleeps for 10 secs or returns early if kodi aborts
+ /// if monitor.abortRequested():
+ /// # abort was requested to Kodi (e.g. shutdown), do your cleanup logic
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ waitForAbort(...);
+#else
+ bool waitForAbort(double timeout = -1);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_monitor
+ /// @brief \python_func{ abortRequested() }
+ /// Returns True if abort has been requested.
+ ///
+ /// @return True if requested
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v14 New function added.
+ ///
+ abortRequested();
+#else
+ bool abortRequested();
+#endif
+ ~Monitor() override;
+ };
+ /** @} */
+ }
+};
diff --git a/xbmc/interfaces/legacy/PlayList.cpp b/xbmc/interfaces/legacy/PlayList.cpp
new file mode 100644
index 0000000..1117a81
--- /dev/null
+++ b/xbmc/interfaces/legacy/PlayList.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "PlayList.h"
+
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "playlists/PlayListFactory.h"
+#include "utils/URIUtils.h"
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ //! @todo need a means to check for a valid construction
+ //! either by throwing an exception or by an "isValid" check
+ PlayList::PlayList(int playList) :
+ iPlayList(playList), pPlayList(NULL)
+ {
+ // we do not create our own playlist, just using the ones from playlistplayer
+ if (iPlayList != PLAYLIST::TYPE_MUSIC && iPlayList != PLAYLIST::TYPE_VIDEO)
+ throw PlayListException("PlayList does not exist");
+
+ pPlayList = &CServiceBroker::GetPlaylistPlayer().GetPlaylist(playList);
+ iPlayList = playList;
+ }
+
+ PlayList::~PlayList() = default;
+
+ void PlayList::add(const String& url, XBMCAddon::xbmcgui::ListItem* listitem, int index)
+ {
+ CFileItemList items;
+
+ if (listitem != NULL)
+ {
+ // an optional listitem was passed
+ // set m_strPath to the passed url
+ listitem->item->SetPath(url);
+
+ items.Add(listitem->item);
+ }
+ else
+ {
+ CFileItemPtr item(new CFileItem(url, false));
+ item->SetLabel(url);
+
+ items.Add(item);
+ }
+
+ pPlayList->Insert(items, index);
+ }
+
+ bool PlayList::load(const char* cFileName)
+ {
+ CFileItem item(cFileName);
+ item.SetPath(cFileName);
+
+ if (item.IsPlayList())
+ {
+ // load playlist and copy al items to existing playlist
+
+ // load a playlist like .m3u, .pls
+ // first get correct factory to load playlist
+ std::unique_ptr<PLAYLIST::CPlayList> pPlayList(PLAYLIST::CPlayListFactory::Create(item));
+ if (nullptr != pPlayList)
+ {
+ // load it
+ if (!pPlayList->Load(item.GetPath()))
+ //hmmm unable to load playlist?
+ return false;
+
+ // clear current playlist
+ CServiceBroker::GetPlaylistPlayer().ClearPlaylist(this->iPlayList);
+
+ // add each item of the playlist to the playlistplayer
+ for (int i=0; i < pPlayList->size(); ++i)
+ {
+ CFileItemPtr playListItem =(*pPlayList)[i];
+ if (playListItem->GetLabel().empty())
+ playListItem->SetLabel(URIUtils::GetFileName(playListItem->GetPath()));
+
+ this->pPlayList->Add(playListItem);
+ }
+ }
+ }
+ else
+ // filename is not a valid playlist
+ throw PlayListException("Not a valid playlist");
+
+ return true;
+ }
+
+ void PlayList::remove(const char* filename)
+ {
+ pPlayList->Remove(filename);
+ }
+
+ void PlayList::clear()
+ {
+ pPlayList->Clear();
+ }
+
+ int PlayList::size()
+ {
+ return pPlayList->size();
+ }
+
+ void PlayList::shuffle()
+ {
+ pPlayList->Shuffle();
+ }
+
+ void PlayList::unshuffle()
+ {
+ pPlayList->UnShuffle();
+ }
+
+ int PlayList::getposition()
+ {
+ return CServiceBroker::GetPlaylistPlayer().GetCurrentSong();
+ }
+
+ XBMCAddon::xbmcgui::ListItem* PlayList::operator [](long i)
+ {
+ int iPlayListSize = size();
+
+ long pos = i;
+ if (pos < 0) pos += iPlayListSize;
+
+ if (pos < 0 || pos >= iPlayListSize)
+ throw PlayListException("array out of bound");
+
+ CFileItemPtr ptr((*pPlayList)[pos]);
+
+ return new XBMCAddon::xbmcgui::ListItem(ptr);
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/PlayList.h b/xbmc/interfaces/legacy/PlayList.h
new file mode 100644
index 0000000..6162945
--- /dev/null
+++ b/xbmc/interfaces/legacy/PlayList.h
@@ -0,0 +1,212 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "Exception.h"
+#include "ListItem.h"
+#include "playlists/PlayList.h"
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(PlayListException);
+
+ //
+ /// \defgroup python_PlayList PlayList
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's Play List class.**
+ ///
+ /// \python_class{ xbmc.PlayList(playList) }
+ ///
+ /// To create and edit a playlist which can be handled by the player.
+ ///
+ /// @param playList [integer] To define the stream type
+ /// | Value | Integer String | Description |
+ /// |:-----:|:--------------------|:---------------------------------------|
+ /// | 0 | xbmc.PLAYLIST_MUSIC | Playlist for music files or streams |
+ /// | 1 | xbmc.PLAYLIST_VIDEO | Playlist for video files or streams |
+ ///
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// play=xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ //
+ class PlayList : public AddonClass
+ {
+ int iPlayList;
+ PLAYLIST::CPlayList *pPlayList;
+
+ public:
+ explicit PlayList(int playList);
+ ~PlayList() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ getPlayListId() }
+ /// Get the PlayList Identifier
+ ///
+ /// @return Id as an integer.
+ ///
+ getPlayListId();
+#else
+ inline int getPlayListId() const { return iPlayList; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ add(url[, listitem, index]) }
+ /// Adds a new file to the playlist.
+ ///
+ /// @param url string or unicode - filename or url to add.
+ /// @param listitem [opt] listitem - used with setInfo() to set different infolabels.
+ /// @param index [opt] integer - position to add playlist item. (default=end)
+ ///
+ /// @note You can use the above as keywords for arguments and skip certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
+ /// video = 'F:\\movies\\Ironman.mov'
+ /// listitem = xbmcgui.ListItem('Ironman', thumbnailImage='F:\\movies\\Ironman.tbn')
+ /// listitem.setInfo('video', {'Title': 'Ironman', 'Genre': 'Science Fiction'})
+ /// playlist.add(url=video, listitem=listitem, index=7)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ add(...);
+#else
+ void add(const String& url, XBMCAddon::xbmcgui::ListItem* listitem = NULL, int index = -1);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ load(filename) }
+ /// Load a playlist.
+ ///
+ /// Clear current playlist and copy items from the file to this Playlist
+ /// filename can be like .pls or .m3u ...
+ ///
+ /// @param filename File with list to play inside
+ /// @return False if unable to load playlist
+ ///
+ load(...);
+#else
+ bool load(const char* filename);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ remove(filename) }
+ /// Remove an item with this filename from the playlist.
+ ///
+ /// @param filename The file to remove from list.
+ ///
+ remove(...);
+#else
+ void remove(const char* filename);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ clear() }
+ /// Clear all items in the playlist.
+ ///
+ clear();
+#else
+ void clear();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ size() }
+ /// Returns the total number of PlayListItems in this playlist.
+ ///
+ /// @return Amount of playlist entries.
+ ///
+ size();
+#else
+ int size();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ shuffle() }
+ /// Shuffle the playlist.
+ ///
+ shuffle();
+#else
+ void shuffle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ unshuffle() }
+ /// Unshuffle the playlist.
+ ///
+ unshuffle();
+#else
+ void unshuffle();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ getposition() }
+ /// Returns the position of the current song in this playlist.
+ ///
+ /// @return Position of the current song
+ ///
+ getposition();
+#else
+ int getposition();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayList
+ /// @brief \python_func{ [] }
+ /// Retrieve the item at the given position.
+ ///
+ /// @param i Pointer in list
+ /// @return The selected item on list
+ ///
+ /// @note A negative index means
+ /// from the end rather than from the start.
+ ///
+ [](...);
+#else
+ XBMCAddon::xbmcgui::ListItem* operator[](long i);
+#endif
+ };
+ /// @}
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/Player.cpp b/xbmc/interfaces/legacy/Player.cpp
new file mode 100644
index 0000000..cf982ba
--- /dev/null
+++ b/xbmc/interfaces/legacy/Player.cpp
@@ -0,0 +1,607 @@
+/*
+ * 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 "Player.h"
+
+#include "AddonUtils.h"
+#include "GUIInfoManager.h"
+#include "GUIUserMessages.h"
+#include "ListItem.h"
+#include "PlayList.h"
+#include "PlayListPlayer.h"
+#include "ServiceBroker.h"
+#include "application/Application.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPlayer.h"
+#include "cores/IPlayer.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "messaging/ApplicationMessenger.h"
+#include "settings/MediaSettings.h"
+
+namespace
+{
+
+std::shared_ptr<const CApplicationPlayer> getAppPlayer()
+{
+ const auto& components = CServiceBroker::GetAppComponents();
+ auto res = components.GetComponent<CApplicationPlayer>();
+ return res;
+}
+
+std::shared_ptr<CApplicationPlayer> getAppPlayerMut()
+{
+ auto& components = CServiceBroker::GetAppComponents();
+ auto res = components.GetComponent<CApplicationPlayer>();
+ return res;
+}
+
+} // namespace
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ PlayParameter Player::defaultPlayParameter;
+
+ Player::Player()
+ {
+ iPlayList = PLAYLIST::TYPE_MUSIC;
+
+ // now that we're done, register hook me into the system
+ if (languageHook)
+ {
+ DelayedCallGuard dc(languageHook);
+ languageHook->RegisterPlayerCallback(this);
+ }
+ }
+
+ Player::~Player()
+ {
+ deallocating();
+
+ // we're shutting down so unregister me.
+ if (languageHook)
+ {
+ DelayedCallGuard dc(languageHook);
+ languageHook->UnregisterPlayerCallback(this);
+ }
+ }
+
+ void Player::play(const Alternative<String, const PlayList* > & item,
+ const XBMCAddon::xbmcgui::ListItem* listitem, bool windowed, int startpos)
+ {
+ XBMC_TRACE;
+
+ if (&item == &defaultPlayParameter)
+ playCurrent(windowed);
+ else if (item.which() == XBMCAddon::first)
+ playStream(item.former(), listitem, windowed);
+ else // item is a PlayListItem
+ playPlaylist(item.later(),windowed,startpos);
+ }
+
+ void Player::playStream(const String& item, const xbmcgui::ListItem* plistitem, bool windowed)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dc(languageHook);
+ if (!item.empty())
+ {
+ // set fullscreen or windowed
+ CMediaSettings::GetInstance().SetMediaStartWindowed(windowed);
+
+ const AddonClass::Ref<xbmcgui::ListItem> listitem(plistitem);
+
+ if (listitem.isSet())
+ {
+ // set m_strPath to the passed url
+ listitem->item->SetPath(item.c_str());
+ CServiceBroker::GetAppMessenger()->PostMsg(
+ TMSG_MEDIA_PLAY, 0, 0, static_cast<void*>(new CFileItem(*listitem->item)));
+ }
+ else
+ {
+ CFileItemList *l = new CFileItemList; //don't delete,
+ l->Add(std::make_shared<CFileItem>(item, false));
+ CServiceBroker::GetAppMessenger()->PostMsg(TMSG_MEDIA_PLAY, -1, -1,
+ static_cast<void*>(l));
+ }
+ }
+ else
+ playCurrent(windowed);
+ }
+
+ void Player::playCurrent(bool windowed)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dc(languageHook);
+ // set fullscreen or windowed
+ CMediaSettings::GetInstance().SetMediaStartWindowed(windowed);
+
+ // play current file in playlist
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != iPlayList)
+ CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(iPlayList);
+ CServiceBroker::GetAppMessenger()->SendMsg(
+ TMSG_PLAYLISTPLAYER_PLAY, CServiceBroker::GetPlaylistPlayer().GetCurrentSong());
+ }
+
+ void Player::playPlaylist(const PlayList* playlist, bool windowed, int startpos)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dc(languageHook);
+ if (playlist != NULL)
+ {
+ // set fullscreen or windowed
+ CMediaSettings::GetInstance().SetMediaStartWindowed(windowed);
+
+ // play a python playlist (a playlist from playlistplayer.cpp)
+ iPlayList = playlist->getPlayListId();
+ CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(iPlayList);
+ if (startpos > -1)
+ CServiceBroker::GetPlaylistPlayer().SetCurrentSong(startpos);
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_PLAYLISTPLAYER_PLAY, startpos);
+ }
+ else
+ playCurrent(windowed);
+ }
+
+ void Player::stop()
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_STOP);
+ }
+
+ void Player::pause()
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_MEDIA_PAUSE);
+ }
+
+ void Player::playnext()
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dc(languageHook);
+
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_PLAYLISTPLAYER_NEXT);
+ }
+
+ void Player::playprevious()
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dc(languageHook);
+
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_PLAYLISTPLAYER_PREV);
+ }
+
+ void Player::playselected(int selected)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dc(languageHook);
+
+ if (CServiceBroker::GetPlaylistPlayer().GetCurrentPlaylist() != iPlayList)
+ {
+ CServiceBroker::GetPlaylistPlayer().SetCurrentPlaylist(iPlayList);
+ }
+ CServiceBroker::GetPlaylistPlayer().SetCurrentSong(selected);
+
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_PLAYLISTPLAYER_PLAY, selected);
+ //CServiceBroker::GetPlaylistPlayer().Play(selected);
+ //CLog::Log(LOGINFO, "Current Song After Play: {}", CServiceBroker::GetPlaylistPlayer().GetCurrentSong());
+ }
+
+ void Player::OnPlayBackStarted(const CFileItem &file)
+ {
+ // We only have fileItem due to us having to
+ // implement the interface, we can't send it to python
+ // as we're not able to serialize it.
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this, &Player::onPlayBackStarted));
+ }
+
+ void Player::OnAVStarted(const CFileItem &file)
+ {
+ // We only have fileItem due to us having to
+ // implement the interface, we can't send it to python
+ // as we're not able to serialize it.
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this, &Player::onAVStarted));
+ }
+
+ void Player::OnAVChange()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this, &Player::onAVChange));
+ }
+
+ void Player::OnPlayBackEnded()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this,&Player::onPlayBackEnded));
+ }
+
+ void Player::OnPlayBackStopped()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this,&Player::onPlayBackStopped));
+ }
+
+ void Player::OnPlayBackError()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this,&Player::onPlayBackError));
+ }
+
+ void Player::OnPlayBackPaused()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this,&Player::onPlayBackPaused));
+ }
+
+ void Player::OnPlayBackResumed()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this,&Player::onPlayBackResumed));
+ }
+
+ void Player::OnQueueNextItem()
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player>(this,&Player::onQueueNextItem));
+ }
+
+ void Player::OnPlayBackSpeedChanged(int speed)
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player,int>(this,&Player::onPlayBackSpeedChanged,speed));
+ }
+
+ void Player::OnPlayBackSeek(int64_t time, int64_t seekOffset)
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player,int,int>(this,&Player::onPlayBackSeek,static_cast<int>(time),static_cast<int>(seekOffset)));
+ }
+
+ void Player::OnPlayBackSeekChapter(int chapter)
+ {
+ XBMC_TRACE;
+ invokeCallback(new CallbackFunction<Player,int>(this,&Player::onPlayBackSeekChapter,chapter));
+ }
+
+ void Player::onPlayBackStarted()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onAVStarted()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onAVChange()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackEnded()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackStopped()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackError()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackPaused()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackResumed()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onQueueNextItem()
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackSpeedChanged(int speed)
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackSeek(int time, int seekOffset)
+ {
+ XBMC_TRACE;
+ }
+
+ void Player::onPlayBackSeekChapter(int chapter)
+ {
+ XBMC_TRACE;
+ }
+
+ bool Player::isPlaying()
+ {
+ XBMC_TRACE;
+ return getAppPlayer()->IsPlaying();
+ }
+
+ bool Player::isPlayingAudio()
+ {
+ XBMC_TRACE;
+ return getAppPlayer()->IsPlayingAudio();
+ }
+
+ bool Player::isPlayingVideo()
+ {
+ XBMC_TRACE;
+ return getAppPlayer()->IsPlayingVideo();
+ }
+
+ bool Player::isPlayingRDS()
+ {
+ XBMC_TRACE;
+ return getAppPlayer()->IsPlayingRDS();
+ }
+
+ bool Player::isPlayingGame()
+ {
+ XBMC_TRACE;
+ return getAppPlayer()->IsPlayingGame();
+ }
+
+ bool Player::isExternalPlayer()
+ {
+ XBMC_TRACE;
+ return getAppPlayer()->IsExternalPlaying();
+ }
+
+ String Player::getPlayingFile()
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlaying())
+ throw PlayerException("Kodi is not playing any file");
+
+ return g_application.CurrentFileItem().GetDynPath();
+ }
+
+ XBMCAddon::xbmcgui::ListItem* Player::getPlayingItem()
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlaying())
+ throw PlayerException("Kodi is not playing any item");
+
+ CFileItemPtr itemPtr = std::make_shared<CFileItem>(g_application.CurrentFileItem());
+ return new XBMCAddon::xbmcgui::ListItem(itemPtr);
+ }
+
+ InfoTagVideo* Player::getVideoInfoTag()
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlayingVideo())
+ throw PlayerException("Kodi is not playing any videofile");
+
+ const CVideoInfoTag* movie = CServiceBroker::GetGUI()->GetInfoManager().GetCurrentMovieTag();
+ if (movie)
+ return new InfoTagVideo(movie);
+
+ return new InfoTagVideo(true);
+ }
+
+ InfoTagMusic* Player::getMusicInfoTag()
+ {
+ XBMC_TRACE;
+ if (getAppPlayer()->IsPlayingVideo() || !getAppPlayer()->IsPlayingAudio())
+ throw PlayerException("Kodi is not playing any music file");
+
+ const MUSIC_INFO::CMusicInfoTag* tag = CServiceBroker::GetGUI()->GetInfoManager().GetCurrentSongTag();
+ if (tag)
+ return new InfoTagMusic(tag);
+
+ return new InfoTagMusic(true);
+ }
+
+ void Player::updateInfoTag(const XBMCAddon::xbmcgui::ListItem* item)
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlaying())
+ throw PlayerException("Kodi is not playing any file");
+
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_UPDATE_ITEM, 0, item->item);
+ CServiceBroker::GetGUI()->GetWindowManager().SendMessage(msg);
+ }
+
+ InfoTagGame* Player::getGameInfoTag()
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlayingGame())
+ throw PlayerException("Kodi is not playing any game file");
+
+ const KODI::GAME::CGameInfoTag* game =
+ CServiceBroker::GetGUI()->GetInfoManager().GetCurrentGameTag();
+ if (game)
+ return new InfoTagGame(game);
+
+ return new InfoTagGame();
+ }
+
+ InfoTagRadioRDS* Player::getRadioRDSInfoTag()
+ {
+ XBMC_TRACE;
+ if (getAppPlayer()->IsPlayingVideo() || !getAppPlayer()->IsPlayingRDS())
+ throw PlayerException("Kodi is not playing any music file with RDS");
+
+ std::shared_ptr<CFileItem> item = g_application.CurrentFileItemPtr();
+ if (item && item->HasPVRChannelInfoTag())
+ return new InfoTagRadioRDS(item->GetPVRChannelInfoTag());
+
+ return new InfoTagRadioRDS();
+ }
+
+ double Player::getTotalTime()
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlaying())
+ throw PlayerException("Kodi is not playing any media file");
+
+ return g_application.GetTotalTime();
+ }
+
+ double Player::getTime()
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlaying())
+ throw PlayerException("Kodi is not playing any media file");
+
+ return g_application.GetTime();
+ }
+
+ void Player::seekTime(double pTime)
+ {
+ XBMC_TRACE;
+ if (!getAppPlayer()->IsPlaying())
+ throw PlayerException("Kodi is not playing any media file");
+
+ g_application.SeekTime( pTime );
+ }
+
+ void Player::setSubtitles(const char* cLine)
+ {
+ XBMC_TRACE;
+ if (getAppPlayer()->HasPlayer())
+ {
+ getAppPlayerMut()->AddSubtitle(cLine);
+ }
+ }
+
+ void Player::showSubtitles(bool bVisible)
+ {
+ XBMC_TRACE;
+ if (getAppPlayer()->HasPlayer())
+ {
+ getAppPlayerMut()->SetSubtitleVisible(bVisible != 0);
+ }
+ }
+
+ String Player::getSubtitles()
+ {
+ XBMC_TRACE;
+ if (getAppPlayer()->HasPlayer())
+ {
+ SubtitleStreamInfo info;
+ getAppPlayerMut()->GetSubtitleStreamInfo(CURRENT_STREAM, info);
+
+ if (info.language.length() > 0)
+ return info.language;
+ else
+ return info.name;
+ }
+
+ return "";
+ }
+
+ std::vector<String> Player::getAvailableSubtitleStreams()
+ {
+ if (getAppPlayer()->HasPlayer())
+ {
+ int subtitleCount = getAppPlayer()->GetSubtitleCount();
+ std::vector<String> ret(subtitleCount);
+ for (int iStream=0; iStream < subtitleCount; iStream++)
+ {
+ SubtitleStreamInfo info;
+ getAppPlayer()->GetSubtitleStreamInfo(iStream, info);
+
+ if (info.language.length() > 0)
+ ret[iStream] = info.language;
+ else
+ ret[iStream] = info.name;
+ }
+ return ret;
+ }
+
+ return std::vector<String>();
+ }
+
+ void Player::setSubtitleStream(int iStream)
+ {
+ if (getAppPlayer()->HasPlayer())
+ {
+ int streamCount = getAppPlayer()->GetSubtitleCount();
+ if(iStream < streamCount)
+ {
+ getAppPlayerMut()->SetSubtitle(iStream);
+ getAppPlayerMut()->SetSubtitleVisible(true);
+ }
+ }
+ }
+
+ std::vector<String> Player::getAvailableAudioStreams()
+ {
+ if (getAppPlayer()->HasPlayer())
+ {
+ int streamCount = getAppPlayer()->GetAudioStreamCount();
+ std::vector<String> ret(streamCount);
+ for (int iStream=0; iStream < streamCount; iStream++)
+ {
+ AudioStreamInfo info;
+ getAppPlayerMut()->GetAudioStreamInfo(iStream, info);
+
+ if (info.language.length() > 0)
+ ret[iStream] = info.language;
+ else
+ ret[iStream] = info.name;
+ }
+ return ret;
+ }
+
+ return std::vector<String>();
+ }
+
+ void Player::setAudioStream(int iStream)
+ {
+ if (getAppPlayer()->HasPlayer())
+ {
+ int streamCount = getAppPlayer()->GetAudioStreamCount();
+ if (iStream < streamCount)
+ getAppPlayerMut()->SetAudioStream(iStream);
+ }
+ }
+
+ std::vector<String> Player::getAvailableVideoStreams()
+ {
+ int streamCount = getAppPlayer()->GetVideoStreamCount();
+ std::vector<String> ret(streamCount);
+ for (int iStream = 0; iStream < streamCount; ++iStream)
+ {
+ VideoStreamInfo info;
+ getAppPlayer()->GetVideoStreamInfo(iStream, info);
+
+ if (info.language.length() > 0)
+ ret[iStream] = info.language;
+ else
+ ret[iStream] = info.name;
+ }
+ return ret;
+ }
+
+ void Player::setVideoStream(int iStream)
+ {
+ int streamCount = getAppPlayer()->GetVideoStreamCount();
+ if (iStream < streamCount)
+ getAppPlayerMut()->SetVideoStream(iStream);
+ }
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/Player.h b/xbmc/interfaces/legacy/Player.h
new file mode 100644
index 0000000..b700597
--- /dev/null
+++ b/xbmc/interfaces/legacy/Player.h
@@ -0,0 +1,824 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonCallback.h"
+#include "AddonString.h"
+#include "Alternative.h"
+#include "Exception.h"
+#include "InfoTagGame.h"
+#include "InfoTagMusic.h"
+#include "InfoTagRadioRDS.h"
+#include "InfoTagVideo.h"
+#include "ListItem.h"
+#include "PlayList.h"
+#include "cores/IPlayerCallback.h"
+#include "swighelper.h"
+
+#include <vector>
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(PlayerException);
+
+ typedef Alternative<String, const PlayList* > PlayParameter;
+
+ // This class is a merge of what was previously in xbmcmodule/player.h
+ // and xbmcmodule/PythonPlayer.h without the python references. The
+ // queuing and handling of asynchronous callbacks is done internal to
+ // this class.
+
+ //
+ /// \defgroup python_Player Player
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's player.**
+ ///
+ /// \python_class{ xbmc.Player() }
+ ///
+ /// To become and create the class to play something.
+ ///
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// xbmc.Player().play(url, listitem, windowed)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ //
+ class Player : public AddonCallback, public IPlayerCallback
+ {
+ private:
+ int iPlayList;
+
+ void playStream(const String& item = emptyString, const XBMCAddon::xbmcgui::ListItem* listitem = NULL, bool windowed = false);
+ void playPlaylist(const PlayList* playlist = NULL,
+ bool windowed = false, int startpos=-1);
+ void playCurrent(bool windowed = false);
+
+ public:
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ static PlayParameter defaultPlayParameter;
+#endif
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+ // Construct a Player proxying the given generated binding. The
+ // construction of a Player needs to identify whether or not any
+ // callbacks will be executed asynchronously or not.
+ explicit Player();
+ ~Player(void) override;
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ play([item, listitem, windowed, startpos]) }
+ /// Play an item.
+ ///
+ /// @param item [opt] string - filename, url or playlist
+ /// @param listitem [opt] listitem - used with setInfo() to set
+ /// different infolabels.
+ /// @param windowed [opt] bool - true=play video windowed,
+ /// false=play users preference.(default)
+ /// @param startpos [opt] int - starting position when playing
+ /// a playlist. Default = -1
+ ///
+ /// @note If item is not given then the Player will try to play the
+ /// current item in the current playlist.\n
+ /// \n
+ /// You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.
+ ///
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// listitem = xbmcgui.ListItem('Ironman')
+ /// listitem.setInfo('video', {'Title': 'Ironman', 'Genre': 'Science Fiction'})
+ /// xbmc.Player().play(url, listitem, windowed)
+ /// xbmc.Player().play(playlist, listitem, windowed, startpos)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ play(...);
+#else
+ void play(const PlayParameter& item = Player::defaultPlayParameter,
+ const XBMCAddon::xbmcgui::ListItem* listitem = NULL, bool windowed = false, int startpos = -1);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ stop() }
+ /// Stop playing.
+ ///
+ stop();
+#else
+ void stop();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ pause() }
+ /// Pause or resume playing if already paused.
+ ///
+ pause();
+#else
+ void pause();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ playnext() }
+ /// Play next item in playlist.
+ ///
+ playnext();
+#else
+ void playnext();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ playprevious() }
+ /// Play previous item in playlist.
+ ///
+ playprevious();
+#else
+ void playprevious();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ playselected(selected) }
+ /// Play a certain item from the current playlist.
+ ///
+ /// @param selected Integer - Item to select
+ ///
+ playselected(...);
+#else
+ void playselected(int selected);
+#endif
+
+ //
+ /// @defgroup python_PlayerCB Callback functions from Kodi to Add-On
+ /// \ingroup python_Player
+ /// @{
+ /// @brief **Callback functions.**
+ ///
+ /// Functions to handle control callbacks from Kodi to Add-On.
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// @link python_Player Go back to normal functions from player@endlink
+ //
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackStarted() }
+ /// onPlayBackStarted method.
+ ///
+ /// Will be called when Kodi player starts. Video or audio might not be available at this point.
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 Use onAVStarted() instead if you need to detect if Kodi is actually playing a media file
+ /// (i.e, if a stream is available)
+ ///
+ onPlayBackStarted();
+#else
+ virtual void onPlayBackStarted();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onAVStarted() }
+ /// onAVStarted method.
+ ///
+ /// Will be called when Kodi has a video or audiostream.
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ onAVStarted();
+#else
+ virtual void onAVStarted();
+#endif
+
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onAVChange() }
+ /// onAVChange method.
+ ///
+ /// Will be called when Kodi has a video, audio or subtitle stream. Also happens when the stream changes.
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ onAVChange();
+#else
+ virtual void onAVChange();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackEnded() }
+ /// onPlayBackEnded method.
+ ///
+ /// Will be called when Kodi stops playing a file.
+ ///
+ onPlayBackEnded();
+#else
+ virtual void onPlayBackEnded();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackStopped() }
+ /// onPlayBackStopped method.
+ ///
+ /// Will be called when user stops Kodi playing a file.
+ ///
+ onPlayBackStopped();
+#else
+ virtual void onPlayBackStopped();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackError() }
+ /// onPlayBackError method.
+ ///
+ /// Will be called when playback stops due to an error.
+ ///
+ onPlayBackError();
+#else
+ virtual void onPlayBackError();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackPaused() }
+ /// onPlayBackPaused method.
+ ///
+ /// Will be called when user pauses a playing file.
+ ///
+ onPlayBackPaused();
+#else
+ virtual void onPlayBackPaused();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackResumed() }
+ /// onPlayBackResumed method.
+ ///
+ /// Will be called when user resumes a paused file.
+ ///
+ onPlayBackResumed();
+#else
+ virtual void onPlayBackResumed();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onQueueNextItem() }
+ /// onQueueNextItem method.
+ ///
+ /// Will be called when user queues the next item.
+ ///
+ onQueueNextItem();
+#else
+ virtual void onQueueNextItem();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackSpeedChanged(speed) }
+ /// onPlayBackSpeedChanged method.
+ ///
+ /// Will be called when players speed changes (eg. user FF/RW).
+ ///
+ /// @param speed [integer] Current speed of player
+ ///
+ /// @note Negative speed means player is rewinding, 1 is normal playback
+ /// speed.
+ ///
+ onPlayBackSpeedChanged(int speed);
+#else
+ virtual void onPlayBackSpeedChanged(int speed);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackSeek(time, seekOffset) }
+ /// onPlayBackSeek method.
+ ///
+ /// Will be called when user seeks to a time.
+ ///
+ /// @param time [integer] Time to seek to
+ /// @param seekOffset [integer] ?
+ ///
+ onPlayBackSeek(...);
+#else
+ virtual void onPlayBackSeek(int time, int seekOffset);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_PlayerCB
+ /// @brief \python_func{ onPlayBackSeekChapter(chapter) }
+ /// onPlayBackSeekChapter method.
+ ///
+ /// Will be called when user performs a chapter seek.
+ ///
+ /// @param chapter [integer] Chapter to seek to
+ ///
+ onPlayBackSeekChapter(...);
+#else
+ virtual void onPlayBackSeekChapter(int chapter);
+#endif
+ /// @}
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ isPlaying() }
+ /// Check Kodi is playing something.
+ ///
+ /// @return True if Kodi is playing a file.
+ ///
+ isPlaying();
+#else
+ bool isPlaying();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ isPlayingAudio() }
+ /// Check for playing audio.
+ ///
+ /// @return True if Kodi is playing an audio file.
+ ///
+ isPlayingAudio();
+#else
+ bool isPlayingAudio();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ isPlayingVideo() }
+ /// Check for playing video.
+ ///
+ /// @return True if Kodi is playing a video.
+ ///
+ isPlayingVideo();
+#else
+ bool isPlayingVideo();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ isPlayingRDS() }
+ /// Check for playing radio data system (RDS).
+ ///
+ /// @return True if kodi is playing a radio data
+ /// system (RDS).
+ ///
+ isPlayingRDS();
+#else
+ bool isPlayingRDS();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ isPlayingGame() }
+ /// Check for playing game.
+ ///
+ /// @return True if kodi is playing a game
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ isPlayingGame();
+#else
+ bool isPlayingGame();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ isExternalPlayer() }
+ /// Check for external player.
+ ///
+ /// @return True if kodi is playing using an
+ /// external player.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 New function added.
+ ///
+ isExternalPlayer();
+#else
+ bool isExternalPlayer();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getPlayingFile() }
+ /// Returns the current playing file as a string.
+ ///
+ /// @note For LiveTV, returns a __pvr://__ url which is not translatable
+ /// to an OS specific file or external url.
+ ///
+ /// @return Playing filename
+ /// @throws Exception If player is not playing a file.
+ ///
+ getPlayingFile();
+#else
+ String getPlayingFile();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getPlayingItem() }
+ /// Returns the current playing item.
+ ///
+ /// @return Playing item
+ /// @throws Exception If player is not playing a file.
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getPlayingItem();
+#else
+ XBMCAddon::xbmcgui::ListItem* getPlayingItem();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getTime() }
+ /// Get playing time.
+ ///
+ /// Returns the current time of the current playing media as fractional
+ /// seconds.
+ ///
+ /// @return Current time as fractional seconds
+ /// @throws Exception If player is not playing a file.
+ ///
+ getTime();
+#else
+ double getTime();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ seekTime(seekTime) }
+ /// Seek time.
+ ///
+ /// Seeks the specified amount of time as fractional seconds.
+ /// The time specified is relative to the beginning of the currently.
+ /// playing media file.
+ ///
+ /// @param seekTime Time to seek as fractional seconds
+ /// @throws Exception If player is not playing a file.
+ ///
+ seekTime(...);
+#else
+ void seekTime(double seekTime);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ setSubtitles(subtitleFile) }
+ /// Set subtitle file and enable subtitles.
+ ///
+ /// @param subtitleFile File to use as source ofsubtitles
+ ///
+ setSubtitles(...);
+#else
+ void setSubtitles(const char* subtitleFile);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ showSubtitles(visible) }
+ /// Enable / disable subtitles.
+ ///
+ /// @param visible [boolean] True for visible subtitles.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// xbmc.Player().showSubtitles(True)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ showSubtitles(...);
+#else
+ void showSubtitles(bool bVisible);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getSubtitles() }
+ /// Get subtitle stream name.
+ ///
+ /// @return Stream name
+ ///
+ getSubtitles();
+#else
+ String getSubtitles();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getAvailableSubtitleStreams() }
+ /// Get Subtitle stream names.
+ ///
+ /// @return List of subtitle streams as name
+ ///
+ getAvailableSubtitleStreams();
+#else
+ std::vector<String> getAvailableSubtitleStreams();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ setSubtitleStream(stream) }
+ /// Set Subtitle Stream.
+ ///
+ /// @param iStream [int] Subtitle stream to select for play
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// xbmc.Player().setSubtitleStream(1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setSubtitleStream(...);
+#else
+ void setSubtitleStream(int iStream);
+#endif
+
+ // Player_UpdateInfoTag
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ updateInfoTag(item) }
+ /// Update info labels for currently playing item.
+ ///
+ /// @param item ListItem with new info
+ ///
+ /// @throws Exception If player is not playing a file
+ ///
+ /// @python_v18 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// item = xbmcgui.ListItem()
+ /// item.setPath(xbmc.Player().getPlayingFile())
+ /// item.setInfo('music', {'title' : 'foo', 'artist' : 'bar'})
+ /// xbmc.Player().updateInfoTag(item)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ updateInfoTag();
+#else
+ void updateInfoTag(const XBMCAddon::xbmcgui::ListItem* item);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getGameInfoTag() }
+ /// To get game info tag.
+ ///
+ /// Returns the GameInfoTag of the current playing game.
+ ///
+ /// @return Game info tag
+ /// @throws Exception If player is not playing a file or current
+ /// file is not a game file.
+ ///
+ ///------------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ getGameInfoTag();
+#else
+ InfoTagGame* getGameInfoTag();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getVideoInfoTag() }
+ /// To get video info tag.
+ ///
+ /// Returns the VideoInfoTag of the current playing Movie.
+ ///
+ /// @return Video info tag
+ /// @throws Exception If player is not playing a file or current
+ /// file is not a movie file.
+ ///
+ getVideoInfoTag();
+#else
+ InfoTagVideo* getVideoInfoTag();
+#endif
+
+ // Player_GetMusicInfoTag
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getMusicInfoTag() }
+ /// To get music info tag.
+ ///
+ /// Returns the MusicInfoTag of the current playing 'Song'.
+ ///
+ /// @return Music info tag
+ /// @throws Exception If player is not playing a file or current
+ /// file is not a music file.
+ ///
+ getMusicInfoTag();
+#else
+ InfoTagMusic* getMusicInfoTag();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getRadioRDSInfoTag() }
+ /// To get Radio RDS info tag
+ ///
+ /// Returns the RadioRDSInfoTag of the current playing 'Radio Song if.
+ /// present'.
+ ///
+ /// @return Radio RDS info tag
+ /// @throws Exception If player is not playing a file or current
+ /// file is not a rds file.
+ ///
+ getRadioRDSInfoTag();
+#else
+ InfoTagRadioRDS* getRadioRDSInfoTag();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getTotalTime() }
+ /// To get total playing time.
+ ///
+ /// Returns the total time of the current playing media in seconds.
+ /// This is only accurate to the full second.
+ ///
+ /// @return Total time of the current playing media
+ /// @throws Exception If player is not playing a file.
+ ///
+ getTotalTime();
+#else
+ double getTotalTime();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getAvailableAudioStreams() }
+ /// Get Audio stream names
+ ///
+ /// @return List of audio streams as name
+ ///
+ getAvailableAudioStreams();
+#else
+ std::vector<String> getAvailableAudioStreams();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ setAudioStream(stream) }
+ /// Set Audio Stream.
+ ///
+ /// @param iStream [int] Audio stream to select for play
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// xbmc.Player().setAudioStream(1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setAudioStream(...);
+#else
+ void setAudioStream(int iStream);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ getAvailableVideoStreams() }
+ /// Get Video stream names
+ ///
+ /// @return List of video streams as name
+ ///
+ getAvailableVideoStreams();
+#else
+ std::vector<String> getAvailableVideoStreams();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_Player
+ /// @brief \python_func{ setVideoStream(stream) }
+ /// Set Video Stream.
+ ///
+ /// @param iStream [int] Video stream to select for play
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ...
+ /// xbmc.Player().setVideoStream(1)
+ /// ...
+ /// ~~~~~~~~~~~~~
+ ///
+ setVideoStream(...);
+#else
+ void setVideoStream(int iStream);
+#endif
+
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ void OnPlayBackStarted(const CFileItem& file) override;
+ void OnAVStarted(const CFileItem& file) override;
+ void OnAVChange() override;
+ void OnPlayBackEnded() override;
+ void OnPlayBackStopped() override;
+ void OnPlayBackError() override;
+ void OnPlayBackPaused() override;
+ void OnPlayBackResumed() override;
+ void OnQueueNextItem() override;
+ void OnPlayBackSpeedChanged(int iSpeed) override;
+ void OnPlayBackSeek(int64_t iTime, int64_t seekOffset) override;
+ void OnPlayBackSeekChapter(int iChapter) override;
+#endif
+
+ protected:
+ };
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/RenderCapture.h b/xbmc/interfaces/legacy/RenderCapture.h
new file mode 100644
index 0000000..cf1b931
--- /dev/null
+++ b/xbmc/interfaces/legacy/RenderCapture.h
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "Exception.h"
+#include "ServiceBroker.h"
+#include "application/ApplicationComponents.h"
+#include "application/ApplicationPlayer.h"
+#include "commons/Buffer.h"
+
+#include <climits>
+
+namespace XBMCAddon
+{
+ namespace xbmc
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(RenderCaptureException);
+
+ //
+ /// \defgroup python_xbmc_RenderCapture RenderCapture
+ /// \ingroup python_xbmc
+ /// @{
+ /// @brief **Kodi's render capture.**
+ ///
+ /// \python_class{ RenderCapture() }
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ //
+ class RenderCapture : public AddonClass
+ {
+ unsigned int m_captureId;
+ unsigned int m_width;
+ unsigned int m_height;
+ uint8_t *m_buffer;
+
+ public:
+ inline RenderCapture()
+ {
+ m_captureId = UINT_MAX;
+ m_buffer = nullptr;
+ m_width = 0;
+ m_height = 0;
+ }
+ inline ~RenderCapture() override
+ {
+ auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ appPlayer->RenderCaptureRelease(m_captureId);
+ delete [] m_buffer;
+ }
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_RenderCapture
+ /// @brief \python_func{ getWidth() }
+ /// Get width
+ ///
+ /// To get width of captured image as set during RenderCapture.capture().
+ /// Returns 0 prior to calling capture.
+ ///
+ /// @return Width or 0 prior to calling capture
+ ///
+ getWidth();
+#else
+ inline int getWidth() { return m_width; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_RenderCapture
+ /// @brief \python_func{ getHeight() }
+ /// Get height
+ ///
+ /// To get height of captured image as set during RenderCapture.capture().
+ /// Returns 0 prior to calling capture.
+ ///
+ /// @return height or 0 prior to calling capture
+ getHeight();
+#else
+ inline int getHeight() { return m_height; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_RenderCapture
+ /// @brief \python_func{ getAspectRatio() }
+ /// Get aspect ratio of currently displayed video.
+ ///
+ /// @return Aspect ratio
+ /// @warning This may be called prior to calling RenderCapture.capture().
+ ///
+ getAspectRatio();
+#else
+ inline float getAspectRatio()
+ {
+ const auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ return appPlayer->GetRenderAspectRatio();
+ }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_RenderCapture
+ /// @brief \python_func{ getImageFormat() }
+ /// Get image format
+ ///
+ /// @return Format of captured image: 'BGRA'
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 Image will now always be returned in BGRA
+ ///
+ getImageFormat()
+#else
+ inline const char* getImageFormat()
+#endif
+ {
+ return "BGRA";
+ }
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_RenderCapture
+ /// @brief \python_func{ getImage([msecs]) }
+ /// Returns captured image as a bytearray.
+ ///
+ /// @param msecs [opt] Milliseconds to wait. Waits
+ /// 1000ms if not specified
+ /// @return Captured image as a bytearray
+ ///
+ /// @note The size of the image is m_width * m_height * 4
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 Added the option to specify wait time in msec.
+ ///
+ getImage(...)
+#else
+ inline XbmcCommons::Buffer getImage(unsigned int msecs = 0)
+#endif
+ {
+ if (!GetPixels(msecs))
+ return XbmcCommons::Buffer(0);
+
+ size_t size = m_width * m_height * 4;
+ return XbmcCommons::Buffer(m_buffer, size);
+ }
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmc_RenderCapture
+ /// @brief \python_func{ capture(width, height) }
+ /// Issue capture request.
+ ///
+ /// @param width Width capture image should be rendered to
+ /// @param height Height capture image should should be rendered to
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v17 Removed the option to pass **flags**
+ ///
+ capture(...)
+#else
+ inline void capture(int width, int height)
+#endif
+ {
+ auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+
+ if (m_buffer)
+ {
+ appPlayer->RenderCaptureRelease(m_captureId);
+ delete [] m_buffer;
+ }
+ m_captureId = appPlayer->RenderCaptureAlloc();
+ m_width = width;
+ m_height = height;
+ m_buffer = new uint8_t[m_width*m_height*4];
+ appPlayer->RenderCapture(m_captureId, m_width, m_height, CAPTUREFLAG_CONTINUOUS);
+ }
+
+// hide these from swig
+#ifndef SWIG
+ inline bool GetPixels(unsigned int msec)
+ {
+ auto& components = CServiceBroker::GetAppComponents();
+ const auto appPlayer = components.GetComponent<CApplicationPlayer>();
+ return appPlayer->RenderCaptureGetPixels(m_captureId, msec, m_buffer,
+ m_width * m_height * 4);
+ }
+#endif
+
+ };
+ //@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/Settings.cpp b/xbmc/interfaces/legacy/Settings.cpp
new file mode 100644
index 0000000..0ba77c3
--- /dev/null
+++ b/xbmc/interfaces/legacy/Settings.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2017-2021 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 "Settings.h"
+
+#include "settings/SettingsBase.h"
+#include "settings/lib/Setting.h"
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+namespace XBMCAddon
+{
+namespace xbmcaddon
+{
+
+template<class TSetting>
+bool GetSettingValue(const std::shared_ptr<CSettingsBase>& settings,
+ const std::string& key,
+ typename TSetting::Value& value)
+{
+ if (key.empty() || !settings->IsLoaded())
+ return false;
+
+ auto setting = settings->GetSetting(key);
+ if (setting == nullptr || setting->GetType() != TSetting::Type())
+ return false;
+
+ value = std::static_pointer_cast<TSetting>(setting)->GetValue();
+ return true;
+}
+
+template<class TSetting>
+bool GetSettingValueList(const std::shared_ptr<CSettingsBase>& settings,
+ const std::string& key,
+ std::function<typename TSetting::Value(CVariant)> transform,
+ std::vector<typename TSetting::Value>& values)
+{
+ if (key.empty() || !settings->IsLoaded())
+ return false;
+
+ auto setting = settings->GetSetting(key);
+ if (setting == nullptr || setting->GetType() != SettingType::List ||
+ std::static_pointer_cast<CSettingList>(setting)->GetElementType() != TSetting::Type())
+ return false;
+
+ const auto variantValues = settings->GetList(key);
+ std::transform(variantValues.begin(), variantValues.end(), std::back_inserter(values), transform);
+ return true;
+}
+
+template<class TSetting>
+bool SetSettingValue(const std::shared_ptr<CSettingsBase>& settings,
+ const std::string& key,
+ typename TSetting::Value value)
+{
+ if (key.empty() || !settings->IsLoaded())
+ return false;
+
+ // try to get the setting
+ auto setting = settings->GetSetting(key);
+ if (setting == nullptr || setting->GetType() != TSetting::Type())
+ return false;
+
+ return std::static_pointer_cast<TSetting>(setting)->SetValue(value);
+}
+
+template<class TSetting>
+bool SetSettingValueList(const std::shared_ptr<CSettingsBase>& settings,
+ const std::string& key,
+ const std::vector<typename TSetting::Value>& values)
+{
+ if (key.empty() || !settings->IsLoaded())
+ return false;
+
+ // try to get the setting
+ auto setting = settings->GetSetting(key);
+ if (setting == nullptr || setting->GetType() != SettingType::List ||
+ std::static_pointer_cast<CSettingList>(setting)->GetElementType() != TSetting::Type())
+ return false;
+
+ std::vector<CVariant> variantValues;
+ std::transform(values.begin(), values.end(), std::back_inserter(variantValues),
+ [](typename TSetting::Value value) { return CVariant(value); });
+
+ return settings->SetList(key, variantValues);
+}
+
+Settings::Settings(std::shared_ptr<CSettingsBase> settings) : settings(std::move(settings))
+{
+}
+
+bool Settings::getBool(const char* id)
+{
+ bool value = false;
+ if (!GetSettingValue<CSettingBool>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"boolean\" for \"%s\"", id);
+
+ return value;
+}
+
+int Settings::getInt(const char* id)
+{
+ int value = 0;
+ if (!GetSettingValue<CSettingInt>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"integer\" for \"%s\"", id);
+
+ return value;
+}
+
+double Settings::getNumber(const char* id)
+{
+ double value = 0.0;
+ if (!GetSettingValue<CSettingNumber>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"number\" for \"%s\"", id);
+
+ return value;
+}
+
+String Settings::getString(const char* id)
+{
+ std::string value;
+ if (!GetSettingValue<CSettingString>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"string\" for \"%s\"", id);
+
+ return value;
+}
+
+std::vector<bool> Settings::getBoolList(const char* id)
+{
+ const auto transform = [](const CVariant& value) { return value.asBoolean(); };
+ std::vector<bool> values;
+ if (!GetSettingValueList<CSettingBool>(settings, id, transform, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[boolean]\" for \"%s\"", id);
+
+ return values;
+}
+
+std::vector<int> Settings::getIntList(const char* id)
+{
+ const auto transform = [](const CVariant& value) { return value.asInteger32(); };
+ std::vector<int> values;
+ if (!GetSettingValueList<CSettingInt>(settings, id, transform, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[integer]\" for \"%s\"", id);
+
+ return values;
+}
+
+std::vector<double> Settings::getNumberList(const char* id)
+{
+ const auto transform = [](const CVariant& value) { return value.asDouble(); };
+ std::vector<double> values;
+ if (!GetSettingValueList<CSettingNumber>(settings, id, transform, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[number]\" for \"%s\"", id);
+
+ return values;
+}
+
+std::vector<String> Settings::getStringList(const char* id)
+{
+ const auto transform = [](const CVariant& value) { return value.asString(); };
+ std::vector<std::string> values;
+ if (!GetSettingValueList<CSettingString>(settings, id, transform, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[string]\" for \"%s\"", id);
+
+ return values;
+}
+
+void Settings::setBool(const char* id, bool value)
+{
+ if (!SetSettingValue<CSettingBool>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"boolean\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setInt(const char* id, int value)
+{
+ if (!SetSettingValue<CSettingInt>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"integer\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setNumber(const char* id, double value)
+{
+ if (!SetSettingValue<CSettingNumber>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"number\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setString(const char* id, const String& value)
+{
+ if (!SetSettingValue<CSettingString>(settings, id, value))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"string\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setBoolList(const char* id, const std::vector<bool>& values)
+{
+ if (!SetSettingValueList<CSettingBool>(settings, id, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[boolean]\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setIntList(const char* id, const std::vector<int>& values)
+{
+ if (!SetSettingValueList<CSettingInt>(settings, id, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[integer]\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setNumberList(const char* id, const std::vector<double>& values)
+{
+ if (!SetSettingValueList<CSettingNumber>(settings, id, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[number]\" for \"%s\"", id);
+ settings->Save();
+}
+
+void Settings::setStringList(const char* id, const std::vector<String>& values)
+{
+ if (!SetSettingValueList<CSettingString>(settings, id, values))
+ throw XBMCAddon::WrongTypeException("Invalid setting type \"list[string]\" for \"%s\"", id);
+ settings->Save();
+}
+
+} // namespace xbmcaddon
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/Settings.h b/xbmc/interfaces/legacy/Settings.h
new file mode 100644
index 0000000..8b8bb0e
--- /dev/null
+++ b/xbmc/interfaces/legacy/Settings.h
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2017-2021 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 "commons/Exception.h"
+#include "interfaces/legacy/AddonClass.h"
+#include "interfaces/legacy/AddonString.h"
+#include "interfaces/legacy/Exception.h"
+#include "interfaces/legacy/Tuple.h"
+#include "settings/lib/SettingDefinitions.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+class CSettingsBase;
+
+namespace XBMCAddon
+{
+namespace xbmcaddon
+{
+
+XBMCCOMMONS_STANDARD_EXCEPTION(SettingCallbacksNotSupportedException);
+
+//
+/// \defgroup python_settings Settings
+/// \ingroup python_xbmcaddon
+/// @{
+/// @brief **Add-on settings**
+///
+/// \python_class{ Settings() }
+///
+/// This wrapper provides access to the settings specific to an add-on.
+/// It supports reading and writing specific setting values.
+///
+///-----------------------------------------------------------------------
+/// @python_v20 New class added.
+///
+/// **Example:**
+/// ~~~~~~~~~~~~~{.py}
+/// ...
+/// settings = xbmcaddon.Addon('id').getSettings()
+/// ...
+/// ~~~~~~~~~~~~~
+//
+class Settings : public AddonClass
+{
+public:
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ std::shared_ptr<CSettingsBase> settings;
+#endif
+
+#ifndef SWIG
+ Settings(std::shared_ptr<CSettingsBase> settings);
+#endif
+
+ virtual ~Settings() = default;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getBool(id) }
+ /// Returns the value of a setting as a boolean.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return bool - Setting as a boolean
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// enabled = settings.getBool('enabled')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getBool(...);
+#else
+ bool getBool(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getInt(id) }
+ /// Returns the value of a setting as an integer.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return integer - Setting as an integer
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// max = settings.getInt('max')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getInt(...);
+#else
+ int getInt(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getNumber(id) }
+ /// Returns the value of a setting as a floating point number.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return float - Setting as a floating point number
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// max = settings.getNumber('max')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getNumber(...);
+#else
+ double getNumber(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getString(id) }
+ /// Returns the value of a setting as a unicode string.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return string - Setting as a unicode string
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// apikey = settings.getString('apikey')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getString(...);
+#else
+ String getString(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getBoolList(id) }
+ /// Returns the value of a setting as a list of booleans.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return list - Setting as a list of booleans
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// enabled = settings.getBoolList('enabled')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getBoolList(...);
+#else
+ std::vector<bool> getBoolList(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getIntList(id) }
+ /// Returns the value of a setting as a list of integers.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return list - Setting as a list of integers
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// ids = settings.getIntList('ids')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getIntList(...);
+#else
+ std::vector<int> getIntList(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getNumberList(id) }
+ /// Returns the value of a setting as a list of floating point numbers.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return list - Setting as a list of floating point numbers
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// max = settings.getNumberList('max')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getNumberList(...);
+#else
+ std::vector<double> getNumberList(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ getStringList(id) }
+ /// Returns the value of a setting as a list of unicode strings.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @return list - Setting as a list of unicode strings
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// views = settings.getStringList('views')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getStringList(...);
+#else
+ std::vector<String> getStringList(const char* id);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setBool(id, value) }
+ /// Sets the value of a setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value bool - value of the setting.
+ /// @return bool - True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setBool(id='enabled', value=True)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setBool(...);
+#else
+ void setBool(const char* id, bool value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setInt(id, value) }
+ /// Sets the value of a setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value integer - value of the setting.
+ /// @return bool - True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setInt(id='max', value=5)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setInt(...);
+#else
+ void setInt(const char* id, int value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setNumber(id, value) }
+ /// Sets the value of a setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value float - value of the setting.
+ /// @return bool - True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setNumber(id='max', value=5.5)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setNumber(...);
+#else
+ void setNumber(const char* id, double value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setString(id, value) }
+ /// Sets the value of a setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param value string or unicode - value of the setting.
+ /// @return bool - True if the value of the setting was set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setString(id='username', value='teamkodi')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setString(...);
+#else
+ void setString(const char* id, const String& value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setBoolList(id, values) }
+ /// Sets the boolean values of a list setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param values list of boolean - values of the setting.
+ /// @return bool - True if the values of the setting were set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setBoolList(id='enabled', values=[ True, False ])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setBoolList(...);
+#else
+ void setBoolList(const char* id, const std::vector<bool>& values);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setIntList(id, value) }
+ /// Sets the integer values of a list setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param values list of int - values of the setting.
+ /// @return bool - True if the values of the setting were set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setIntList(id='max', values=[ 5, 23 ])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setIntList(...);
+#else
+ void setIntList(const char* id, const std::vector<int>& values);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setNumberList(id, value) }
+ /// Sets the floating point values of a list setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param values list of float - values of the setting.
+ /// @return bool - True if the values of the setting were set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setNumberList(id='max', values=[ 5.5, 5.8 ])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setNumberList(...);
+#else
+ void setNumberList(const char* id, const std::vector<double>& values);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_settings
+ /// @brief \python_func{ setStringList(id, value) }
+ /// Sets the string values of a list setting.
+ ///
+ /// @param id string - id of the setting that the module needs to access.
+ /// @param values list of string or unicode - values of the setting.
+ /// @return bool - True if the values of the setting were set, false otherwise
+ ///
+ ///
+ /// @note You can use the above as keywords for arguments.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v20 New function added.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// settings.setStringList(id='username', values=[ 'team', 'kodi' ])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setStringList(...);
+#else
+ void setStringList(const char* id, const std::vector<String>& values);
+#endif
+};
+//@}
+
+} // namespace xbmcaddon
+} // namespace XBMCAddon
diff --git a/xbmc/interfaces/legacy/Stat.h b/xbmc/interfaces/legacy/Stat.h
new file mode 100644
index 0000000..90a3843
--- /dev/null
+++ b/xbmc/interfaces/legacy/Stat.h
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonClass.h"
+#include "LanguageHook.h"
+#include "filesystem/File.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcvfs
+ {
+ //
+ /// \defgroup python_stat Stat
+ /// \ingroup python_xbmcvfs
+ /// @{
+ /// @brief **Get file or file system status.**
+ ///
+ /// \python_class{ xbmcvfs.Stat(path) }
+ ///
+ /// These class return information about a file. Execute (search) permission
+ /// is required on all of the directories in path that lead to the file.
+ ///
+ /// @param path [string] file or folder
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v12 New function added
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// st = xbmcvfs.Stat(path)
+ /// modified = st.st_mtime()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ //
+ class Stat : public AddonClass
+ {
+ struct __stat64 st;
+
+ public:
+ Stat(const String& path)
+ {
+ DelayedCallGuard dg;
+ XFILE::CFile::Stat(path, &st);
+ }
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_mode() }
+ /// To get file protection.
+ ///
+ /// @return st_mode
+ ///
+ st_mode();
+#else
+ inline long long st_mode() { return st.st_mode; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_ino() }
+ /// To get inode number.
+ ///
+ /// @return st_ino
+ ///
+ st_ino();
+#else
+ inline long long st_ino() { return st.st_ino; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_dev() }
+ /// To get ID of device containing file.
+ ///
+ /// The st_dev field describes the device on which this file resides.
+ ///
+ /// @return st_dev
+ ///
+ st_dev();
+#else
+ inline long long st_dev() { return st.st_dev; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_nlink() }
+ /// To get number of hard links.
+ ///
+ /// @return st_nlink
+ ///
+ st_nlink();
+#else
+ inline long long st_nlink() { return st.st_nlink; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_uid() }
+ /// To get user ID of owner.
+ ///
+ /// @return st_uid
+ ///
+ st_uid();
+#else
+ inline long long st_uid() { return st.st_uid; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_gid() }
+ /// To get group ID of owner.
+ ///
+ /// @return st_gid
+ ///
+ st_gid();
+#else
+ inline long long st_gid() { return st.st_gid; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_size() }
+ /// To get total size, in bytes.
+ ///
+ /// The st_size field gives the size of the file (if it is a regular file
+ /// or a symbolic link) in bytes. The size of a symbolic link (only on
+ /// Linux and Mac OS X) is the length of the pathname it contains, without
+ /// a terminating null byte.
+ ///
+ /// @return st_size
+ ///
+ st_size();
+#else
+ inline long long st_size() { return st.st_size; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_atime() }
+ /// To get time of last access.
+ ///
+ /// @return st_atime
+ ///
+ st_atime();
+#else
+ inline long long atime() { return st.st_atime; }; //names st_atime/st_mtime/st_ctime are used by sys/stat.h
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_mtime() }
+ /// To get time of last modification.
+ ///
+ /// @return st_mtime
+ ///
+ st_mtime();
+#else
+ inline long long mtime() { return st.st_mtime; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_stat
+ /// @brief \python_func{ st_ctime() }
+ /// To get time of last status change.
+ ///
+ /// @return st_ctime
+ ///
+ st_ctime();
+#else
+ inline long long ctime() { return st.st_ctime; }
+#endif
+ };
+ /// @}
+ }
+}
+
diff --git a/xbmc/interfaces/legacy/String.cpp b/xbmc/interfaces/legacy/String.cpp
new file mode 100644
index 0000000..cb172a2
--- /dev/null
+++ b/xbmc/interfaces/legacy/String.cpp
@@ -0,0 +1,14 @@
+/*
+ * 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 "AddonString.h"
+
+namespace XBMCAddon
+{
+ String emptyString;
+}
diff --git a/xbmc/interfaces/legacy/Tuple.h b/xbmc/interfaces/legacy/Tuple.h
new file mode 100644
index 0000000..116f307
--- /dev/null
+++ b/xbmc/interfaces/legacy/Tuple.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/**
+ * This file contains a few templates to define various length
+ * Tuples.
+ */
+namespace XBMCAddon
+{
+ struct tuple_null_type { };
+
+ class TupleBase
+ {
+ protected:
+ int numValuesSet;
+ explicit inline TupleBase(int pnumValuesSet) : numValuesSet(pnumValuesSet) {}
+ inline void nvs(int newSize) { if(numValuesSet < newSize) numValuesSet = newSize; }
+ public:
+ inline int GetNumValuesSet() const { return numValuesSet; }
+ };
+
+ // stub type template to be partial specialized
+ template<typename T1 = tuple_null_type, typename T2 = tuple_null_type,
+ typename T3 = tuple_null_type, typename T4 = tuple_null_type,
+ typename Extraneous = tuple_null_type> class Tuple {};
+
+ // Tuple that holds a single value
+ template<typename T1> class Tuple<T1, tuple_null_type, tuple_null_type, tuple_null_type, tuple_null_type> : public TupleBase
+ {
+ private:
+ T1 v1;
+ public:
+ explicit inline Tuple(T1 p1) : TupleBase(1), v1(p1) {}
+ inline Tuple() : TupleBase(0) {}
+ inline Tuple(const Tuple<T1>& o) : TupleBase(o), v1(o.v1) {}
+ Tuple<T1>& operator=(const Tuple<T1>& other) = default;
+
+ inline T1& first() { TupleBase::nvs(1); return v1; }
+ inline const T1& first() const { return v1; }
+ };
+
+ // Tuple that holds two values
+ template<typename T1, typename T2> class Tuple<T1, T2, tuple_null_type, tuple_null_type, tuple_null_type> : public Tuple<T1>
+ {
+ protected:
+ T2 v2;
+
+ public:
+ inline Tuple(T1 p1, T2 p2) : Tuple<T1>(p1), v2(p2) { TupleBase::nvs(2); }
+ explicit inline Tuple(T1 p1) : Tuple<T1>(p1) {}
+ inline Tuple() = default;
+ Tuple<T1, T2>& operator=(const Tuple<T1, T2>& other) = default;
+ inline Tuple(const Tuple<T1,T2>& o) : Tuple<T1>(o), v2(o.v2) {}
+
+ inline T2& second() { TupleBase::nvs(2); return v2; }
+ inline const T2& second() const { return v2; }
+ };
+
+ // Tuple that holds three values
+ template<typename T1, typename T2, typename T3> class Tuple<T1, T2, T3, tuple_null_type, tuple_null_type> : public Tuple<T1,T2>
+ {
+ private:
+ T3 v3;
+ public:
+ inline Tuple(T1 p1, T2 p2, T3 p3) : Tuple<T1,T2>(p1,p2), v3(p3) { TupleBase::nvs(3); }
+ inline Tuple(T1 p1, T2 p2) : Tuple<T1,T2>(p1,p2) {}
+ explicit inline Tuple(T1 p1) : Tuple<T1,T2>(p1) {}
+ inline Tuple() = default;
+ inline Tuple(const Tuple<T1,T2,T3>& o) : Tuple<T1,T2>(o), v3(o.v3) {}
+
+ inline T3& third() { TupleBase::nvs(3); return v3; }
+ inline const T3& third() const { return v3; }
+ };
+
+ // Tuple that holds four values
+ template<typename T1, typename T2, typename T3, typename T4> class Tuple<T1, T2, T3, T4, tuple_null_type> : public Tuple<T1,T2,T3>
+ {
+ private:
+ T4 v4;
+ public:
+ inline Tuple(T1 p1, T2 p2, T3 p3, T4 p4) : Tuple<T1,T2,T3>(p1,p2,p3), v4(p4) { TupleBase::nvs(4); }
+ inline Tuple(T1 p1, T2 p2, T3 p3) : Tuple<T1,T2,T3>(p1,p2,p3) {}
+ inline Tuple(T1 p1, T2 p2) : Tuple<T1,T2,T3>(p1,p2) {}
+ explicit inline Tuple(T1 p1) : Tuple<T1,T2,T3>(p1) {}
+ inline Tuple() = default;
+ inline Tuple(const Tuple<T1,T2,T3,T4>& o) : Tuple<T1,T2,T3>(o), v4(o.v4) {}
+
+ inline T4& fourth() { TupleBase::nvs(4); return v4; }
+ inline const T4& fourth() const { return v4; }
+ };
+}
diff --git a/xbmc/interfaces/legacy/Window.cpp b/xbmc/interfaces/legacy/Window.cpp
new file mode 100644
index 0000000..100803e
--- /dev/null
+++ b/xbmc/interfaces/legacy/Window.cpp
@@ -0,0 +1,767 @@
+/*
+ * 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 "Window.h"
+
+#include "ServiceBroker.h"
+#include "WindowException.h"
+#include "WindowInterceptor.h"
+#include "application/Application.h"
+#include "guilib/GUIButtonControl.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIEditControl.h"
+#include "guilib/GUIRadioButtonControl.h"
+#include "guilib/GUIWindowManager.h"
+#include "messaging/ApplicationMessenger.h"
+#include "utils/StringUtils.h"
+#include "utils/Variant.h"
+
+#define ACTIVE_WINDOW CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow()
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ thread_local ref* InterceptorBase::upcallTls;
+
+ /**
+ * Used in add/remove control. It only locks if it's given a
+ * non-NULL CCriticalSection. It's given a NULL CCriticalSection
+ * when a function higher in the call stack already has a
+ */
+ class MaybeLock
+ {
+ CCriticalSection* lock;
+ public:
+ inline explicit MaybeLock(CCriticalSection* p_lock) : lock(p_lock) { if (lock) lock->lock(); }
+ inline ~MaybeLock() { if (lock) lock->unlock(); }
+ };
+
+ class SingleLockWithDelayGuard
+ {
+ DelayedCallGuard dcg;
+ CCriticalSection& lock;
+ public:
+ inline SingleLockWithDelayGuard(CCriticalSection& ccrit, LanguageHook* lh) : dcg(lh), lock(ccrit) { lock.lock(); }
+ inline ~SingleLockWithDelayGuard() { lock.unlock(); }
+ };
+
+ /**
+ * Explicit template instantiation
+ */
+ template class Interceptor<CGUIWindow>;
+
+ /**
+ * This interceptor is a simple, non-callbackable (is that a word?)
+ * Interceptor to satisfy the Window requirements for upcalling
+ * for the purposes of instantiating a Window instance from
+ * an already existing window.
+ */
+ class ProxyExistingWindowInterceptor : public InterceptorBase
+ {
+ CGUIWindow* cguiwindow;
+
+ public:
+ inline ProxyExistingWindowInterceptor(CGUIWindow* window) :
+ cguiwindow(window) { XBMC_TRACE; }
+
+ CGUIWindow* get() override;
+ };
+
+ CGUIWindow* ProxyExistingWindowInterceptor::get() { XBMC_TRACE; return cguiwindow; }
+
+ Window::Window(bool discrim):
+ window(NULL),
+ m_actionEvent(true),
+ canPulse(true), existingWindow(false)
+ {
+ XBMC_TRACE;
+ }
+
+ /**
+ * This just creates a default window.
+ */
+ Window::Window(int existingWindowId) :
+ window(NULL),
+ m_actionEvent(true)
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+
+ if (existingWindowId == -1)
+ {
+ // in this case just do the other constructor.
+ canPulse = true;
+ existingWindow = false;
+
+ setWindow(new Interceptor<CGUIWindow>("CGUIWindow",this,getNextAvailableWindowId()));
+ }
+ else
+ {
+ // user specified window id, use this one if it exists
+ // It is not possible to capture key presses or button presses
+ CGUIWindow* pWindow = CServiceBroker::GetGUI()->GetWindowManager().GetWindow(existingWindowId);
+ if (!pWindow)
+ throw WindowException("Window id does not exist");
+
+ setWindow(new ProxyExistingWindowInterceptor(pWindow));
+ }
+ }
+
+ Window::~Window()
+ {
+ XBMC_TRACE;
+
+ deallocating();
+ }
+
+ void Window::deallocating()
+ {
+ AddonCallback::deallocating();
+
+ dispose();
+ }
+
+ void Window::dispose()
+ {
+ XBMC_TRACE;
+
+ //! @todo rework locking
+ // Python GIL and CServiceBroker::GetWinSystem()->GetGfxContext() are deadlock happy
+ // dispose is called from GUIWindowManager and in this case DelayGuard must not be used.
+ if (!CServiceBroker::GetAppMessenger()->IsProcessThread())
+ {
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(), languageHook);
+ }
+
+ if (!isDisposed)
+ {
+ isDisposed = true;
+
+ // no callbacks are possible any longer
+ // - this will be handled by the parent constructor
+
+ // first change to an existing window
+ if (!existingWindow)
+ {
+ if (ACTIVE_WINDOW == iWindowId && !g_application.m_bStop)
+ {
+ if(CServiceBroker::GetGUI()->GetWindowManager().GetWindow(iOldWindowId))
+ {
+ CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(iOldWindowId);
+ }
+ // old window does not exist anymore, switch to home
+ else CServiceBroker::GetGUI()->GetWindowManager().ActivateWindow(WINDOW_HOME);
+ }
+
+ }
+ else
+ {
+ //! @bug
+ //! This is an existing window, so no resources are free'd. Note that
+ //! THIS WILL FAIL for any controls newly created by python - they will
+ //! remain after the script ends. Ideally this would be remedied by
+ //! a flag in Control that specifies that it was python created - any python
+ //! created controls could then be removed + free'd from the window.
+ //! how this works with controlgroups though could be a bit tricky.
+ }
+
+ // and free our list of controls
+ std::vector<AddonClass::Ref<Control> >::iterator it = vecControls.begin();
+ while (it != vecControls.end())
+ {
+ AddonClass::Ref<Control> pControl = *it;
+ // initialize control to zero
+ pControl->pGUIControl = NULL;
+ pControl->iControlId = 0;
+ pControl->iParentId = 0;
+ ++it;
+ }
+
+ if (!existingWindow)
+ {
+ if (window)
+ {
+ if (CServiceBroker::GetGUI()->GetWindowManager().IsWindowVisible(ref(window)->GetID()))
+ {
+ destroyAfterDeInit = true;
+ close();
+ }
+ else
+ CServiceBroker::GetGUI()->GetWindowManager().Delete(ref(window)->GetID());
+ }
+ }
+
+ vecControls.clear();
+ }
+ }
+
+ void Window::setWindow(InterceptorBase* _window)
+ {
+ XBMC_TRACE;
+ window = _window;
+ iWindowId = _window->get()->GetID();
+
+ if (!existingWindow)
+ CServiceBroker::GetGUI()->GetWindowManager().Add(window->get());
+ }
+
+ int Window::getNextAvailableWindowId()
+ {
+ XBMC_TRACE;
+ // window id's 13000 - 13100 are reserved for python
+ // get first window id that is not in use
+ int id = WINDOW_PYTHON_START;
+ // if window 13099 is in use it means python can't create more windows
+ if (CServiceBroker::GetGUI()->GetWindowManager().GetWindow(WINDOW_PYTHON_END))
+ throw WindowException("maximum number of windows reached");
+
+ while(id < WINDOW_PYTHON_END && CServiceBroker::GetGUI()->GetWindowManager().GetWindow(id) != NULL) id++;
+ return id;
+ }
+
+ void Window::popActiveWindowId()
+ {
+ XBMC_TRACE;
+ if (iOldWindowId != iWindowId &&
+ iWindowId != ACTIVE_WINDOW)
+ iOldWindowId = ACTIVE_WINDOW;
+ }
+
+ // Internal helper method
+ /* Searches for a control in Window->vecControls
+ * If we can't find any but the window has the controlId (in case of a not python window)
+ * we create a new control with basic functionality
+ */
+ Control* Window::GetControlById(int iControlId, CCriticalSection* gc)
+ {
+ XBMC_TRACE;
+
+ // find in window vector first!!!
+ // this saves us from creating a complete new control
+ std::vector<AddonClass::Ref<Control> >::iterator it = vecControls.begin();
+ while (it != vecControls.end())
+ {
+ AddonClass::Ref<Control> control = (*it);
+ if (control->iControlId == iControlId)
+ {
+ return control.get();
+ } else ++it;
+ }
+
+ // lock xbmc GUI before accessing data from it
+ MaybeLock lock(gc);
+
+ // check if control exists
+ CGUIControl* pGUIControl = ref(window)->GetControl(iControlId);
+ if (!pGUIControl)
+ {
+ // control does not exist.
+ throw WindowException("Non-Existent Control %d",iControlId);
+ }
+
+ // allocate a new control with a new reference
+ CLabelInfo li;
+
+ Control* pControl = NULL;
+
+ //! @todo Yuck! Should probably be done with a Factory pattern
+ switch(pGUIControl->GetControlType())
+ {
+ case CGUIControl::GUICONTROL_BUTTON:
+ pControl = new ControlButton();
+
+ li = ((CGUIButtonControl *)pGUIControl)->GetLabelInfo();
+
+ // note: conversion from infocolors -> plain colors here
+ ((ControlButton*)pControl)->disabledColor = li.disabledColor;
+ ((ControlButton*)pControl)->focusedColor = li.focusedColor;
+ ((ControlButton*)pControl)->textColor = li.textColor;
+ ((ControlButton*)pControl)->shadowColor = li.shadowColor;
+ if (li.font) ((ControlButton*)pControl)->strFont = li.font->GetFontName();
+ ((ControlButton*)pControl)->align = li.align;
+ break;
+ case CGUIControl::GUICONTROL_LABEL:
+ pControl = new ControlLabel();
+ break;
+ case CGUIControl::GUICONTROL_SPIN:
+ pControl = new ControlSpin();
+ break;
+ case CGUIControl::GUICONTROL_FADELABEL:
+ pControl = new ControlFadeLabel();
+ break;
+ case CGUIControl::GUICONTROL_TEXTBOX:
+ pControl = new ControlTextBox();
+ break;
+ case CGUIControl::GUICONTROL_IMAGE:
+ case CGUIControl::GUICONTROL_BORDEREDIMAGE:
+ pControl = new ControlImage();
+ break;
+ case CGUIControl::GUICONTROL_PROGRESS:
+ pControl = new ControlProgress();
+ break;
+ case CGUIControl::GUICONTROL_SLIDER:
+ pControl = new ControlSlider();
+ break;
+ case CGUIControl::GUICONTAINER_LIST:
+ case CGUIControl::GUICONTAINER_WRAPLIST:
+ case CGUIControl::GUICONTAINER_FIXEDLIST:
+ case CGUIControl::GUICONTAINER_PANEL:
+ pControl = new ControlList();
+ // create a python spin control
+ ((ControlList*)pControl)->pControlSpin = new ControlSpin();
+ break;
+ case CGUIControl::GUICONTROL_GROUP:
+ pControl = new ControlGroup();
+ break;
+ case CGUIControl::GUICONTROL_RADIO:
+ pControl = new ControlRadioButton();
+
+ li = ((CGUIRadioButtonControl *)pGUIControl)->GetLabelInfo();
+
+ // note: conversion from infocolors -> plain colors here
+ ((ControlRadioButton*)pControl)->disabledColor = li.disabledColor;
+ ((ControlRadioButton*)pControl)->focusedColor = li.focusedColor;
+ ((ControlRadioButton*)pControl)->textColor = li.textColor;
+ ((ControlRadioButton*)pControl)->shadowColor = li.shadowColor;
+ if (li.font) ((ControlRadioButton*)pControl)->strFont = li.font->GetFontName();
+ ((ControlRadioButton*)pControl)->align = li.align;
+ break;
+ case CGUIControl::GUICONTROL_EDIT:
+ pControl = new ControlEdit();
+
+ li = ((CGUIEditControl *)pGUIControl)->GetLabelInfo();
+
+ // note: conversion from infocolors -> plain colors here
+ ((ControlEdit*)pControl)->disabledColor = li.disabledColor;
+ ((ControlEdit*)pControl)->textColor = li.textColor;
+ if (li.font) ((ControlEdit*)pControl)->strFont = li.font->GetFontName();
+ ((ControlButton*)pControl)->align = li.align;
+ break;
+ default:
+ break;
+ }
+
+ if (!pControl)
+ // throw an exception
+ throw WindowException("Unknown control type for python");
+
+ // we have a valid control here, fill in all the 'Control' data
+ pControl->pGUIControl = pGUIControl;
+ pControl->iControlId = pGUIControl->GetID();
+ pControl->iParentId = iWindowId;
+ pControl->dwHeight = (int)pGUIControl->GetHeight();
+ pControl->dwWidth = (int)pGUIControl->GetWidth();
+ pControl->dwPosX = (int)pGUIControl->GetXPosition();
+ pControl->dwPosY = (int)pGUIControl->GetYPosition();
+ pControl->iControlUp = pGUIControl->GetAction(ACTION_MOVE_UP).GetNavigation();
+ pControl->iControlDown = pGUIControl->GetAction(ACTION_MOVE_DOWN).GetNavigation();
+ pControl->iControlLeft = pGUIControl->GetAction(ACTION_MOVE_LEFT).GetNavigation();
+ pControl->iControlRight = pGUIControl->GetAction(ACTION_MOVE_RIGHT).GetNavigation();
+
+ // It got this far so means the control isn't actually in the vector of controls
+ // so lets add it to save doing all that next time
+ vecControls.emplace_back(pControl);
+
+ // return the control with increased reference (+1)
+ return pControl;
+ }
+
+ void Window::PulseActionEvent()
+ {
+ XBMC_TRACE;
+ if (canPulse)
+ m_actionEvent.Set();
+ }
+
+ bool Window::WaitForActionEvent(unsigned int milliseconds)
+ {
+ XBMC_TRACE;
+ // DO NOT MAKE THIS A DELAYED CALL!!!!
+ bool ret = languageHook == NULL ? m_actionEvent.Wait(std::chrono::milliseconds(milliseconds))
+ : languageHook->WaitForEvent(m_actionEvent, milliseconds);
+ if (ret)
+ m_actionEvent.Reset();
+ return ret;
+ }
+
+ bool Window::OnAction(const CAction &action)
+ {
+ XBMC_TRACE;
+ // do the base class window first, and the call to python after this
+ bool ret = ref(window)->OnAction(action);
+
+ // workaround - for scripts which try to access the active control (focused) when there is none.
+ // for example - the case when the mouse enters the screen.
+ CGUIControl *pControl = ref(window)->GetFocusedControl();
+ if (action.IsMouse() && !pControl)
+ return ret;
+
+ AddonClass::Ref<Action> inf(new Action(action));
+ invokeCallback(new CallbackFunction<Window,AddonClass::Ref<Action> >(this,&Window::onAction,inf.get()));
+ PulseActionEvent();
+
+ return ret;
+ }
+
+ bool Window::OnBack(int actionID)
+ {
+ // we are always a Python window ... keep that in mind when reviewing the old code
+ return true;
+ }
+
+ void Window::OnDeinitWindow(int nextWindowID /*= 0*/)
+ {
+ // NOTE!: This handle child classes correctly. XML windows will call
+ // the OnDeinitWindow from CGUIMediaWindow while non-XML classes will
+ // call the OnDeinitWindow on CGUIWindow
+ ref(window)->OnDeinitWindow(nextWindowID);
+ if (destroyAfterDeInit)
+ CServiceBroker::GetGUI()->GetWindowManager().Delete(window->get()->GetID());
+ }
+
+ void Window::onAction(Action* action)
+ {
+ XBMC_TRACE;
+ // default onAction behavior
+ if(action->id == ACTION_PREVIOUS_MENU || action->id == ACTION_NAV_BACK)
+ close();
+ }
+
+ bool Window::OnMessage(CGUIMessage& message)
+ {
+ XBMC_TRACE;
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_CLICKED:
+ {
+ int iControl=message.GetSenderId();
+ AddonClass::Ref<Control> inf;
+ // find python control object with same iControl
+ std::vector<AddonClass::Ref<Control> >::iterator it = vecControls.begin();
+ while (it != vecControls.end())
+ {
+ AddonClass::Ref<Control> pControl = (*it);
+ if (pControl->iControlId == iControl)
+ {
+ inf = pControl.get();
+ break;
+ }
+ ++it;
+ }
+
+ // did we find our control?
+ if (inf.isNotNull())
+ {
+ // currently we only accept messages from a button or controllist with a select action
+ if (inf->canAcceptMessages(message.GetParam1()))
+ {
+ invokeCallback(new CallbackFunction<Window,AddonClass::Ref<Control> >(this,&Window::onControl,inf.get()));
+ PulseActionEvent();
+
+ // return true here as we are handling the event
+ return true;
+ }
+ }
+ // if we get here, we didn't add the action
+ }
+ break;
+ }
+
+ return ref(window)->OnMessage(message);
+ }
+
+ void Window::onControl(Control* action) { XBMC_TRACE; /* do nothing by default */ }
+ void Window::onClick(int controlId) { XBMC_TRACE; /* do nothing by default */ }
+ void Window::onDoubleClick(int controlId) { XBMC_TRACE; /* do nothing by default */ }
+ void Window::onFocus(int controlId) { XBMC_TRACE; /* do nothing by default */ }
+ void Window::onInit() { XBMC_TRACE; /* do nothing by default */ }
+
+ void Window::show()
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dcguard(languageHook);
+ popActiveWindowId();
+
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_ACTIVATE_WINDOW, iWindowId, 0);
+ }
+
+ void Window::setFocus(Control* pControl)
+ {
+ XBMC_TRACE;
+ if(pControl == NULL)
+ throw WindowException("Object should be of type Control");
+
+ CGUIMessage msg = CGUIMessage(GUI_MSG_SETFOCUS,pControl->iParentId, pControl->iControlId);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, pControl->iParentId);
+ }
+
+ void Window::setFocusId(int iControlId)
+ {
+ XBMC_TRACE;
+ CGUIMessage msg = CGUIMessage(GUI_MSG_SETFOCUS,iWindowId,iControlId);
+ CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg, iWindowId);
+ }
+
+ Control* Window::getFocus()
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+
+ int iControlId = ref(window)->GetFocusedControlID();
+ if(iControlId == -1)
+ throw WindowException("No control in this window has focus");
+ // Sine I'm already holding the lock theres no reason to give it to GetFocusedControlID
+ return GetControlById(iControlId,NULL);
+ }
+
+ long Window::getFocusId()
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+ int iControlId = ref(window)->GetFocusedControlID();
+ if(iControlId == -1)
+ throw WindowException("No control in this window has focus");
+ return (long)iControlId;
+ }
+
+ void Window::removeControl(Control* pControl)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg(languageHook);
+ doRemoveControl(pControl,&CServiceBroker::GetWinSystem()->GetGfxContext(),true);
+ }
+
+ void Window::doRemoveControl(Control* pControl, CCriticalSection* gcontext, bool wait)
+ {
+ XBMC_TRACE;
+ // type checking, object should be of type Control
+ if(pControl == NULL)
+ throw WindowException("Object should be of type Control");
+
+ {
+ MaybeLock mlock(gcontext);
+ if(!ref(window)->GetControl(pControl->iControlId))
+ throw WindowException("Control does not exist in window");
+ }
+
+ // delete control from vecControls in window object
+ std::vector<AddonClass::Ref<Control> >::iterator it = vecControls.begin();
+ while (it != vecControls.end())
+ {
+ AddonClass::Ref<Control> control = (*it);
+ if (control->iControlId == pControl->iControlId)
+ {
+ it = vecControls.erase(it);
+ } else ++it;
+ }
+
+ CGUIMessage msg(GUI_MSG_REMOVE_CONTROL, 0, 0);
+ msg.SetPointer(pControl->pGUIControl);
+ CServiceBroker::GetAppMessenger()->SendGUIMessage(msg, iWindowId, wait);
+
+ // initialize control to zero
+ pControl->pGUIControl = NULL;
+ pControl->iControlId = 0;
+ pControl->iParentId = 0;
+ }
+
+ void Window::removeControls(std::vector<Control*> pControls)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg(languageHook);
+ int count = 1; int size = pControls.size();
+ for (std::vector<Control*>::iterator iter = pControls.begin(); iter != pControls.end(); count++, ++iter)
+ doRemoveControl(*iter,NULL, count == size);
+ }
+
+ long Window::getHeight()
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(), languageHook);
+ RESOLUTION_INFO resInfo = ref(window)->GetCoordsRes();
+ return resInfo.iHeight;
+ }
+
+ long Window::getWidth()
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(), languageHook);
+ RESOLUTION_INFO resInfo = ref(window)->GetCoordsRes();
+ return resInfo.iWidth;
+ }
+
+ void Window::setProperty(const char* key, const String& value)
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+ std::string lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+
+ ref(window)->SetProperty(lowerKey, value);
+ }
+
+ String Window::getProperty(const char* key)
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+ std::string lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+ std::string value = ref(window)->GetProperty(lowerKey).asString();
+ return value;
+ }
+
+ void Window::clearProperty(const char* key)
+ {
+ XBMC_TRACE;
+ if (!key) return;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+
+ std::string lowerKey = key;
+ StringUtils::ToLower(lowerKey);
+ ref(window)->SetProperty(lowerKey, "");
+ }
+
+ void Window::clearProperties()
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+ ref(window)->ClearProperties();
+ }
+
+ void Window::close()
+ {
+ XBMC_TRACE;
+ bModal = false;
+
+ if (!existingWindow)
+ PulseActionEvent();
+
+ {
+ DelayedCallGuard dcguard(languageHook);
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_PREVIOUS_WINDOW, iOldWindowId, 0);
+ }
+
+ iOldWindowId = 0;
+ }
+
+ void Window::doModal()
+ {
+ XBMC_TRACE;
+ if (!existingWindow)
+ {
+ bModal = true;
+
+ if(iWindowId != ACTIVE_WINDOW)
+ show();
+
+ while (bModal && !g_application.m_bStop)
+ {
+//! @todo garbear added this code to the python window.cpp class and
+//! commented in XBPyThread.cpp. I'm not sure how to handle this
+//! in this native implementation.
+// // Check if XBPyThread::stop() raised a SystemExit exception
+// if (PyThreadState_Get()->async_exc == PyExc_SystemExit)
+// {
+// CLog::Log(LOGDEBUG, "PYTHON: doModal() encountered a SystemExit exception, closing window and returning");
+// Window_Close(self, NULL);
+// break;
+// }
+ languageHook->MakePendingCalls(); // MakePendingCalls
+
+ bool stillWaiting;
+ do
+ {
+ {
+ DelayedCallGuard dcguard(languageHook);
+ stillWaiting = WaitForActionEvent(100) ? false : true;
+ }
+ languageHook->MakePendingCalls();
+ } while (stillWaiting);
+ }
+ }
+ }
+
+ void Window::addControl(Control* pControl)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg(languageHook);
+ doAddControl(pControl,&CServiceBroker::GetWinSystem()->GetGfxContext(),true);
+ }
+
+ void Window::doAddControl(Control* pControl, CCriticalSection* gcontext, bool wait)
+ {
+ XBMC_TRACE;
+ if(pControl == NULL)
+ throw WindowException("NULL Control passed to WindowBase::addControl");
+
+ if(pControl->iControlId != 0)
+ throw WindowException("Control is already used");
+
+ // lock kodi GUI before accessing data from it
+ pControl->iParentId = iWindowId;
+
+ {
+ MaybeLock mlock(gcontext);
+ // assign control id, if id is already in use, try next id
+ do pControl->iControlId = ++iCurrentControlId;
+ while (ref(window)->GetControl(pControl->iControlId));
+ }
+
+ pControl->Create();
+
+ // set default navigation for control
+ pControl->iControlUp = pControl->iControlId;
+ pControl->iControlDown = pControl->iControlId;
+ pControl->iControlLeft = pControl->iControlId;
+ pControl->iControlRight = pControl->iControlId;
+
+ pControl->pGUIControl->SetAction(ACTION_MOVE_UP, CGUIAction(pControl->iControlUp));
+ pControl->pGUIControl->SetAction(ACTION_MOVE_DOWN, CGUIAction(pControl->iControlDown));
+ pControl->pGUIControl->SetAction(ACTION_MOVE_LEFT, CGUIAction(pControl->iControlLeft));
+ pControl->pGUIControl->SetAction(ACTION_MOVE_RIGHT, CGUIAction(pControl->iControlRight));
+
+ // add control to list and allocate resources for the control
+ vecControls.emplace_back(pControl);
+ pControl->pGUIControl->AllocResources();
+
+ // This calls the CGUIWindow parent class to do the final add
+ CGUIMessage msg(GUI_MSG_ADD_CONTROL, 0, 0);
+ msg.SetPointer(pControl->pGUIControl);
+ CServiceBroker::GetAppMessenger()->SendGUIMessage(msg, iWindowId, wait);
+ }
+
+ void Window::addControls(std::vector<Control*> pControls)
+ {
+ XBMC_TRACE;
+ SingleLockWithDelayGuard gslock(CServiceBroker::GetWinSystem()->GetGfxContext(),languageHook);
+ int count = 1; int size = pControls.size();
+ for (std::vector<Control*>::iterator iter = pControls.begin(); iter != pControls.end(); count++, ++iter)
+ doAddControl(*iter,NULL, count == size);
+ }
+
+ Control* Window::getControl(int iControlId)
+ {
+ XBMC_TRACE;
+ DelayedCallGuard dg(languageHook);
+ return GetControlById(iControlId,&CServiceBroker::GetWinSystem()->GetGfxContext());
+ }
+
+ void Action::setFromCAction(const CAction& action)
+ {
+ XBMC_TRACE;
+ id = action.GetID();
+ buttonCode = action.GetButtonCode();
+ fAmount1 = action.GetAmount(0);
+ fAmount2 = action.GetAmount(1);
+ fRepeat = action.GetRepeat();
+ strAction = action.GetName();
+ }
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/Window.h b/xbmc/interfaces/legacy/Window.h
new file mode 100644
index 0000000..b30be7b
--- /dev/null
+++ b/xbmc/interfaces/legacy/Window.h
@@ -0,0 +1,878 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "AddonCallback.h"
+#include "AddonString.h"
+#include "Control.h"
+#include "swighelper.h"
+
+#include <limits.h>
+#include <mutex>
+#include <vector>
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ // Forward declare the interceptor as the AddonWindowInterceptor.h
+ // file needs to include the Window class because of the template
+ class InterceptorBase;
+
+ //
+ /// \defgroup python_xbmcgui_action Action
+ /// \ingroup python_xbmcgui
+ ///@{
+ /// @brief **Action class.**
+ ///
+ /// \python_class{ xbmcgui.Action(): }
+ ///
+ /// This class serves in addition to identify carried out
+ /// \ref kodi_key_action_ids of Kodi and to be able to carry out thereby own
+ /// necessary steps.
+ ///
+ /// The data of this class are always transmitted by callback
+ /// Window::onAction at a window.
+ ///
+ class Action : public AddonClass
+ {
+ public:
+ Action() = default;
+
+#ifndef SWIG
+ explicit Action(const CAction& caction) { setFromCAction(caction); }
+
+ void setFromCAction(const CAction& caction);
+
+ long id = -1;
+ float fAmount1 = 0.0f;
+ float fAmount2 = 0.0f;
+ float fRepeat = 0.0f;
+ unsigned long buttonCode = 0;
+ std::string strAction;
+
+ // Not sure if this is correct but it's here for now.
+ AddonClass::Ref<Control> control; // previously pObject
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_action
+ /// @brief \python_func{ getId() }
+ /// To get \ref kodi_key_action_ids
+ ///
+ /// This function returns the identification code used by the explained
+ /// order, it is necessary to determine the type of command from
+ /// \ref kodi_key_action_ids.
+ ///
+ /// @return The action's current id as a long or 0 if
+ /// no action is mapped in the xml's.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// def onAction(self, action):
+ /// if action.getId() == ACTION_PREVIOUS_MENU:
+ /// print('action received: previous')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getId();
+#else
+ long getId() { XBMC_TRACE; return id; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_action
+ /// @brief \python_func{ getButtonCode() }
+ /// Returns the button code for this action.
+ ///
+ /// @return [integer] button code
+ ///
+ getButtonCode();
+#else
+ long getButtonCode() { XBMC_TRACE; return buttonCode; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_action
+ /// @brief \python_func{ getAmount1() }
+ /// Returns the first amount of force applied to the thumbstick.
+ ///
+ /// @return [float] first amount
+ ///
+ getAmount1();
+#else
+ float getAmount1() { XBMC_TRACE; return fAmount1; }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_action
+ /// @brief \python_func{ getAmount2() }
+ /// Returns the second amount of force applied to the thumbstick.
+ ///
+ /// @return [float] second amount
+ ///
+ getAmount2();
+#else
+ float getAmount2() { XBMC_TRACE; return fAmount2; }
+#endif
+ };
+ ///@}
+
+ //==========================================================================
+ // This is the main class for the xbmcgui.Window functionality. It is tied
+ // into the main Kodi windowing system via the Interceptor
+ //==========================================================================
+ //
+ /// \defgroup python_xbmcgui_window Window
+ /// \ingroup python_xbmcgui
+ /// @{
+ /// @brief __GUI window class for Add-Ons.__
+ ///
+ /// This class allows over their functions to create and edit windows that
+ /// can be accessed from an Add-On.
+ ///
+ /// Likewise, all functions from here as well in the other window classes
+ /// \ref python_xbmcgui_window_dialog "WindowDialog",
+ /// \ref python_xbmcgui_window_xml "WindowXML" and
+ /// \ref python_xbmcgui_window_dialog_xml "WindowXMLDialog"
+ /// with inserted and available.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ /// Constructor for window
+ /// ----------------------------
+ ///
+ /// \python_class{ xbmcgui.Window([existingWindowId]): }
+ ///
+ /// Creates a new from Add-On usable window class. This is to create
+ /// window for related controls by system calls.
+ ///
+ /// @param existingWindowId [opt] Specify an id to use an existing
+ /// window.
+ /// @throws ValueError if supplied window Id does not exist.
+ /// @throws Exception if more then 200 windows are created.
+ ///
+ /// Deleting this window will activate the old window that was active
+ /// and resets (not delete) all controls that are associated with this
+ /// window.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// win = xbmcgui.Window()
+ /// width = win.getWidth()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ ///
+ //
+ class Window : public AddonCallback
+ {
+ friend class WindowDialogMixin;
+ bool isDisposed = false;
+
+ void doAddControl(Control* pControl, CCriticalSection* gcontext, bool wait);
+ void doRemoveControl(Control* pControl, CCriticalSection* gcontext, bool wait);
+
+ protected:
+#ifndef SWIG
+ InterceptorBase* window;
+ int iWindowId = -1;
+
+ std::vector<AddonClass::Ref<Control> > vecControls;
+ int iOldWindowId = 0;
+ int iCurrentControlId = 3000;
+ bool bModal = false;
+ CEvent m_actionEvent;
+
+ bool canPulse = false;
+
+ // I REALLY hate this ... but it's the simplest fix right now.
+ bool existingWindow = true;
+ bool destroyAfterDeInit = false;
+
+ /**
+ * This only takes a boolean to allow subclasses to explicitly use it. A
+ * default constructor can be used as a concrete class and we need to tell
+ * the difference.
+ * subclasses should use this constructor and not the other.
+ */
+ explicit Window(bool discrim);
+
+ void deallocating() override;
+
+ /**
+ * This helper retrieves the next available id. It is assumed that the
+ * global lock is already being held.
+ */
+ static int getNextAvailableWindowId();
+
+ /**
+ * Child classes MUST call this in their constructors. It should be an
+ * instance of Interceptor<P extends CGUIWindow>. Control of memory
+ * management for this class is then given to the Window.
+ */
+ void setWindow(InterceptorBase* _window);
+
+ /**
+ * This is a helper method since popping the previous window id is a common
+ * function.
+ */
+ void popActiveWindowId();
+
+ /**
+ * This is a helper method since getting a control by it's id is a common
+ * function.
+ */
+ Control* GetControlById(int iControlId, CCriticalSection* gc);
+
+ SWIGHIDDENVIRTUAL void PulseActionEvent();
+ SWIGHIDDENVIRTUAL bool WaitForActionEvent(unsigned int milliseconds);
+#endif
+
+ public:
+ explicit Window(int existingWindowId = -1);
+
+ ~Window() override;
+
+#ifndef SWIG
+ SWIGHIDDENVIRTUAL bool OnMessage(CGUIMessage& message);
+ SWIGHIDDENVIRTUAL bool OnAction(const CAction &action);
+ SWIGHIDDENVIRTUAL bool OnBack(int actionId);
+ SWIGHIDDENVIRTUAL void OnDeinitWindow(int nextWindowID);
+
+ SWIGHIDDENVIRTUAL bool IsDialogRunning() const
+ {
+ XBMC_TRACE;
+ return false;
+ }
+ SWIGHIDDENVIRTUAL bool IsDialog() const
+ {
+ XBMC_TRACE;
+ return false;
+ }
+ SWIGHIDDENVIRTUAL bool IsModalDialog() const
+ {
+ XBMC_TRACE;
+ return false;
+ }
+ SWIGHIDDENVIRTUAL bool IsMediaWindow() const
+ {
+ XBMC_TRACE;
+ return false;
+ }
+ SWIGHIDDENVIRTUAL void dispose();
+
+ /**
+ * This is called from the InterceptorBase destructor to prevent further
+ * use of the interceptor from the window.
+ */
+ inline void interceptorClear()
+ {
+ std::unique_lock<CCriticalSection> lock(*this);
+ window = NULL;
+ }
+#endif
+
+ //
+ /// @defgroup python_xbmcgui_window_cb Callback functions from Kodi to add-on
+ /// \ingroup python_xbmcgui_window
+ /// @{
+ /// @brief __GUI window callback functions.__
+ ///
+ /// Functions to handle control callbacks from Kodi.
+ ///
+ /// Likewise, all functions from here as well in the all window classes
+ /// (\ref python_xbmcgui_window "Window",
+ /// \ref python_xbmcgui_window_dialog "WindowDialog",
+ /// \ref python_xbmcgui_window_xml "WindowXML" and
+ /// \ref python_xbmcgui_window_dialog_xml "WindowXMLDialog") with inserted
+ /// and available.
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// @link python_xbmcgui_window Go back to normal functions from window@endlink
+ //
+
+ // callback takes a parameter
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_cb
+ /// @brief \python_func{ onAction(self, Action action) }
+ /// **onAction method.**
+ ///
+ /// This method will receive all actions that the main program will send
+ /// to this window.
+ ///
+ /// @param self Own base class pointer
+ /// @param action The action id to perform, see
+ /// \ref python_xbmcgui_action to get use
+ /// of them
+ ///
+ /// @note
+ /// - By default, only the `PREVIOUS_MENU` and `NAV_BACK actions` are
+ /// handled.
+ /// - Overwrite this method to let your script handle all actions.
+ /// - Don't forget to capture `ACTION_PREVIOUS_MENU` or `ACTION_NAV_BACK`,
+ /// else the user can't close this window.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # Define own function where becomes called from Kodi
+ /// def onAction(self, action):
+ /// if action.getId() == ACTION_PREVIOUS_MENU:
+ /// print('action received: previous')
+ /// self.close()
+ /// if action.getId() == ACTION_SHOW_INFO:
+ /// print('action received: show info')
+ /// if action.getId() == ACTION_STOP:
+ /// print('action received: stop')
+ /// if action.getId() == ACTION_PAUSE:
+ /// print('action received: pause')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ onAction(...);
+#else
+ virtual void onAction(Action* action);
+#endif
+
+ // on control is not actually on Window in the api but is called into Python anyway.
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_cb
+ /// @brief \python_func{ onControl(self, Control) }
+ /// **onControl method.**
+ ///
+ /// This method will receive all click events on owned and selected
+ /// controls when the control itself doesn't handle the message.
+ ///
+ /// @param self Own base class pointer
+ /// @param control The \ref python_xbmcgui_control "Control" class
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # Define own function where becomes called from Kodi
+ /// def onControl(self, control):
+ /// print("Window.onControl(control=[%s])"%control)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ void onControl(...);
+#else
+ virtual void onControl(Control* control);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_cb
+ /// @brief \python_func{ onClick(self, int controlId) }
+ /// **onClick method.**
+ ///
+ /// This method will receive all click events that the main program will
+ /// send to this window.
+ ///
+ /// @param self Own base class pointer
+ /// @param controlId The one time clicked GUI control
+ /// identifier
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # Define own function where becomes called from Kodi
+ /// def onClick(self,controlId):
+ /// if controlId == 10:
+ /// print("The control with Id 10 is clicked")
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ onClick(...);
+#else
+ virtual void onClick(int controlId);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_cb
+ /// @brief \python_func{ onDoubleClick(self, int controlId) }
+ /// __onDoubleClick method.__
+ ///
+ /// This method will receive all double click events that the main program
+ /// will send to this window.
+ ///
+ /// @param self Own base class pointer
+ /// @param controlId The double clicked GUI control
+ /// identifier
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # Define own function where becomes called from Kodi
+ /// def onDoubleClick(self,controlId):
+ /// if controlId == 10:
+ /// print("The control with Id 10 is double clicked")
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ onDoubleClick(...);
+#else
+ virtual void onDoubleClick(int controlId);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_cb
+ /// @brief \python_func{ onFocus(self, int controlId) }
+ /// __onFocus method.__
+ ///
+ /// This method will receive all focus events that the main program will
+ /// send to this window.
+ ///
+ /// @param self Own base class pointer
+ /// @param controlId The focused GUI control identifier
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # Define own function where becomes called from Kodi
+ /// def onDoubleClick(self,controlId):
+ /// if controlId == 10:
+ /// print("The control with Id 10 is focused")
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ onFocus(...);
+#else
+ virtual void onFocus(int controlId);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_cb
+ /// @brief \python_func{ onInit(self) }
+ /// __onInit method.__
+ ///
+ /// This method will be called to initialize the window
+ ///
+ /// @param self Own base class pointer
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// # Define own function where becomes called from Kodi
+ /// def onInit(self):
+ /// print("Window.onInit method called from Kodi")
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ onInit(...);
+#else
+ virtual void onInit();
+#endif
+ //@}
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ show() }
+ /// Show this window.
+ ///
+ /// Shows this window by activating it, calling close() after it wil
+ /// activate the current window again.
+ ///
+ /// @note If your script ends this window will be closed to. To show it
+ /// forever, make a loop at the end of your script or use doModal()
+ /// instead.
+ ///
+ show();
+#else
+ SWIGHIDDENVIRTUAL void show();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ setFocus(Control) }
+ /// Give the supplied control focus.
+ ///
+ /// @param Control \ref python_xbmcgui_control "Control" class to focus
+ /// @throws TypeError If supplied argument is not a \ref python_xbmcgui_control "Control"
+ /// type
+ /// @throws SystemError On Internal error
+ /// @throws RuntimeError If control is not added to a window
+ ///
+ setFocus(...);
+#else
+ SWIGHIDDENVIRTUAL void setFocus(Control* pControl);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ setFocusId(ControlId) }
+ /// Gives the control with the supplied focus.
+ ///
+ /// @param ControlId [integer] On skin defined id of control
+ /// @throws SystemError On Internal error
+ /// @throws RuntimeError If control is not added to a window
+ ///
+ setFocusId(...);
+#else
+ SWIGHIDDENVIRTUAL void setFocusId(int iControlId);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ getFocus(Control) }
+ /// Returns the control which is focused.
+ ///
+ /// @return Focused control class
+ /// @throws SystemError On Internal error
+ /// @throws RuntimeError If no control has focus
+ ///
+ getFocus();
+#else
+ SWIGHIDDENVIRTUAL Control* getFocus();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ getFocusId(int) }
+ /// Returns the id of the control which is focused.
+ ///
+ /// @return Focused control id
+ /// @throws SystemError On Internal error
+ /// @throws RuntimeError If no control has focus
+ ///
+ getFocusId();
+#else
+ SWIGHIDDENVIRTUAL long getFocusId();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ removeControl(Control) }
+ /// Removes the control from this window.
+ ///
+ /// @param Control \ref python_xbmcgui_control "Control" class to remove
+ /// @throws TypeError If supplied argument is not a \ref python_xbmcgui_control
+ /// type
+ /// @throws RuntimeError If control is not added to this window
+ ///
+ /// This will not delete the control. It is only removed from the window.
+ ///
+ removeControl(...);
+#else
+ SWIGHIDDENVIRTUAL void removeControl(Control* pControl);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ removeControls(List) }
+ /// Removes a list of controls from this window.
+ ///
+ /// @param List List with controls to remove
+ /// @throws TypeError If supplied argument is not a \ref python_xbmcgui_control
+ /// type
+ /// @throws RuntimeError If control is not added to this window
+ ///
+ /// This will not delete the controls. They are only removed from the
+ /// window.
+ ///
+ removeControls(...);
+#else
+ SWIGHIDDENVIRTUAL void removeControls(std::vector<Control*> pControls);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ getHeight() }
+ /// Returns the height of this Window instance.
+ ///
+ /// @return Window height in pixels
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 Function changed
+ ///
+ getHeight();
+#else
+ SWIGHIDDENVIRTUAL long getHeight();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ getWidth() }
+ /// Returns the width of this Window instance.
+ ///
+ /// @return Window width in pixels
+ ///
+ ///-----------------------------------------------------------------------
+ /// @python_v18 Function changed
+ ///
+ getWidth();
+#else
+ SWIGHIDDENVIRTUAL long getWidth();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ setProperty(key, value) }
+ /// Sets a window property, similar to an infolabel.
+ ///
+ /// @param key string - property name.
+ /// @param value string or unicode - value of property.
+ ///
+ /// @note Key is NOT case sensitive. Setting value to an empty string is
+ /// equivalent to clearProperty(key).\n
+ /// You can use the above as keywords for arguments and skip
+ /// certain optional arguments.\n
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// win = xbmcgui.Window(xbmcgui.getCurrentWindowId())
+ /// win.setProperty('Category', 'Newest')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setProperty(...);
+#else
+ SWIGHIDDENVIRTUAL void setProperty(const char* key, const String& value);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ getProperty(key) }
+ /// Returns a window property as a string, similar to an infolabel.
+ ///
+ /// @param key string - property name.
+ ///
+ /// @note Key is NOT case sensitive.\n
+ /// You can use the above as keywords for arguments and skip
+ /// certain optional arguments.
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// win = xbmcgui.Window(xbmcgui.getCurrentWindowId())
+ /// category = win.getProperty('Category')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getProperty(...);
+#else
+ SWIGHIDDENVIRTUAL String getProperty(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ clearProperty(key) }
+ /// Clears the specific window property.
+ ///
+ /// @param key string - property name.
+ ///
+ /// @note Key is NOT case sensitive. Equivalent to setProperty(key,'')
+ /// You can use the above as keywords for arguments and skip certain
+ /// optional arguments.
+ /// Once you use a keyword, all following arguments require the
+ /// keyword.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// win = xbmcgui.Window(xbmcgui.getCurrentWindowId())
+ /// win.clearProperty('Category')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ clearProperty(...);
+#else
+ SWIGHIDDENVIRTUAL void clearProperty(const char* key);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ clearProperties() }
+ /// Clears all window properties.
+ ///
+ ///
+ ///-----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// win = xbmcgui.Window(xbmcgui.getCurrentWindowId())
+ /// win.clearProperties()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ clearProperties();
+#else
+ SWIGHIDDENVIRTUAL void clearProperties();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ close() }
+ /// Closes this window.
+ ///
+ /// Closes this window by activating the old window.
+ ///
+ /// @note The window is not deleted with this method.
+ ///
+ close();
+#else
+ SWIGHIDDENVIRTUAL void close();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ doModal() }
+ /// Display this window until close() is called.
+ ///
+ doModal();
+#else
+
+ SWIGHIDDENVIRTUAL void doModal();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ addControl(Control) }
+ /// Add a \ref python_xbmcgui_control "Control" to this window.
+ ///
+ /// @param Control \ref python_xbmcgui_control "Control" to add
+ /// @throws TypeError If supplied argument is not a \ref python_xbmcgui_control
+ /// type
+ /// @throws ReferenceError If control is already used in another
+ /// window
+ /// @throws RuntimeError Should not happen :-)
+ ///
+ /// The next controls can be added to a window atm
+ /// | Control-class | Description |
+ /// |---------------------|------------------------------------------------------------|
+ /// | \ref python_xbmcgui_control_label "ControlLabel" | Label control to show text
+ /// | \ref python_xbmcgui_control_fadelabel "ControlFadeLabel" | The fadelabel has multiple labels which it cycles through
+ /// | \ref python_xbmcgui_control_textbox "ControlTextBox" | To show bigger text field
+ /// | \ref python_xbmcgui_control_button "ControlButton" | Brings a button to do some actions
+ /// | \ref python_xbmcgui_control_edit "ControlEdit" | The edit control allows a user to input text in Kodi
+ /// | \ref python_xbmcgui_control_fadelabel "ControlFadeLabel" | The fade label control is used for displaying multiple pieces of text in the same space in Kodi
+ /// | \ref python_xbmcgui_control_list "ControlList" | Add a list for something like files
+ /// | \ref python_xbmcgui_control_group "ControlGroup" | Is for a group which brings the others together
+ /// | \ref python_xbmcgui_control_image "ControlImage" | Controls a image on skin
+ /// | \ref python_xbmcgui_control_radiobutton "ControlRadioButton" | For a radio button which handle boolean values
+ /// | \ref python_xbmcgui_control_progress "ControlProgress" | Progress bar for a performed work or something else
+ /// | \ref python_xbmcgui_control_slider "ControlSlider" | The slider control is used for things where a sliding bar best represents the operation at hand
+ /// | \ref python_xbmcgui_control_spin "ControlSpin" | The spin control is used for when a list of options can be chosen
+ /// | \ref python_xbmcgui_control_textbox "ControlTextBox" | The text box is used for showing a large multipage piece of text in Kodi
+ ///
+ addControl(...);
+#else
+ SWIGHIDDENVIRTUAL void addControl(Control* pControl);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ addControls(List) }
+ /// Add a list of Controls to this window.
+ ///
+ /// @param List List with controls to add
+ /// @throws TypeError If supplied argument is not of List
+ /// type, or a control is not of \ref python_xbmcgui_control
+ /// type
+ /// @throws ReferenceError If control is already used in another
+ /// window
+ /// @throws RuntimeError Should not happen :-)
+ ///
+ addControls(...);
+#else
+ SWIGHIDDENVIRTUAL void addControls(std::vector<Control*> pControls);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window
+ /// @brief \python_func{ getControl(controlId) }
+ /// Gets the control from this window.
+ ///
+ /// @param controlId \ref python_xbmcgui_control id to get
+ /// @throws Exception If \ref python_xbmcgui_control doesn't exist
+ ///
+ /// @remark controlId doesn't have to be a python control, it can be a
+ /// control id from a Kodi window too (you can find id's in the xml files.
+ ///
+ /// @note Not python controls are not completely usable yet
+ /// You can only use the \ref python_xbmcgui_control functions
+ ///
+ getControl(...);
+#else
+ SWIGHIDDENVIRTUAL Control* getControl(int iControlId);
+#endif
+ };
+ ///@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/WindowDialog.cpp b/xbmc/interfaces/legacy/WindowDialog.cpp
new file mode 100644
index 0000000..13ea4fd
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowDialog.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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 "WindowDialog.h"
+
+#include "ServiceBroker.h"
+#include "WindowInterceptor.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindow.h"
+#include "guilib/GUIWindowManager.h"
+
+#include <mutex>
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ WindowDialog::WindowDialog() :
+ Window(true), WindowDialogMixin(this)
+ {
+ std::unique_lock<CCriticalSection> lock(CServiceBroker::GetWinSystem()->GetGfxContext());
+ InterceptorBase* interceptor = new Interceptor<CGUIWindow>("CGUIWindow", this, getNextAvailableWindowId());
+ // set the render order to the dialog's default because this dialog is mapped to CGUIWindow instead of CGUIDialog
+ interceptor->SetRenderOrder(RENDER_ORDER_DIALOG);
+ setWindow(interceptor);
+ }
+
+ WindowDialog::~WindowDialog() { deallocating(); }
+
+ bool WindowDialog::OnMessage(CGUIMessage& message)
+ {
+#ifdef ENABLE_XBMC_TRACE_API
+ XBMC_TRACE;
+ CLog::Log(LOGDEBUG, "{}NEWADDON WindowDialog::OnMessage Message {}", _tg.getSpaces(),
+ message.GetMessage());
+#endif
+
+ switch(message.GetMessage())
+ {
+ case GUI_MSG_WINDOW_INIT:
+ {
+ ref(window)->OnMessage(message);
+ return true;
+ }
+ break;
+
+ case GUI_MSG_CLICKED:
+ {
+ return Window::OnMessage(message);
+ }
+ break;
+ }
+
+ // we do not message CGUIPythonWindow here..
+ return ref(window)->OnMessage(message);
+ }
+
+ bool WindowDialog::OnAction(const CAction &action)
+ {
+ XBMC_TRACE;
+ return WindowDialogMixin::OnAction(action) ? true : Window::OnAction(action);
+ }
+
+ void WindowDialog::OnDeinitWindow(int nextWindowID)
+ {
+ CServiceBroker::GetGUI()->GetWindowManager().RemoveDialog(iWindowId);
+ Window::OnDeinitWindow(nextWindowID);
+ }
+
+ }
+}
diff --git a/xbmc/interfaces/legacy/WindowDialog.h b/xbmc/interfaces/legacy/WindowDialog.h
new file mode 100644
index 0000000..0d44c86
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowDialog.h
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Window.h"
+#include "WindowDialogMixin.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ //
+ /// \defgroup python_xbmcgui_window_dialog Subclass - WindowDialog
+ /// \ingroup python_xbmcgui_window
+ /// @{
+ /// @brief __GUI window dialog class for Add-Ons.__
+ ///
+ /// \python_class{ xbmcgui.WindowDialog(int windowId): }
+ ///
+ /// Creates a new window from Add-On usable dialog class. This is to create
+ /// window for related controls by system calls.
+ ///
+ /// @param windowId [opt] Specify an id to use an existing
+ /// window.
+ /// @throws ValueError if supplied window Id does not exist.
+ /// @throws Exception if more then 200 windows are created.
+ ///
+ /// Deleting this window will activate the old window that was active
+ /// and resets (not delete) all controls that are associated with this
+ /// window.
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.WindowDialog()
+ /// width = dialog.getWidth()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ ///
+ //
+ class WindowDialog : public Window, private WindowDialogMixin
+ {
+ public:
+ WindowDialog();
+ ~WindowDialog() override;
+
+#ifndef SWIG
+ bool OnMessage(CGUIMessage& message) override;
+ bool OnAction(const CAction& action) override;
+ void OnDeinitWindow(int nextWindowID) override;
+
+ bool IsDialogRunning() const override { return WindowDialogMixin::IsDialogRunning(); }
+ bool IsModalDialog() const override
+ {
+ XBMC_TRACE;
+ return true;
+ };
+ bool IsDialog() const override
+ {
+ XBMC_TRACE;
+ return true;
+ };
+
+ inline void show() override
+ {
+ XBMC_TRACE;
+ WindowDialogMixin::show();
+ }
+ inline void close() override
+ {
+ XBMC_TRACE;
+ WindowDialogMixin::close();
+ }
+#endif
+ };
+ ///@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/WindowDialogMixin.cpp b/xbmc/interfaces/legacy/WindowDialogMixin.cpp
new file mode 100644
index 0000000..32d6fa9
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowDialogMixin.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "WindowDialogMixin.h"
+
+#include "ServiceBroker.h"
+#include "WindowInterceptor.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "messaging/ApplicationMessenger.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ void WindowDialogMixin::show()
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_PYTHON_DIALOG, HACK_CUSTOM_ACTION_OPENING,
+ 0, static_cast<void*>(w->window->get()));
+ }
+
+ void WindowDialogMixin::close()
+ {
+ XBMC_TRACE;
+ w->bModal = false;
+ w->PulseActionEvent();
+
+ CServiceBroker::GetAppMessenger()->SendMsg(TMSG_GUI_PYTHON_DIALOG, HACK_CUSTOM_ACTION_CLOSING,
+ 0, static_cast<void*>(w->window->get()));
+
+ w->iOldWindowId = 0;
+ }
+
+ bool WindowDialogMixin::IsDialogRunning() const { XBMC_TRACE; return w->window->isActive(); }
+
+ bool WindowDialogMixin::OnAction(const CAction &action)
+ {
+ XBMC_TRACE;
+ switch (action.GetID())
+ {
+ case HACK_CUSTOM_ACTION_OPENING:
+ {
+ // This is from the CGUIPythonWindowXMLDialog::Show_Internal
+ CServiceBroker::GetGUI()->GetWindowManager().RegisterDialog(w->window->get());
+ // active this dialog...
+ CGUIMessage msg(GUI_MSG_WINDOW_INIT,0,0);
+ w->OnMessage(msg);
+ w->window->setActive(true);
+ //! @todo Figure out how to clean up the CAction
+ return true;
+ }
+ break;
+
+ case HACK_CUSTOM_ACTION_CLOSING:
+ {
+ // This is from the CGUIPythonWindowXMLDialog::Show_Internal
+ w->window->get()->Close();
+ return true;
+ }
+ break;
+ }
+
+ return false;
+ }
+ }
+}
+
+
+
diff --git a/xbmc/interfaces/legacy/WindowDialogMixin.h b/xbmc/interfaces/legacy/WindowDialogMixin.h
new file mode 100644
index 0000000..5057e81
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowDialogMixin.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Window.h"
+
+// These messages are a side effect of the way dialogs work through the
+// main ApplicationMessenger. At some point it would be nice to remove
+// the messenger and have direct (or even drive) communications.
+#define HACK_CUSTOM_ACTION_CLOSING -3
+#define HACK_CUSTOM_ACTION_OPENING -4
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ class WindowDialogMixin
+ {
+ private:
+ Window* w;
+
+ protected:
+ inline explicit WindowDialogMixin(Window* window) : w(window) {}
+
+ public:
+ virtual ~WindowDialogMixin() = default;
+
+ SWIGHIDDENVIRTUAL void show();
+ SWIGHIDDENVIRTUAL void close();
+
+#ifndef SWIG
+ SWIGHIDDENVIRTUAL bool IsDialogRunning() const;
+ SWIGHIDDENVIRTUAL bool OnAction(const CAction &action);
+#endif
+ };
+ }
+}
diff --git a/xbmc/interfaces/legacy/WindowException.h b/xbmc/interfaces/legacy/WindowException.h
new file mode 100644
index 0000000..ae35b57
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowException.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Exception.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ XBMCCOMMONS_STANDARD_EXCEPTION(WindowException);
+ }
+}
+
+
diff --git a/xbmc/interfaces/legacy/WindowInterceptor.h b/xbmc/interfaces/legacy/WindowInterceptor.h
new file mode 100644
index 0000000..4890150
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowInterceptor.h
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Window.h"
+#include "guilib/GUIWindow.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+
+#ifndef SWIG
+ class Window;
+ class ref;
+
+ /**
+ * These two classes are closely associated with the Interceptor template below.
+ * For more detailed explanation, see that class.
+ */
+ class InterceptorBase
+ {
+ protected:
+ AddonClass::Ref<Window> window;
+ // This instance is in Window.cpp
+ static thread_local ref* upcallTls;
+
+ InterceptorBase() : window(NULL) { upcallTls = NULL; }
+
+ /**
+ * Calling up ONCE resets the upcall to to false. The reason is that when
+ * a call is recursive we cannot assume the ref has cleared the flag.
+ * so ...
+ *
+ * ref(window)->UpCall()
+ *
+ * during the context of 'UpCall' it's possible that another call will
+ * be made back on the window from the xbmc core side (this happens in
+ * sometimes in OnMessage). In that case, if upcall is still 'true', than
+ * the call will wrongly proceed back to the xbmc core side rather than
+ * to the Addon API side.
+ */
+ static bool up() { bool ret = ((upcallTls) != NULL); upcallTls = NULL; return ret; }
+ public:
+
+ virtual ~InterceptorBase() { if (window.isNotNull()) { window->interceptorClear(); } }
+
+ virtual CGUIWindow* get() = 0;
+
+ virtual void SetRenderOrder(int renderOrder) { }
+
+ virtual void setActive(bool active) { }
+ virtual bool isActive() { return false; }
+
+ friend class ref;
+ };
+
+ /**
+ * Guard class. But instead of managing memory or thread resources,
+ * any call made using the operator-> results in an 'upcall.' That is,
+ * it expects the call about to be made to have come from the XBMCAddon
+ * xbmcgui Window API and not from either the scripting language or the
+ * XBMC core Windowing system.
+ *
+ * This class is meant to hold references to instances of Interceptor<P>.
+ * see that template definition below.
+ */
+ class ref
+ {
+ InterceptorBase* w;
+ public:
+ inline explicit ref(InterceptorBase* b) : w(b) { w->upcallTls = this; }
+ inline ~ref() { w->upcallTls = NULL; }
+ inline CGUIWindow* operator->() { return w->get(); }
+ inline CGUIWindow* get() { return w->get(); }
+ };
+
+ /**
+ * The intention of this class is to intercept calls from
+ * multiple points in the CGUIWindow class hierarchy and pass
+ * those calls over to the XBMCAddon API Window hierarchy. It
+ * is a class template that uses the type template parameter
+ * to determine the parent class.
+ *
+ * Since this class also maintains two way communication between
+ * the XBMCAddon API Window hierarchy and the core XBMC CGUIWindow
+ * hierarchy, it is used as a general bridge. For calls going
+ * TO the window hierarchy (as in callbacks) it operates in a
+ * straightforward manner. In the reverse direction (from the
+ * XBMCAddon hierarchy) it uses some hackery in a "smart pointer"
+ * overloaded -> operator.
+ */
+
+#define checkedb(methcall) ( window.isNotNull() ? window-> methcall : false )
+#define checkedv(methcall) { if (window.isNotNull()) window-> methcall ; }
+
+ template <class P /* extends CGUIWindow*/> class Interceptor :
+ public P, public InterceptorBase
+ {
+ std::string classname;
+ protected:
+ CGUIWindow* get() override { return this; }
+
+ public:
+ Interceptor(const char* specializedName,
+ Window* _window, int windowid) : P(windowid, ""),
+ classname("Interceptor<" + std::string(specializedName) + ">")
+ {
+#ifdef ENABLE_XBMC_TRACE_API
+ XBMCAddonUtils::TraceGuard tg;
+ CLog::Log(LOGDEBUG, "{}NEWADDON constructing {} 0x{:x}", tg.getSpaces(), classname,
+ (long)(((void*)this)));
+#endif
+ window.reset(_window);
+ P::SetLoadType(CGUIWindow::LOAD_ON_GUI_INIT);
+ }
+
+ Interceptor(const char* specializedName,
+ Window* _window, int windowid,
+ const char* xmlfile) : P(windowid, xmlfile),
+ classname("Interceptor<" + std::string(specializedName) + ">")
+ {
+#ifdef ENABLE_XBMC_TRACE_API
+ XBMCAddonUtils::TraceGuard tg;
+ CLog::Log(LOGDEBUG, "{}NEWADDON constructing {} 0x{:x}", tg.getSpaces(), classname,
+ (long)(((void*)this)));
+#endif
+ window.reset(_window);
+ P::SetLoadType(CGUIWindow::LOAD_ON_GUI_INIT);
+ }
+
+#ifdef ENABLE_XBMC_TRACE_API
+ ~Interceptor() override
+ {
+ XBMCAddonUtils::TraceGuard tg;
+ CLog::Log(LOGDEBUG, "{}NEWADDON LIFECYCLE destroying {} 0x{:x}", tg.getSpaces(), classname,
+ (long)(((void*)this)));
+ }
+#else
+ ~Interceptor() override = default;
+#endif
+
+ bool OnMessage(CGUIMessage& message) override
+ { XBMC_TRACE; return up() ? P::OnMessage(message) : checkedb(OnMessage(message)); }
+ bool OnAction(const CAction &action) override
+ { XBMC_TRACE; return up() ? P::OnAction(action) : checkedb(OnAction(action)); }
+
+ // NOTE!!: This ALWAYS skips up to the CGUIWindow instance.
+ bool OnBack(int actionId) override
+ { XBMC_TRACE; return up() ? CGUIWindow::OnBack(actionId) : checkedb(OnBack(actionId)); }
+
+ void OnDeinitWindow(int nextWindowID) override
+ { XBMC_TRACE; if(up()) P::OnDeinitWindow(nextWindowID); else checkedv(OnDeinitWindow(nextWindowID)); }
+
+ bool IsModalDialog() const override
+ {
+ XBMC_TRACE;
+ return checkedb(IsModalDialog());
+ }
+
+ bool IsDialogRunning() const override
+ {
+ XBMC_TRACE;
+ return checkedb(IsDialogRunning());
+ }
+ bool IsDialog() const override
+ {
+ XBMC_TRACE;
+ return checkedb(IsDialog());
+ }
+ bool IsMediaWindow() const override
+ {
+ XBMC_TRACE;
+ return checkedb(IsMediaWindow());
+ }
+
+ void SetRenderOrder(int renderOrder) override { XBMC_TRACE; P::m_renderOrder = renderOrder; }
+
+ void setActive(bool active) override { XBMC_TRACE; P::m_active = active; }
+ bool isActive() override { XBMC_TRACE; return P::m_active; }
+ };
+
+ template <class P /* extends CGUIWindow*/> class InterceptorDialog :
+ public Interceptor<P>
+ {
+ public:
+ InterceptorDialog(const char* specializedName,
+ Window* _window, int windowid) :
+ Interceptor<P>(specializedName, _window, windowid)
+ { }
+
+ InterceptorDialog(const char* specializedName,
+ Window* _window, int windowid,
+ const char* xmlfile) :
+ Interceptor<P>(specializedName, _window, windowid,xmlfile)
+ { }
+ };
+
+#undef checkedb
+#undef checkedv
+
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/WindowXML.cpp b/xbmc/interfaces/legacy/WindowXML.cpp
new file mode 100644
index 0000000..51a4fbf
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowXML.cpp
@@ -0,0 +1,527 @@
+/*
+ * 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 "WindowXML.h"
+
+#include "ServiceBroker.h"
+#include "WindowException.h"
+#include "WindowInterceptor.h"
+#include "addons/Addon.h"
+#include "addons/Skin.h"
+#include "addons/addoninfo/AddonInfo.h"
+#include "addons/addoninfo/AddonType.h"
+#include "guilib/GUIComponent.h"
+#include "guilib/GUIWindowManager.h"
+#include "guilib/TextureManager.h"
+#include "utils/FileUtils.h"
+#include "utils/StringUtils.h"
+#include "utils/URIUtils.h"
+
+#include <mutex>
+
+// These #defs are for WindowXML
+#define CONTROL_BTNVIEWASICONS 2
+#define CONTROL_BTNSORTBY 3
+#define CONTROL_BTNSORTASC 4
+#define CONTROL_LABELFILES 12
+
+#define A(x) interceptor->x
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ template class Interceptor<CGUIMediaWindow>;
+
+ /**
+ * This class extends the Interceptor<CGUIMediaWindow> in order to
+ * add behavior for a few more virtual functions that were unnecessary
+ * in the Window or WindowDialog.
+ */
+#define checkedb(methcall) ( window.isNotNull() ? xwin-> methcall : false )
+#define checkedv(methcall) { if (window.isNotNull()) xwin-> methcall ; }
+
+
+ //! @todo This should be done with template specialization
+ class WindowXMLInterceptor : public InterceptorDialog<CGUIMediaWindow>
+ {
+ WindowXML* xwin;
+ public:
+ WindowXMLInterceptor(WindowXML* _window, int windowid,const char* xmlfile) :
+ InterceptorDialog<CGUIMediaWindow>("CGUIMediaWindow",_window,windowid,xmlfile), xwin(_window)
+ { }
+
+ void AllocResources(bool forceLoad = false) override
+ { XBMC_TRACE; if(up()) CGUIMediaWindow::AllocResources(forceLoad); else checkedv(AllocResources(forceLoad)); }
+ void FreeResources(bool forceUnLoad = false) override
+ { XBMC_TRACE; if(up()) CGUIMediaWindow::FreeResources(forceUnLoad); else checkedv(FreeResources(forceUnLoad)); }
+ bool OnClick(int iItem, const std::string &player = "") override { XBMC_TRACE; return up() ? CGUIMediaWindow::OnClick(iItem, player) : checkedb(OnClick(iItem)); }
+
+ void Process(unsigned int currentTime, CDirtyRegionList &dirtyregions) override
+ { XBMC_TRACE; if(up()) CGUIMediaWindow::Process(currentTime,dirtyregions); else checkedv(Process(currentTime,dirtyregions)); }
+
+ // this is a hack to SKIP the CGUIMediaWindow
+ bool OnAction(const CAction &action) override
+ { XBMC_TRACE; return up() ? CGUIWindow::OnAction(action) : checkedb(OnAction(action)); }
+
+ protected:
+ // CGUIWindow
+ bool LoadXML(const std::string &strPath, const std::string &strPathLower) override
+ { XBMC_TRACE; return up() ? CGUIMediaWindow::LoadXML(strPath,strPathLower) : xwin->LoadXML(strPath,strPathLower); }
+
+ // CGUIMediaWindow
+ void GetContextButtons(int itemNumber, CContextButtons &buttons) override
+ { XBMC_TRACE; if (up()) CGUIMediaWindow::GetContextButtons(itemNumber,buttons); else xwin->GetContextButtons(itemNumber,buttons); }
+ bool Update(const std::string &strPath, bool) override
+ { XBMC_TRACE; return up() ? CGUIMediaWindow::Update(strPath) : xwin->Update(strPath); }
+ void SetupShares() override { XBMC_TRACE; if(up()) CGUIMediaWindow::SetupShares(); else checkedv(SetupShares()); }
+
+ friend class WindowXML;
+ friend class WindowXMLDialog;
+
+ };
+
+ WindowXML::~WindowXML() { XBMC_TRACE; deallocating(); }
+
+ WindowXML::WindowXML(const String& xmlFilename,
+ const String& scriptPath,
+ const String& defaultSkin,
+ const String& defaultRes,
+ bool isMedia) :
+ Window(true)
+ {
+ XBMC_TRACE;
+ RESOLUTION_INFO res;
+ std::string strSkinPath = g_SkinInfo->GetSkinPath(xmlFilename, &res);
+ m_isMedia = isMedia;
+
+ if (!CFileUtils::Exists(strSkinPath))
+ {
+ std::string str("none");
+ ADDON::AddonInfoPtr addonInfo =
+ std::make_shared<ADDON::CAddonInfo>(str, ADDON::AddonType::SKIN);
+ ADDON::CSkinInfo::TranslateResolution(defaultRes, res);
+
+ // Check for the matching folder for the skin in the fallback skins folder
+ std::string fallbackPath = URIUtils::AddFileToFolder(scriptPath, "resources", "skins");
+ std::string basePath = URIUtils::AddFileToFolder(fallbackPath, g_SkinInfo->ID());
+
+ strSkinPath = g_SkinInfo->GetSkinPath(xmlFilename, &res, basePath);
+
+ // Check for the matching folder for the skin in the fallback skins folder (if it exists)
+ if (CFileUtils::Exists(basePath))
+ {
+ addonInfo->SetPath(basePath);
+ std::shared_ptr<ADDON::CSkinInfo> skinInfo = std::make_shared<ADDON::CSkinInfo>(addonInfo, res);
+ skinInfo->Start();
+ strSkinPath = skinInfo->GetSkinPath(xmlFilename, &res);
+ }
+
+ if (!CFileUtils::Exists(strSkinPath))
+ {
+ // Finally fallback to the DefaultSkin as it didn't exist in either the XBMC Skin folder or the fallback skin folder
+ addonInfo->SetPath(URIUtils::AddFileToFolder(fallbackPath, defaultSkin));
+ std::shared_ptr<ADDON::CSkinInfo> skinInfo = std::make_shared<ADDON::CSkinInfo>(addonInfo, res);
+
+ skinInfo->Start();
+ strSkinPath = skinInfo->GetSkinPath(xmlFilename, &res);
+ if (!CFileUtils::Exists(strSkinPath))
+ throw WindowException("XML File for Window is missing");
+ }
+ }
+
+ m_scriptPath = scriptPath;
+// sXMLFileName = strSkinPath;
+
+ interceptor = new WindowXMLInterceptor(this, lockingGetNextAvailableWindowId(),strSkinPath.c_str());
+ setWindow(interceptor);
+ interceptor->SetCoordsRes(res);
+ }
+
+ int WindowXML::lockingGetNextAvailableWindowId()
+ {
+ XBMC_TRACE;
+ std::unique_lock<CCriticalSection> lock(CServiceBroker::GetWinSystem()->GetGfxContext());
+ return getNextAvailableWindowId();
+ }
+
+ void WindowXML::addItem(const Alternative<String, const ListItem*>& item, int position)
+ {
+ XBMC_TRACE;
+ // item could be deleted if the reference count is 0.
+ // so I MAY need to check prior to using a Ref just in
+ // case this object is managed by Python. I'm not sure
+ // though.
+ AddonClass::Ref<ListItem> ritem = item.which() == XBMCAddon::first ? ListItem::fromString(item.former()) : AddonClass::Ref<ListItem>(item.later());
+
+ // Tells the window to add the item to FileItem vector
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+
+ //----------------------------------------------------
+ // Former AddItem call
+ //AddItem(ritem->item, pos);
+ {
+ CFileItemPtr& fileItem = ritem->item;
+ if (position == INT_MAX || position > A(m_vecItems)->Size())
+ {
+ A(m_vecItems)->Add(fileItem);
+ }
+ else if (position < -1 && !(position*-1 < A(m_vecItems)->Size()))
+ {
+ A(m_vecItems)->AddFront(fileItem,0);
+ }
+ else
+ {
+ A(m_vecItems)->AddFront(fileItem,position);
+ }
+ A(m_viewControl).SetItems(*(A(m_vecItems)));
+ }
+ //----------------------------------------------------
+ }
+ }
+
+ void WindowXML::addItems(const std::vector<Alternative<String, const XBMCAddon::xbmcgui::ListItem* > > & items)
+ {
+ XBMC_TRACE;
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ for (auto item : items)
+ {
+ AddonClass::Ref<ListItem> ritem = item.which() == XBMCAddon::first ? ListItem::fromString(item.former()) : AddonClass::Ref<ListItem>(item.later());
+ CFileItemPtr& fileItem = ritem->item;
+ A(m_vecItems)->Add(fileItem);
+ }
+ A(m_viewControl).SetItems(*(A(m_vecItems)));
+ }
+
+
+ void WindowXML::removeItem(int position)
+ {
+ XBMC_TRACE;
+ // Tells the window to remove the item at the specified position from the FileItem vector
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ A(m_vecItems)->Remove(position);
+ A(m_viewControl).SetItems(*(A(m_vecItems)));
+ }
+
+ int WindowXML::getCurrentListPosition()
+ {
+ XBMC_TRACE;
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ int listPos = A(m_viewControl).GetSelectedItem();
+ return listPos;
+ }
+
+ void WindowXML::setCurrentListPosition(int position)
+ {
+ XBMC_TRACE;
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ A(m_viewControl).SetSelectedItem(position);
+ }
+
+ ListItem* WindowXML::getListItem(int position)
+ {
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ //CFileItemPtr fi = pwx->GetListItem(listPos);
+ CFileItemPtr fi;
+ {
+ if (position < 0 || position >= A(m_vecItems)->Size())
+ return new ListItem();
+ fi = A(m_vecItems)->Get(position);
+ }
+
+ if (fi == NULL)
+ {
+ throw WindowException("Index out of range (%i)",position);
+ }
+
+ ListItem* sListItem = new ListItem();
+ sListItem->item = fi;
+
+ // let's hope someone reference counts this.
+ return sListItem;
+ }
+
+ int WindowXML::getListSize()
+ {
+ XBMC_TRACE;
+ return A(m_vecItems)->Size();
+ }
+
+ void WindowXML::clearList()
+ {
+ XBMC_TRACE;
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ A(ClearFileItems());
+
+ A(m_viewControl).SetItems(*(A(m_vecItems)));
+ }
+
+ void WindowXML::setContainerProperty(const String& key, const String& value)
+ {
+ XBMC_TRACE;
+ A(m_vecItems)->SetProperty(key, value);
+ }
+
+ void WindowXML::setContent(const String& value)
+ {
+ XBMC_TRACE;
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ A(m_vecItems)->SetContent(value);
+ }
+
+ int WindowXML::getCurrentContainerId()
+ {
+ XBMC_TRACE;
+ XBMCAddonUtils::GuiLock lock(languageHook, false);
+ return A(m_viewControl.GetCurrentControl());
+ }
+
+ bool WindowXML::OnAction(const CAction &action)
+ {
+ XBMC_TRACE;
+ // do the base class window first, and the call to python after this
+ bool ret = ref(window)->OnAction(action); // we don't currently want the mediawindow actions here
+ // look at the WindowXMLInterceptor onAction, it skips
+ // the CGUIMediaWindow::OnAction and calls directly to
+ // CGUIWindow::OnAction
+ AddonClass::Ref<Action> inf(new Action(action));
+ invokeCallback(new CallbackFunction<WindowXML,AddonClass::Ref<Action> >(this,&WindowXML::onAction,inf.get()));
+ PulseActionEvent();
+ return ret;
+ }
+
+ bool WindowXML::OnMessage(CGUIMessage& message)
+ {
+#ifdef ENABLE_XBMC_TRACE_API
+ XBMC_TRACE;
+ CLog::Log(LOGDEBUG, "{}Message id:{}", _tg.getSpaces(), (int)message.GetMessage());
+#endif
+
+ //! @todo We shouldn't be dropping down to CGUIWindow in any of this ideally.
+ //! We have to make up our minds about what python should be doing and
+ //! what this side of things should be doing
+ switch (message.GetMessage())
+ {
+ case GUI_MSG_WINDOW_DEINIT:
+ {
+ return ref(window)->OnMessage(message);
+ }
+ break;
+
+ case GUI_MSG_WINDOW_INIT:
+ {
+ ref(window)->OnMessage(message);
+ invokeCallback(new CallbackFunction<WindowXML>(this,&WindowXML::onInit));
+ PulseActionEvent();
+ return true;
+ }
+ break;
+
+ case GUI_MSG_FOCUSED:
+ {
+ if (A(m_viewControl).HasControl(message.GetControlId()) &&
+ A(m_viewControl).GetCurrentControl() != message.GetControlId())
+ {
+ A(m_viewControl).SetFocused();
+ return true;
+ }
+ // check if our focused control is one of our category buttons
+ int iControl=message.GetControlId();
+
+ invokeCallback(new CallbackFunction<WindowXML,int>(this,&WindowXML::onFocus,iControl));
+ PulseActionEvent();
+ }
+ break;
+
+ case GUI_MSG_NOTIFY_ALL:
+ // most messages from GUI_MSG_NOTIFY_ALL break container content, whitelist working ones.
+ if (message.GetParam1() == GUI_MSG_PAGE_CHANGE || message.GetParam1() == GUI_MSG_WINDOW_RESIZE)
+ return A(CGUIMediaWindow::OnMessage(message));
+ return true;
+
+ case GUI_MSG_CLICKED:
+ {
+ int iControl=message.GetSenderId();
+ // Handle Sort/View internally. Scripters shouldn't use ID 2, 3 or 4.
+ if (iControl == CONTROL_BTNSORTASC) // sort asc
+ {
+ CLog::Log(LOGINFO, "WindowXML: Internal asc/dsc button not implemented");
+ /*if (m_guiState.get())
+ m_guiState->SetNextSortOrder();
+ UpdateFileList();*/
+ return true;
+ }
+ else if (iControl == CONTROL_BTNSORTBY) // sort by
+ {
+ CLog::Log(LOGINFO, "WindowXML: Internal sort button not implemented");
+ /*if (m_guiState.get())
+ m_guiState->SetNextSortMethod();
+ UpdateFileList();*/
+ return true;
+ }
+
+ if(iControl && iControl != interceptor->GetID()) // pCallbackWindow && != this->GetID())
+ {
+ CGUIControl* controlClicked = interceptor->GetControl(iControl);
+
+ // The old python way used to check list AND SELECITEM method
+ // or if its a button, radiobutton.
+ // Its done this way for now to allow other controls without a
+ // python version like togglebutton to still raise a onAction event
+ if (controlClicked) // Will get problems if we the id is not on the window
+ // and we try to do GetControlType on it. So check to make sure it exists
+ {
+ if ((controlClicked->IsContainer() && (message.GetParam1() == ACTION_SELECT_ITEM || message.GetParam1() == ACTION_MOUSE_LEFT_CLICK)) || !controlClicked->IsContainer())
+ {
+ invokeCallback(new CallbackFunction<WindowXML,int>(this,&WindowXML::onClick,iControl));
+ PulseActionEvent();
+ return true;
+ }
+ else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_MOUSE_DOUBLE_CLICK)
+ {
+ invokeCallback(new CallbackFunction<WindowXML,int>(this,&WindowXML::onDoubleClick,iControl));
+ PulseActionEvent();
+ return true;
+ }
+ else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_MOUSE_RIGHT_CLICK)
+ {
+ AddonClass::Ref<Action> inf(new Action(CAction(ACTION_CONTEXT_MENU)));
+ invokeCallback(new CallbackFunction<WindowXML,AddonClass::Ref<Action> >(this,&WindowXML::onAction,inf.get()));
+ PulseActionEvent();
+ return true;
+ }
+ // the core context menu can lead to all sort of issues right now when used with WindowXMLs, so lets intercept the corresponding message
+ else if (controlClicked->IsContainer() && message.GetParam1() == ACTION_CONTEXT_MENU)
+ return true;
+ }
+ }
+ }
+ break;
+ }
+
+ return A(CGUIMediaWindow::OnMessage(message));
+ }
+
+ void WindowXML::AllocResources(bool forceLoad /*= false */)
+ {
+ XBMC_TRACE;
+ std::string tmpDir = URIUtils::GetDirectory(ref(window)->GetProperty("xmlfile").asString());
+ std::string fallbackMediaPath;
+ URIUtils::GetParentPath(tmpDir, fallbackMediaPath);
+ URIUtils::RemoveSlashAtEnd(fallbackMediaPath);
+ m_mediaDir = fallbackMediaPath;
+
+ //CLog::Log(LOGDEBUG, "CGUIPythonWindowXML::AllocResources called: {}", fallbackMediaPath);
+ CServiceBroker::GetGUI()->GetTextureManager().AddTexturePath(m_mediaDir);
+ ref(window)->AllocResources(forceLoad);
+ CServiceBroker::GetGUI()->GetTextureManager().RemoveTexturePath(m_mediaDir);
+ }
+
+ void WindowXML::FreeResources(bool forceUnLoad /*= false */)
+ {
+ XBMC_TRACE;
+
+ ref(window)->FreeResources(forceUnLoad);
+ }
+
+ void WindowXML::Process(unsigned int currentTime, CDirtyRegionList &regions)
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetGUI()->GetTextureManager().AddTexturePath(m_mediaDir);
+ ref(window)->Process(currentTime, regions);
+ CServiceBroker::GetGUI()->GetTextureManager().RemoveTexturePath(m_mediaDir);
+ }
+
+ bool WindowXML::OnClick(int iItem)
+ {
+ XBMC_TRACE;
+ // Hook Over calling CGUIMediaWindow::OnClick(iItem) results in it trying to PLAY the file item
+ // which if its not media is BAD and 99 out of 100 times undesirable.
+ return false;
+ }
+
+ bool WindowXML::OnDoubleClick(int iItem)
+ {
+ XBMC_TRACE;
+ return false;
+ }
+
+ void WindowXML::GetContextButtons(int itemNumber, CContextButtons &buttons)
+ {
+ XBMC_TRACE;
+ // maybe on day we can make an easy way to do this context menu
+ // with out this method overriding the MediaWindow version, it will display 'Add to Favorites'
+ }
+
+ bool WindowXML::LoadXML(const String &strPath, const String &strLowerPath)
+ {
+ XBMC_TRACE;
+ return A(CGUIWindow::LoadXML(strPath, strLowerPath));
+ }
+
+ void WindowXML::SetupShares()
+ {
+ XBMC_TRACE;
+ }
+
+ bool WindowXML::Update(const String &strPath)
+ {
+ XBMC_TRACE;
+ return true;
+ }
+
+ WindowXMLDialog::WindowXMLDialog(const String& xmlFilename, const String& scriptPath,
+ const String& defaultSkin,
+ const String& defaultRes) :
+ WindowXML(xmlFilename, scriptPath, defaultSkin, defaultRes),
+ WindowDialogMixin(this)
+ { XBMC_TRACE; }
+
+ WindowXMLDialog::~WindowXMLDialog() { XBMC_TRACE; deallocating(); }
+
+ bool WindowXMLDialog::OnMessage(CGUIMessage &message)
+ {
+ XBMC_TRACE;
+ if (message.GetMessage() == GUI_MSG_WINDOW_DEINIT)
+ return A(CGUIWindow::OnMessage(message));
+
+ return WindowXML::OnMessage(message);
+ }
+
+ bool WindowXMLDialog::OnAction(const CAction &action)
+ {
+ XBMC_TRACE;
+ return WindowDialogMixin::OnAction(action) ? true : WindowXML::OnAction(action);
+ }
+
+ void WindowXMLDialog::OnDeinitWindow(int nextWindowID)
+ {
+ XBMC_TRACE;
+ CServiceBroker::GetGUI()->GetWindowManager().RemoveDialog(interceptor->GetID());
+ WindowXML::OnDeinitWindow(nextWindowID);
+ }
+
+ bool WindowXMLDialog::LoadXML(const String &strPath, const String &strLowerPath)
+ {
+ XBMC_TRACE;
+ if (WindowXML::LoadXML(strPath, strLowerPath))
+ {
+ // Set the render order to the dialog's default in case it's not specified in the skin xml
+ // because this dialog is mapped to CGUIMediaWindow instead of CGUIDialog.
+ // This must be done here, because the render order will be reset before loading the skin xml.
+ if (ref(window)->GetRenderOrder() == RENDER_ORDER_WINDOW)
+ window->SetRenderOrder(RENDER_ORDER_DIALOG);
+ return true;
+ }
+ return false;
+ }
+
+ }
+
+}
diff --git a/xbmc/interfaces/legacy/WindowXML.h b/xbmc/interfaces/legacy/WindowXML.h
new file mode 100644
index 0000000..349b0a0
--- /dev/null
+++ b/xbmc/interfaces/legacy/WindowXML.h
@@ -0,0 +1,559 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "Window.h"
+#include "WindowDialogMixin.h"
+#include "swighelper.h"
+#include "windows/GUIMediaWindow.h"
+
+#include <limits.h>
+#include <vector>
+
+namespace XBMCAddon
+{
+ namespace xbmcgui
+ {
+ class ListItem;
+ class WindowXMLInterceptor;
+
+ //
+ /// \defgroup python_xbmcgui_window_xml Subclass - WindowXML
+ /// \ingroup python_xbmcgui_window
+ /// @{
+ /// @brief __GUI xml window class.__
+ ///
+ /// \python_class{ xbmcgui.WindowXML(xmlFilename, scriptPath[, defaultSkin, defaultRes]) }
+ ///
+ /// Creates a new xml file based window class.
+ ///
+ /// \note This class include also all calls from <b><c>\ref python_xbmcgui_window</c></b>.
+ ///
+ /// @param xmlFilename string - the name of the xml file to
+ /// look for.
+ /// @param scriptPath string - path to script. used to
+ /// fallback to if the xml doesn't exist in
+ /// the current skin. (eg xbmcaddon.Addon().getAddonInfo('path'))
+ /// @param defaultSkin [opt] string - name of the folder in the
+ /// skins path to look in for the xml.
+ /// (default='Default')
+ /// @param defaultRes [opt] string - default skins resolution.
+ /// (1080i, 720p, ntsc16x9, ntsc, pal16x9 or pal. default='720p')
+ /// @param isMedia [opt] bool - if False, create a regular window.
+ /// if True, create a mediawindow.
+ /// (default=False)
+ /// @throws Exception if more then 200 windows are created.
+ ///
+ /// \remark Skin folder structure is e.g. **resources/skins/Default/720p**
+ ///
+ /// Deleting this window will activate the old window that was active
+ /// and resets (not delete) all controls that are associated with this
+ /// window.
+ ///
+ ///--------------------------------------------------------------------------
+ /// @python_v18 New param added **isMedia**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// win = xbmcgui.WindowXML('script-Lyrics-main.xml', xbmcaddon.Addon().getAddonInfo('path'), 'default', '1080i', False)
+ /// win.doModal()
+ /// del win
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ ///
+ ///--------------------------------------------------------------------------
+ ///
+ /// On functions defined input variable <b><tt>controlId</tt> (GUI control identifier)</b>
+ /// is the on window.xml defined value behind type added with <tt><b>id="..."</b></tt> and
+ /// used to identify for changes there and on callbacks.
+ ///
+ /// ~~~~~~~~~~~~~{.xml}
+ /// <control type="label" id="31">
+ /// <description>Title Label</description>
+ /// ...
+ /// </control>
+ /// <control type="progress" id="32">
+ /// <description>progress control</description>
+ /// ...
+ /// </control>
+ /// ~~~~~~~~~~~~~
+ ///
+ //
+ class WindowXML : public Window
+ {
+ std::string sFallBackPath;
+
+ protected:
+#ifndef SWIG
+ /**
+ * This helper retrieves the next available id. It is doesn't
+ * assume that the global lock is already being held.
+ */
+ static int lockingGetNextAvailableWindowId();
+
+ WindowXMLInterceptor* interceptor;
+#endif
+
+ public:
+ WindowXML(const String& xmlFilename, const String& scriptPath,
+ const String& defaultSkin = "Default",
+ const String& defaultRes = "720p",
+ bool isMedia = false);
+ ~WindowXML() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ addItem(item[, position]) }
+ /// Add a new item to this Window List.
+ ///
+ /// @param item string, unicode or ListItem - item to add.
+ /// @param position [opt] integer - position of item to add. (NO Int = Adds to bottom,0 adds to top, 1 adds to one below from top,-1 adds to one above from bottom etc etc )
+ /// - If integer positions are greater than list size, negative positions will add to top of list, positive positions will add to bottom of list
+ ///
+ ///
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.addItem('Reboot Kodi', 0)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ addItem(...);
+#else
+ SWIGHIDDENVIRTUAL void addItem(const Alternative<String, const ListItem*>& item, int position = INT_MAX);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ addItems(items) }
+ /// Add a list of items to to the window list.
+ ///
+ ///
+ /// @param items List - list of strings, unicode objects or ListItems to add.
+ ///
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.addItems(['Reboot Kodi', 'Restart Kodi'])
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ addItems(...);
+#else
+ SWIGHIDDENVIRTUAL void addItems(const std::vector<Alternative<String, const XBMCAddon::xbmcgui::ListItem* > > & items);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ removeItem(position) }
+ /// Removes a specified item based on position, from the Window List.
+ ///
+ /// @param position integer - position of item to remove.
+ ///
+ ///
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.removeItem(5)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ removeItem(...);
+#else
+ SWIGHIDDENVIRTUAL void removeItem(int position);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ getCurrentListPosition() }
+ /// Gets the current position in the Window List.
+ ///
+ ///
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// pos = self.getCurrentListPosition()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCurrentListPosition();
+#else
+ SWIGHIDDENVIRTUAL int getCurrentListPosition();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ setCurrentListPosition(position) }
+ /// Set the current position in the Window List.
+ ///
+ /// @param position integer - position of item to set.
+ ///
+ ///
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.setCurrentListPosition(5)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setCurrentListPosition(...);
+#else
+ SWIGHIDDENVIRTUAL void setCurrentListPosition(int position);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ getListItem(position) }
+ /// Returns a given ListItem in this Window List.
+ ///
+ /// @param position integer - position of item to return.
+ ///
+ ///
+ ///
+ /// ----------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// listitem = self.getListItem(6)
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getListItem(...);
+#else
+ SWIGHIDDENVIRTUAL ListItem* getListItem(int position);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ getListSize() }
+ /// Returns the number of items in this Window List.
+ ///
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// listSize = self.getListSize()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getListSize();
+#else
+ SWIGHIDDENVIRTUAL int getListSize();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ clearList() }
+ /// Clear the Window List.
+ ///
+ /// ------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.clearList()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ clearList();
+#else
+ SWIGHIDDENVIRTUAL void clearList();
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ setContainerProperty(key, value) }
+ /// Sets a container property, similar to an infolabel.
+ ///
+ /// @param key string - property name.
+ /// @param value string or unicode - value of property.
+ ///
+ /// @note Key is NOT case sensitive.\n
+ /// You can use the above as keywords for arguments and skip certain
+ /// optional arguments.\n
+ /// Once you use a keyword, all following arguments require the keyword.
+ ///
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v17 Changed function from **setProperty** to **setContainerProperty**.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.setContainerProperty('Category', 'Newest')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setContainerProperty(...);
+#else
+ SWIGHIDDENVIRTUAL void setContainerProperty(const String &strProperty, const String &strValue);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ setContent(value) }
+ /// Sets the content type of the container.
+ ///
+ /// @param value string or unicode - content value.
+ ///
+ /// __Available content types__
+ /// | Name | Media |
+ /// |:-----------:|:-----------------------------------------|
+ /// | actors | Videos
+ /// | addons | Addons, Music, Pictures, Programs, Videos
+ /// | albums | Music, Videos
+ /// | artists | Music, Videos
+ /// | countries | Music, Videos
+ /// | directors | Videos
+ /// | files | Music, Videos
+ /// | games | Games
+ /// | genres | Music, Videos
+ /// | images | Pictures
+ /// | mixed | Music, Videos
+ /// | movies | Videos
+ /// | Musicvideos | Music, Videos
+ /// | playlists | Music, Videos
+ /// | seasons | Videos
+ /// | sets | Videos
+ /// | songs | Music
+ /// | studios | Music, Videos
+ /// | tags | Music, Videos
+ /// | tvshows | Videos
+ /// | videos | Videos
+ /// | years | Music, Videos
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v18 Added new function.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// self.setContent('movies')
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ setContent(...);
+#else
+ SWIGHIDDENVIRTUAL void setContent(const String &strValue);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcgui_window_xml
+ /// @brief \python_func{ getCurrentContainerId() }
+ /// Get the id of the currently visible container.
+ ///
+ /// ------------------------------------------------------------------------
+ /// @python_v17 Added new function.
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// container_id = self.getCurrentContainerId()
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ getCurrentContainerId(...);
+#else
+ SWIGHIDDENVIRTUAL int getCurrentContainerId();
+#endif
+
+#ifndef SWIG
+ // CGUIWindow
+ bool OnMessage(CGUIMessage& message) override;
+ bool OnAction(const CAction& action) override;
+ SWIGHIDDENVIRTUAL void AllocResources(bool forceLoad = false);
+ SWIGHIDDENVIRTUAL void FreeResources(bool forceUnLoad = false);
+ SWIGHIDDENVIRTUAL bool OnClick(int iItem);
+ SWIGHIDDENVIRTUAL bool OnDoubleClick(int iItem);
+ SWIGHIDDENVIRTUAL void Process(unsigned int currentTime, CDirtyRegionList &dirtyregions);
+
+ bool IsMediaWindow() const override
+ {
+ XBMC_TRACE;
+ return m_isMedia;
+ };
+
+ // This method is identical to the Window::OnDeinitWindow method
+ // except it passes the message on to their respective parents.
+ // Since the respective parent differences are handled by the
+ // interceptor there's no reason to define this one here.
+// SWIGHIDDENVIRTUAL void OnDeinitWindow(int nextWindowID);
+
+
+ protected:
+ // CGUIWindow
+ SWIGHIDDENVIRTUAL bool LoadXML(const String &strPath, const String &strPathLower);
+
+ // CGUIMediaWindow
+ SWIGHIDDENVIRTUAL void GetContextButtons(int itemNumber, CContextButtons &buttons);
+ SWIGHIDDENVIRTUAL bool Update(const String &strPath);
+
+ void SetupShares();
+ String m_scriptPath;
+ String m_mediaDir;
+ bool m_isMedia;
+
+ friend class WindowXMLInterceptor;
+#endif
+ };
+ ///@}
+
+ // Ideally what we want here is a Dialog/Media Window. The problem is that these
+ // are two orthogonal discriminations of CGUIWindow and there wasn't a previous
+ // accounting for this possibility through the use of making CGUIWindow a
+ // virtual base class of the pertinent subclasses. So now we're left with
+ // no good solution.
+ //
+ // <strike>So here we're going to have the 'main' hierarchy (the one visible to SWIG)
+ // go the way intended - through WindowXML, but we're going to borrow dialog
+ // functionality from CGUIDialog by using it as a Mixin.</strike>
+ //
+ // jmarshall says that this class has no reason to inherit from CGUIMediaWindow.
+ // At some point this entire hierarchy needs to be reworked. The XML handling
+ // routines should be put in a mixin.
+ //
+ /// \defgroup python_xbmcgui_window_dialog_xml Subclass - WindowDialogXML
+ /// \ingroup python_xbmcgui_window_xml
+ /// @{
+ /// @brief __GUI xml window dialog__
+ ///
+ /// \python_class{ xbmcgui.WindowXMLDialog(xmlFilename, scriptPath[, defaultSkin, defaultRes]) }
+ ///
+ /// Creates a new xml file based window dialog class.
+ ///
+ /// @param xmlFilename string - the name of the xml file to
+ /// look for.
+ /// @param scriptPath string - path to script. used to
+ /// fallback to if the xml doesn't exist in
+ /// the current skin. (eg \ref python_xbmcaddon_Addon "xbmcaddon.Addon().getAddonInfo('path'))"
+ /// @param defaultSkin [opt] string - name of the folder in the
+ /// skins path to look in for the xml.
+ /// (default='Default')
+ /// @param defaultRes [opt] string - default skins resolution.
+ /// (1080i, 720p, ntsc16x9, ntsc, pal16x9 or pal. default='720p')
+ /// @throws Exception if more then 200 windows are created.
+ ///
+ /// @note Skin folder structure is e.g. **resources/skins/Default/720p**
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// **Example:**
+ /// ~~~~~~~~~~~~~{.py}
+ /// ..
+ /// dialog = xbmcgui.WindowXMLDialog('script-Lyrics-main.xml', xbmcaddon.Addon().getAddonInfo('path'), 'default', '1080i')
+ /// dialog.doModal()
+ /// del dialog
+ /// ..
+ /// ~~~~~~~~~~~~~
+ ///
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ /// On functions defined input variable <b><tt>controlId</tt> (GUI control identifier)</b>
+ /// is the on window.xml defined value behind type added with <tt><b>id="..."</b></tt> and
+ /// used to identify for changes there and on callbacks.
+ ///
+ /// ~~~~~~~~~~~~~{.xml}
+ /// <control type="label" id="31">
+ /// <description>Title Label</description>
+ /// ...
+ /// </control>
+ /// <control type="progress" id="32">
+ /// <description>progress control</description>
+ /// ...
+ /// </control>
+ /// ~~~~~~~~~~~~~
+ ///
+ //
+ class WindowXMLDialog : public WindowXML, private WindowDialogMixin
+ {
+ public:
+ WindowXMLDialog(const String& xmlFilename, const String& scriptPath,
+ const String& defaultSkin = "Default",
+ const String& defaultRes = "720p");
+
+ ~WindowXMLDialog() override;
+
+#ifndef SWIG
+ bool OnMessage(CGUIMessage& message) override;
+ bool IsDialogRunning() const override
+ {
+ XBMC_TRACE;
+ return WindowDialogMixin::IsDialogRunning();
+ }
+ bool IsDialog() const override
+ {
+ XBMC_TRACE;
+ return true;
+ };
+ bool IsModalDialog() const override
+ {
+ XBMC_TRACE;
+ return true;
+ };
+ bool IsMediaWindow() const override
+ {
+ XBMC_TRACE;
+ return false;
+ };
+ bool OnAction(const CAction& action) override;
+ void OnDeinitWindow(int nextWindowID) override;
+
+ bool LoadXML(const String& strPath, const String& strPathLower) override;
+
+ inline void show() override
+ {
+ XBMC_TRACE;
+ WindowDialogMixin::show();
+ }
+ inline void close() override
+ {
+ XBMC_TRACE;
+ WindowDialogMixin::close();
+ }
+
+ friend class DialogJumper;
+#endif
+ };
+ ///@}
+ }
+}
diff --git a/xbmc/interfaces/legacy/aojsonrpc.h b/xbmc/interfaces/legacy/aojsonrpc.h
new file mode 100644
index 0000000..7f1d875
--- /dev/null
+++ b/xbmc/interfaces/legacy/aojsonrpc.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "interfaces/json-rpc/ITransportLayer.h"
+#include "interfaces/json-rpc/JSONRPC.h"
+
+class CVariant;
+
+class CAddOnTransport : public JSONRPC::ITransportLayer
+{
+public:
+ bool PrepareDownload(const char *path, CVariant &details, std::string &protocol) override { return false; }
+ bool Download(const char *path, CVariant& result) override { return false; }
+ int GetCapabilities() override { return JSONRPC::Response; }
+
+ class CAddOnClient : public JSONRPC::IClient
+ {
+ public:
+ int GetPermissionFlags() override { return JSONRPC::OPERATION_PERMISSION_ALL; }
+ int GetAnnouncementFlags() override { return 0; }
+ bool SetAnnouncementFlags(int flags) override { return true; }
+ };
+};
diff --git a/xbmc/interfaces/legacy/swighelper.h b/xbmc/interfaces/legacy/swighelper.h
new file mode 100644
index 0000000..15a822c
--- /dev/null
+++ b/xbmc/interfaces/legacy/swighelper.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/**
+ * SWIGHIDDENVIRTUAL allows the keyword 'virtual' to be there when the main
+ * Addon api is compiled, but be hidden from the SWIG code generator.
+ *
+ * This is to provide finer grain control over which methods are callbackable
+ * (is that a word? ...)
+ * into the scripting language, and which ones are not. True polymorphic
+ * behavior across the scripting language boundary will ONLY occur where
+ * the keyword 'virtual' is used. In other words, you can use the macro
+ * SWIGHIDDENVIRTUAL to 'hide' the polymorphic behavior from the scripting
+ * language using the macro instead.
+ *
+ * Note: You should not hide virtual destructors from the scripting language.
+ */
+#ifdef SWIG
+#define SWIGHIDDENVIRTUAL
+#else
+#define SWIGHIDDENVIRTUAL virtual
+#endif
+
+/**
+ * SWIG_CONSTANT_FROM_GETTER will define a constant in the scripting
+ * language from a getter in the Addon api and also provide the
+ * Addon api declaration. E.g. If you use:
+ *
+ * SWIG_CONSTANT_FROM_GETTER(int, MY_CONSTANT);
+ *
+ * ... in an Addon api header file then you need to define a function:
+ *
+ * int getMy_CONSTANT();
+ *
+ * ... in a .cpp file. That call will be made to determine the value
+ * of the constant in the scripting language.
+ */
+#ifdef SWIG
+#define SWIG_CONSTANT_FROM_GETTER(type,varname) %constant type varname = get##varname ()
+#else
+#define SWIG_CONSTANT_FROM_GETTER(type,varname) type get##varname ()
+#endif
+
+/**
+ * SWIG_CONSTANT defines a constant in SWIG from an already existing
+ * definition in the Addon api. E.g. a #define from the core window
+ * system like SORT_METHOD_PROGRAM_COUNT included in the api via
+ * a #include can be exposed to the scripting language using
+ * SWIG_CONSTANT(int,SORT_METHOD_PROGRAM_COUNT).
+ *
+ * This macro can be used when the constant name and the C++ reference
+ * look the same. When they look different see SWIG_CONSTANT2
+ *
+ * Note, this declaration is invisible to the API C++ code and can
+ * only be seen by the SWIG processor.
+ */
+#ifdef SWIG
+#define SWIG_CONSTANT(type,var) %constant type var = var
+#else
+#define SWIG_CONSTANT(type,var)
+#endif
+
+/**
+ * SWIG_CONSTANT2 defines a constant in SWIG from an already existing
+ * definition in the Addon api. E.g. a #define from the core window
+ * system like SORT_METHOD_VIDEO_YEAR included in the api via
+ * a #include can be exposed to the scripting language using
+ * SWIG_CONSTANT2(int,SORT_METHOD_VIDEO_YEAR,SORT_METHOD_YEAR).
+ *
+ * This macro can be used when the constant name and the C++ reference
+ * don't look the same. When they look the same see SWIG_CONSTANT
+ *
+ * Note, this declaration is invisible to the API C++ code and can
+ * only be seen by the SWIG processor.
+ */
+#ifdef SWIG
+#define SWIG_CONSTANT2(type,var,val) %constant type var = val
+#else
+#define SWIG_CONSTANT2(type,var,val)
+#endif
+
+/**
+* SWIG_IMMUTABLE defines a member as immutable i.e. read-only.
+*
+* Note, this declaration is invisible to the API C++ code and can
+* only be seen by the SWIG processor.
+*/
+#ifdef SWIG
+#define SWIG_IMMUTABLE(var) %feature("immutable"); var; %feature("immutable", "")
+#else
+#define SWIG_IMMUTABLE(var) var
+#endif
+
diff --git a/xbmc/interfaces/legacy/wsgi/CMakeLists.txt b/xbmc/interfaces/legacy/wsgi/CMakeLists.txt
new file mode 100644
index 0000000..cc29eb4
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/CMakeLists.txt
@@ -0,0 +1,13 @@
+if(MICROHTTPD_FOUND)
+ set(SOURCES WsgiErrorStream.cpp
+ WsgiInputStream.cpp
+ WsgiResponseBody.cpp
+ WsgiResponse.cpp)
+
+ set(HEADERS WsgiErrorStream.h
+ WsgiInputStream.h
+ WsgiResponse.h
+ WsgiResponseBody.h)
+
+ core_add_library(legacy_interface_wsgi)
+endif()
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp
new file mode 100644
index 0000000..b8096fe
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015-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 "WsgiErrorStream.h"
+
+#include "network/httprequesthandler/python/HTTPPythonRequest.h"
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiErrorStream::WsgiErrorStream()
+ : m_request(NULL)
+ { }
+
+ WsgiErrorStream::~WsgiErrorStream()
+ {
+ m_request = NULL;
+ }
+
+ void WsgiErrorStream::write(const String& str)
+ {
+ if (str.empty())
+ return;
+
+ String msg = str;
+ // remove a trailing \n
+ if (msg.at(msg.size() - 1) == '\n')
+ msg.erase(msg.size() - 1);
+
+ if (m_request != NULL)
+ CLog::Log(LOGERROR, "WSGI [{}]: {}", m_request->url, msg);
+ else
+ CLog::Log(LOGERROR, "WSGI: {}", msg);
+ }
+
+ void WsgiErrorStream::writelines(const std::vector<String>& seq)
+ {
+ if (seq.empty())
+ return;
+
+ String msg = StringUtils::Join(seq, "");
+ write(msg);
+ }
+
+#ifndef SWIG
+ void WsgiErrorStream::SetRequest(HTTPPythonRequest* request)
+ {
+ if (m_request != NULL)
+ return;
+
+ m_request = request;
+ }
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h
new file mode 100644
index 0000000..e9e7694
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015-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.
+ */
+
+#pragma once
+
+#include "interfaces/legacy/AddonClass.h"
+
+#include <vector>
+
+struct HTTPPythonRequest;
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+
+ /// \defgroup python_xbmcwsgi_WsgiErrorStream WsgiErrorStream
+ /// \ingroup python_xbmcwsgi
+ /// @{
+ /// @brief **Represents the wsgi.errors stream to write error messages.**
+ ///
+ /// \python_class{ WsgiErrorStream() }
+ ///
+ /// This implementation writes the error messages to the application's log
+ /// file.
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ class WsgiErrorStream : public AddonClass
+ {
+ public:
+ WsgiErrorStream();
+ ~WsgiErrorStream() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcwsgi_WsgiErrorStream
+ /// \python_func{ flush() }
+ /// Since nothing is buffered this is a no-op.
+ ///
+ ///
+ flush();
+#else
+ inline void flush() { }
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcwsgi_WsgiErrorStream
+ /// \python_func{ write(str) }
+ /// Writes the given error message to the application's log file.
+ ///
+ /// @param str A string to save in log file
+ ///
+ /// @note A trailing `\n` is removed.
+ ///
+ write(...);
+#else
+ void write(const String& str);
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ ///
+ /// \ingroup python_xbmcwsgi_WsgiErrorStream
+ /// \python_func{ writelines(seq) }
+ /// Joins the given list of error messages (without any separator) into
+ /// a single error message which is written to the application's log file.
+ ///
+ /// @param seq A list of strings which will be logged.
+ ///
+ writelines(...);
+#else
+ void writelines(const std::vector<String>& seq);
+#endif
+
+#ifndef SWIG
+ /**
+ * Sets the given request.
+ */
+ void SetRequest(HTTPPythonRequest* request);
+
+ HTTPPythonRequest* m_request;
+#endif
+ };
+ /// @}
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp
new file mode 100644
index 0000000..5146007
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015-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 "WsgiInputStream.h"
+
+#include "network/httprequesthandler/python/HTTPPythonRequest.h"
+#include "utils/StringUtils.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiInputStreamIterator::WsgiInputStreamIterator()
+ : m_data(),
+ m_line()
+ { }
+
+#ifndef SWIG
+ WsgiInputStreamIterator::WsgiInputStreamIterator(const String& data, bool end /* = false */)
+ : m_data(data),
+ m_remaining(end ? 0 : data.size()),
+ m_line()
+ { }
+#endif
+
+ WsgiInputStreamIterator::~WsgiInputStreamIterator() = default;
+
+ String WsgiInputStreamIterator::read(unsigned long size /* = 0 */) const
+ {
+ // make sure we don't try to read more data than we have
+ if (size <= 0 || size > m_remaining)
+ size = m_remaining;
+
+ // remember the current read offset
+ size_t offset = static_cast<size_t>(m_offset);
+
+ // adjust the read offset and the remaining data length
+ m_offset += size;
+ m_remaining -= size;
+
+ // return the data being requested
+ return m_data.substr(offset, size);
+ }
+
+ String WsgiInputStreamIterator::readline(unsigned long size /* = 0 */) const
+ {
+ // make sure we don't try to read more data than we have
+ if (size <= 0 || size > m_remaining)
+ size = m_remaining;
+
+ size_t offset = static_cast<size_t>(m_offset);
+ size_t pos = m_data.find('\n', offset);
+
+ // make sure pos has a valid value and includes the \n character
+ if (pos == std::string::npos)
+ pos = m_data.size();
+ else
+ pos += 1;
+
+ if (pos - offset < size)
+ size = pos - offset;
+
+ // read the next line
+ String line = read(size);
+
+ // remove any trailing \r\n
+ StringUtils::TrimRight(line, "\r\n");
+
+ return line;
+ }
+
+ std::vector<String> WsgiInputStreamIterator::readlines(unsigned long sizehint /* = 0 */) const
+ {
+ std::vector<String> lines;
+
+ // make sure we don't try to read more data than we have
+ if (sizehint <= 0 || sizehint > m_remaining)
+ sizehint = m_remaining;
+
+ do
+ {
+ // read a full line
+ String line = readline();
+
+ // adjust the sizehint by the number of bytes just read
+ sizehint -= line.length();
+
+ // add it to the list of read lines
+ lines.push_back(line);
+ } while (sizehint > 0);
+
+ return lines;
+ }
+
+#ifndef SWIG
+ WsgiInputStreamIterator& WsgiInputStreamIterator::operator++()
+ {
+ m_line.clear();
+
+ if (!end())
+ {
+ // read the next line
+ m_line = readline();
+ }
+
+ return *this;
+ }
+
+ bool WsgiInputStreamIterator::operator==(const WsgiInputStreamIterator& rhs)
+ {
+ return m_data == rhs.m_data &&
+ m_offset == rhs.m_offset &&
+ m_remaining == rhs.m_remaining;
+ }
+
+ bool WsgiInputStreamIterator::operator!=(const WsgiInputStreamIterator& rhs)
+ {
+ return !(*this == rhs);
+ }
+
+ String& WsgiInputStreamIterator::operator*()
+ {
+ return m_line;
+ }
+#endif
+
+ WsgiInputStream::WsgiInputStream()
+ : m_request(NULL)
+ { }
+
+ WsgiInputStream::~WsgiInputStream()
+ {
+ m_request = NULL;
+ }
+
+#ifndef SWIG
+ WsgiInputStreamIterator* WsgiInputStream::begin()
+ {
+ return new WsgiInputStreamIterator(m_data, false);
+ }
+
+ WsgiInputStreamIterator* WsgiInputStream::end()
+ {
+ return new WsgiInputStreamIterator(m_data, true);
+ }
+
+ void WsgiInputStream::SetRequest(HTTPPythonRequest* request)
+ {
+ if (m_request != NULL)
+ return;
+
+ m_request = request;
+
+ // set the remaining bytes to be read
+ m_data = m_request->requestContent;
+ m_offset = 0;
+ m_remaining = m_data.size();
+ }
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiInputStream.h b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.h
new file mode 100644
index 0000000..d7bf73f
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015-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.
+ */
+
+#pragma once
+
+#include "interfaces/legacy/AddonClass.h"
+
+#include <vector>
+
+struct HTTPPythonRequest;
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+
+ // Iterator for the wsgi.input stream.
+ class WsgiInputStreamIterator : public AddonClass
+ {
+ public:
+ WsgiInputStreamIterator();
+ ~WsgiInputStreamIterator() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcwsgi_WsgiInputStream
+ /// \python_func{ read([size]) }
+ ///
+ /// Read a maximum of `<size>` bytes from the wsgi.input stream.
+ ///
+ /// @param size [opt] bytes to read
+ /// @return Returns the readed string
+ ///
+ read(...);
+#else
+ String read(unsigned long size = 0) const;
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcwsgi_WsgiInputStream
+ /// \python_func{ readline([size]) }
+ ///
+ /// Read a full line up to a maximum of `<size>` bytes from the wsgi.input
+ /// stream.
+ ///
+ /// @param size [opt] bytes to read
+ /// @return Returns the readed string line
+ ///
+ read(...);
+#else
+ String readline(unsigned long size = 0) const;
+#endif
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcwsgi_WsgiInputStream
+ /// \python_func{ readlines([sizehint]) }
+ ///
+ /// Read multiple full lines up to at least `<sizehint>` bytes from the
+ /// wsgi.input stream and return them as a list.
+ ///
+ /// @param sizehint [opt] bytes to read
+ /// @return Returns a list readed string lines
+ ///
+ read(...);
+#else
+ std::vector<String> readlines(unsigned long sizehint = 0) const;
+#endif
+
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ WsgiInputStreamIterator(const String& data, bool end = false);
+
+ WsgiInputStreamIterator& operator++();
+ bool operator==(const WsgiInputStreamIterator& rhs);
+ bool operator!=(const WsgiInputStreamIterator& rhs);
+ String& operator*();
+ inline bool end() const { return m_remaining <= 0; }
+
+ protected:
+ String m_data;
+ mutable unsigned long m_offset = 0;
+ mutable unsigned long m_remaining = 0;
+
+ private:
+ String m_line;
+#endif
+ };
+
+ /// \defgroup python_xbmcwsgi_WsgiInputStream WsgiInputStream
+ /// \ingroup python_xbmcwsgi
+ /// @{
+ /// @brief **Represents the wsgi.input stream to access data from a HTTP request.**
+ ///
+ /// \python_class{ WsgiInputStream() }
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ class WsgiInputStream : public WsgiInputStreamIterator
+ {
+ public:
+ WsgiInputStream();
+ ~WsgiInputStream() override;
+
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ WsgiInputStreamIterator* begin();
+ WsgiInputStreamIterator* end();
+
+ /**
+ * Sets the given request.
+ */
+ void SetRequest(HTTPPythonRequest* request);
+
+ HTTPPythonRequest* m_request;
+#endif
+ };
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp b/xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp
new file mode 100644
index 0000000..175e83d
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015-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 "WsgiResponse.h"
+
+#include "utils/StringUtils.h"
+#include "utils/log.h"
+
+#include <inttypes.h>
+#include <utility>
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiResponse::WsgiResponse()
+ : m_responseHeaders(),
+ m_body()
+ { }
+
+ WsgiResponse::~WsgiResponse() = default;
+
+ WsgiResponseBody* WsgiResponse::operator()(const String& status, const std::vector<WsgiHttpHeader>& response_headers, void* exc_info /* = NULL */)
+ {
+ if (m_called)
+ {
+ CLog::Log(LOGWARNING, "WsgiResponse: callable has already been called");
+ return NULL;
+ }
+
+ m_called = true;
+
+ // parse the status
+ if (!status.empty())
+ {
+ std::vector<String> statusParts = StringUtils::Split(status, ' ', 2);
+ if (statusParts.size() == 2 && StringUtils::IsNaturalNumber(statusParts.front()))
+ {
+ int64_t parsedStatus = strtol(statusParts.front().c_str(), NULL, 0);
+ if (parsedStatus >= MHD_HTTP_OK && parsedStatus <= MHD_HTTP_NOT_EXTENDED)
+ m_status = static_cast<int>(parsedStatus);
+ else
+ CLog::Log(LOGWARNING, "WsgiResponse: invalid status number {} in \"{}\" provided",
+ parsedStatus, status);
+ }
+ else
+ CLog::Log(LOGWARNING, "WsgiResponse: invalid status \"{}\" provided", status);
+ }
+ else
+ CLog::Log(LOGWARNING, "WsgiResponse: empty status provided");
+
+ // copy the response headers
+ for (const auto& headerIt : response_headers)
+ m_responseHeaders.insert({headerIt.first(), headerIt.second()});
+
+ return &m_body;
+ }
+
+#ifndef SWIG
+ void WsgiResponse::Append(const std::string& data)
+ {
+ if (!data.empty())
+ m_body.m_data.append(data);
+ }
+
+ bool WsgiResponse::Finalize(HTTPPythonRequest* request) const
+ {
+ if (request == NULL || !m_called)
+ return false;
+
+ // copy the response status
+ request->responseStatus = m_status;
+
+ // copy the response headers
+ if (m_status >= MHD_HTTP_OK && m_status < MHD_HTTP_BAD_REQUEST)
+ request->responseHeaders.insert(m_responseHeaders.begin(), m_responseHeaders.end());
+ else
+ request->responseHeadersError.insert(m_responseHeaders.begin(), m_responseHeaders.end());
+
+ // copy the body
+ request->responseData = m_body.m_data;
+
+ return true;
+ }
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponse.h b/xbmc/interfaces/legacy/wsgi/WsgiResponse.h
new file mode 100644
index 0000000..412e520
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponse.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015-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.
+ */
+
+#pragma once
+
+#include "interfaces/legacy/AddonClass.h"
+#include "interfaces/legacy/Tuple.h"
+#include "interfaces/legacy/wsgi/WsgiResponseBody.h"
+#include "network/httprequesthandler/python/HTTPPythonRequest.h"
+
+#include <vector>
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ typedef Tuple<String, String> WsgiHttpHeader;
+
+ /// \defgroup python_xbmcwsgi_WsgiResponse WsgiResponse
+ /// \ingroup python_xbmcwsgi
+ /// @{
+ /// @brief **Represents the start_response callable passed to a WSGI handler.**
+ ///
+ /// \python_class{ WsgiResponse() }
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ class WsgiResponse : public AddonClass
+ {
+ public:
+ WsgiResponse();
+ ~WsgiResponse() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcwsgi_WsgiInputStreamIterator
+ /// \python_func{ operator(status, response_headers[, exc_info]) }
+ ///
+ /// Callable implementation to initialize the response with the given
+ /// HTTP status and the HTTP response headers.
+ ///
+ /// @param status an HTTP status string like 200 OK or 404
+ /// Not Found.
+ /// @param response_headers a list of (header_name, header_value)
+ /// tuples. It must be a Python list. Each
+ /// header_name must be a valid HTTP header
+ /// field-name (as
+ /// @param exc_info [optional] python sys.exc_info() tuple.
+ /// This argument should be supplied by the
+ /// application only if start_response is
+ /// being called by an error
+ /// @return The write() method \ref python_xbmcwsgi_WsgiResponseBody "WsgiResponseBody"
+ ///
+ operator(...);
+#else
+ WsgiResponseBody* operator()(const String& status, const std::vector<WsgiHttpHeader>& response_headers, void* exc_info = NULL);
+#endif
+
+#ifndef SWIG
+ void Append(const std::string& data);
+
+ bool Finalize(HTTPPythonRequest* request) const;
+
+ private:
+ bool m_called = false;
+ int m_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
+ std::multimap<std::string, std::string> m_responseHeaders;
+
+ WsgiResponseBody m_body;
+#endif
+ };
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp
new file mode 100644
index 0000000..2e84319
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015-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 "WsgiResponseBody.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiResponseBody::WsgiResponseBody()
+ : m_data()
+ { }
+
+ WsgiResponseBody::~WsgiResponseBody() = default;
+
+ void WsgiResponseBody::operator()(const String& data)
+ {
+ if (data.empty())
+ return;
+
+ m_data.append(data);
+ }
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h
new file mode 100644
index 0000000..4f18583
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015-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.
+ */
+
+#pragma once
+
+#include "interfaces/legacy/AddonClass.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ /// \defgroup python_xbmcwsgi_WsgiResponseBody WsgiResponseBody
+ /// \ingroup python_xbmcwsgi
+ /// @{
+ /// @brief **Represents the write callable returned by the start_response callable passed to a WSGI handler.**
+ ///
+ /// \python_class{ WsgiResponseBody() }
+ ///
+ ///-------------------------------------------------------------------------
+ ///
+ class WsgiResponseBody : public AddonClass
+ {
+ public:
+ WsgiResponseBody();
+ ~WsgiResponseBody() override;
+
+#ifdef DOXYGEN_SHOULD_USE_THIS
+ /// \ingroup python_xbmcwsgi_WsgiInputStreamIterator
+ /// \python_func{ operator(status, response_headers[, exc_info]) }
+ ///
+ /// Callable implementation to write data to the response.
+ ///
+ /// @param data string data to write
+ ///
+ operator()(...);
+#else
+ void operator()(const String& data);
+#endif
+
+#if !defined SWIG && !defined DOXYGEN_SHOULD_SKIP_THIS
+ String m_data;
+#endif
+ };
+ }
+}