aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/addons/Addon.cpp13
-rw-r--r--xbmc/addons/Addon.h2
-rw-r--r--xbmc/addons/AddonBuilder.cpp87
-rw-r--r--xbmc/addons/AddonBuilder.h2
-rw-r--r--xbmc/addons/AddonDatabase.cpp85
-rw-r--r--xbmc/addons/AddonDatabase.h1
-rw-r--r--xbmc/addons/AddonManager.cpp289
-rw-r--r--xbmc/addons/AddonManager.h7
-rw-r--r--xbmc/addons/ContextMenuAddon.cpp76
-rw-r--r--xbmc/addons/ContextMenuAddon.h3
-rw-r--r--xbmc/addons/ImageResource.cpp6
-rw-r--r--xbmc/addons/ImageResource.h2
-rw-r--r--xbmc/addons/LanguageResource.cpp60
-rw-r--r--xbmc/addons/LanguageResource.h2
-rw-r--r--xbmc/addons/PluginSource.cpp32
-rw-r--r--xbmc/addons/Repository.cpp71
-rw-r--r--xbmc/addons/Repository.h3
-rw-r--r--xbmc/addons/Scraper.cpp30
-rw-r--r--xbmc/addons/Skin.cpp37
-rw-r--r--xbmc/addons/Skin.h3
-rw-r--r--xbmc/addons/Webinterface.cpp18
-rw-r--r--xbmc/addons/Webinterface.h5
-rw-r--r--xbmc/games/addons/GameClient.cpp34
23 files changed, 654 insertions, 214 deletions
diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp
index c5720d03bf..354b44643b 100644
--- a/xbmc/addons/Addon.cpp
+++ b/xbmc/addons/Addon.cpp
@@ -356,9 +356,16 @@ CAddonSettings* CAddon::GetSettings() const
std::string CAddon::LibPath() const
{
- if (m_addonInfo->LibName().empty())
- return "";
- return URIUtils::AddFileToFolder(m_addonInfo->Path(), m_addonInfo->LibName());
+ // Get library related to given type on construction
+ std::string libName = m_addonInfo->Type(m_type)->LibName();
+ if (libName.empty())
+ {
+ // If not present fallback to master library
+ libName = m_addonInfo->LibName();
+ if (libName.empty())
+ return "";
+ }
+ return URIUtils::AddFileToFolder(m_addonInfo->Path(), libName);
}
AddonVersion CAddon::GetDependencyVersion(const std::string &dependencyID) const
diff --git a/xbmc/addons/Addon.h b/xbmc/addons/Addon.h
index 0c3a6688b4..6cf38a91a9 100644
--- a/xbmc/addons/Addon.h
+++ b/xbmc/addons/Addon.h
@@ -39,6 +39,8 @@ public:
TYPE Type() const override { return m_addonInfo->MainType(); }
TYPE FullType() const override { return Type(); }
bool IsType(TYPE type) const override { return type == m_addonInfo->MainType(); }
+ const CAddonType* Type(TYPE type) const { return m_addonInfo->Type(type); }
+
std::string ID() const override{ return m_addonInfo->ID(); }
std::string Name() const override { return m_addonInfo->Name(); }
bool IsInUse() const override{ return false; };
diff --git a/xbmc/addons/AddonBuilder.cpp b/xbmc/addons/AddonBuilder.cpp
index e1bbbcf564..a2cae49c95 100644
--- a/xbmc/addons/AddonBuilder.cpp
+++ b/xbmc/addons/AddonBuilder.cpp
@@ -31,6 +31,93 @@ using namespace KODI;
namespace ADDON
{
+AddonPtr CAddonBuilder::Generate(const AddonInfoPtr& info, TYPE type)
+{
+ if (!info || info->ID().empty())
+ return AddonPtr();
+
+ if (type == ADDON_UNKNOWN)
+ type = info->MainType();
+ if (type == ADDON_UNKNOWN)
+ return std::make_shared<CAddon>(info, ADDON_UNKNOWN);
+
+ // Handle screensaver special cases
+ if (type == ADDON_SCREENSAVER)
+ {
+ // built in screensaver or python screensaver
+ if (StringUtils::StartsWithNoCase(info->ID(), "screensaver.xbmc.builtin.") ||
+ URIUtils::HasExtension(info->LibName(), ".py"))
+ return std::make_shared<CAddon>(info, type);
+ }
+
+ // Handle audio encoder special cases
+ if (type == ADDON_AUDIOENCODER)
+ {
+ // built in audio encoder
+ if (StringUtils::StartsWithNoCase(info->ID(), "audioencoder.kodi.builtin."))
+ return std::make_shared<CAddonDll>(info, type);
+ }
+
+ switch (type)
+ {
+ case ADDON_AUDIODECODER:
+ case ADDON_AUDIOENCODER:
+ case ADDON_IMAGEDECODER:
+ case ADDON_INPUTSTREAM:
+ case ADDON_PERIPHERALDLL:
+ case ADDON_VFS:
+ case ADDON_VIZ:
+ case ADDON_SCREENSAVER:
+ return std::make_shared<CAddonDll>(info, type);
+ case ADDON_PVRDLL:
+ return std::make_shared<PVR::CPVRClient>(info);
+ case ADDON_GAMEDLL:
+ return std::make_shared<GAME::CGameClient>(info);
+ case ADDON_PLUGIN:
+ case ADDON_SCRIPT:
+ return std::make_shared<CPluginSource>(info, type);
+ case ADDON_SCRIPT_LIBRARY:
+ case ADDON_SCRIPT_LYRICS:
+ case ADDON_SCRIPT_MODULE:
+ case ADDON_SUBTITLE_MODULE:
+ case ADDON_SCRIPT_WEATHER:
+ return std::make_shared<CAddon>(info, type);
+ case ADDON_WEB_INTERFACE:
+ return std::make_shared<CWebinterface>(info);
+ case ADDON_SERVICE:
+ return std::make_shared<CService>(info);
+ case ADDON_SCRAPER_ALBUMS:
+ case ADDON_SCRAPER_ARTISTS:
+ case ADDON_SCRAPER_MOVIES:
+ case ADDON_SCRAPER_MUSICVIDEOS:
+ case ADDON_SCRAPER_TVSHOWS:
+ case ADDON_SCRAPER_LIBRARY:
+ return std::make_shared<CScraper>(info, type);
+ case ADDON_SKIN:
+ return std::make_shared<CSkinInfo>(info);
+ case ADDON_RESOURCE_FONT:
+ return std::make_shared<CFontResource>(info);
+ case ADDON_RESOURCE_IMAGES:
+ return std::make_shared<CImageResource>(info);
+ case ADDON_RESOURCE_GAMES:
+ return std::make_shared<CGameResource>(info);
+ case ADDON_RESOURCE_LANGUAGE:
+ return std::make_shared<CLanguageResource>(info);
+ case ADDON_RESOURCE_UISOUNDS:
+ return std::make_shared<CUISoundsResource>(info);
+ case ADDON_REPOSITORY:
+ return std::make_shared<CRepository>(info);
+ case ADDON_CONTEXT_ITEM:
+ return std::make_shared<CContextMenuAddon>(info);
+ case ADDON_GAME_CONTROLLER:
+ return std::make_shared<GAME::CController>(info);
+ default:
+ break;
+ }
+ return AddonPtr();
+}
+
+
std::shared_ptr<IAddon> CAddonBuilder::Build()
{
if (m_built)
diff --git a/xbmc/addons/AddonBuilder.h b/xbmc/addons/AddonBuilder.h
index c362501f10..f70107d3fd 100644
--- a/xbmc/addons/AddonBuilder.h
+++ b/xbmc/addons/AddonBuilder.h
@@ -17,6 +17,8 @@ namespace ADDON
class CAddonBuilder
{
public:
+ static AddonPtr Generate(const AddonInfoPtr& info, TYPE type);
+
std::shared_ptr<IAddon> Build();
void SetId(std::string id) { m_addonInfo->m_id = std::move(id); }
void SetName(std::string name) { m_addonInfo->m_name = std::move(name); }
diff --git a/xbmc/addons/AddonDatabase.cpp b/xbmc/addons/AddonDatabase.cpp
index 846d756ba1..ec0aec52db 100644
--- a/xbmc/addons/AddonDatabase.cpp
+++ b/xbmc/addons/AddonDatabase.cpp
@@ -11,6 +11,7 @@
#include "XBDateTime.h"
#include "addons/AddonBuilder.h"
#include "addons/AddonManager.h"
+#include "addons/addoninfo/AddonInfoBuilder.h"
#include "dbwrappers/dataset.h"
#include "filesystem/SpecialProtocol.h"
#include "utils/JSONVariantParser.h"
@@ -115,6 +116,50 @@ static void DeserializeMetadata(const std::string& document, CAddonBuilder& buil
builder.SetExtrainfo(std::move(extraInfo));
}
+static void DeserializeMetadata(const std::string& document, CAddonInfoBuilder::CFromDB& builder)
+{
+ CVariant variant;
+ if (!CJSONVariantParser::Parse(document, variant))
+ return;
+
+ builder.SetAuthor(variant["author"].asString());
+ builder.SetDisclaimer(variant["disclaimer"].asString());
+ builder.SetBroken(variant["broken"].asString());
+ builder.SetPackageSize(variant["size"].asUnsignedInteger());
+
+ builder.SetPath(variant["path"].asString());
+ builder.SetIcon(variant["icon"].asString());
+
+ std::map<std::string, std::string> art;
+ for (auto it = variant["art"].begin_map(); it != variant["art"].end_map(); ++it)
+ art.emplace(it->first, it->second.asString());
+ builder.SetArt(std::move(art));
+
+ std::vector<std::string> screenshots;
+ for (auto it = variant["screenshots"].begin_array(); it != variant["screenshots"].end_array(); ++it)
+ screenshots.push_back(it->asString());
+ builder.SetScreenshots(std::move(screenshots));
+
+ builder.SetType(CAddonInfo::TranslateType(variant["extensions"][0].asString()));
+
+ {
+ std::vector<DependencyInfo> deps;
+ for (auto it = variant["dependencies"].begin_array(); it != variant["dependencies"].end_array(); ++it)
+ {
+ deps.emplace_back(
+ (*it)["addonId"].asString(),
+ AddonVersion((*it)["version"].asString()),
+ (*it)["optional"].asBoolean());
+ }
+ builder.SetDependencies(std::move(deps));
+ }
+
+ InfoMap extraInfo;
+ for (auto it = variant["extrainfo"].begin_array(); it != variant["extrainfo"].end_array(); ++it)
+ extraInfo.emplace((*it)["key"].asString(), (*it)["value"].asString());
+ builder.SetExtrainfo(std::move(extraInfo));
+}
+
CAddonDatabase::CAddonDatabase() = default;
CAddonDatabase::~CAddonDatabase() = default;
@@ -506,7 +551,7 @@ bool CAddonDatabase::FindByAddonId(const std::string& addonId, ADDON::VECADDONS&
m_pDS->query(sql.c_str());
while (!m_pDS->eof())
{
- CAddonBuilder builder;
+ CAddonInfoBuilder::CFromDB builder;
builder.SetId(addonId);
builder.SetVersion(AddonVersion(m_pDS->fv(0).get_asString()));
builder.SetName(m_pDS->fv(1).get_asString());
@@ -516,7 +561,7 @@ bool CAddonDatabase::FindByAddonId(const std::string& addonId, ADDON::VECADDONS&
builder.SetChangelog(m_pDS->fv(5).get_asString());
builder.SetOrigin(m_pDS->fv(6).get_asString());
- auto addon = builder.Build();
+ auto addon = CAddonBuilder::Generate(builder.get(), ADDON_UNKNOWN);
if (addon)
addons.push_back(std::move(addon));
else
@@ -653,15 +698,17 @@ bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
if (m_pDS2->eof())
return false;
- CAddonBuilder builder;
+ CAddonInfoBuilder::CFromDB builder;
builder.SetId(m_pDS2->fv("addonID").get_asString());
builder.SetVersion(AddonVersion(m_pDS2->fv("version").get_asString()));
builder.SetName(m_pDS2->fv("name").get_asString());
builder.SetSummary(m_pDS2->fv("summary").get_asString());
builder.SetDescription(m_pDS2->fv("description").get_asString());
DeserializeMetadata(m_pDS2->fv("metadata").get_asString(), builder);
- addon = builder.Build();
+
+ addon = CAddonBuilder::Generate(builder.get(), ADDON_UNKNOWN);
return addon != nullptr;
+
}
catch (...)
{
@@ -740,7 +787,7 @@ bool CAddonDatabase::GetRepositoryContent(const std::string& id, VECADDONS& addo
continue;
}
- CAddonBuilder builder;
+ CAddonInfoBuilder::CFromDB builder;
builder.SetId(addonId);
builder.SetVersion(version);
builder.SetName(m_pDS->fv("name").get_asString());
@@ -748,7 +795,7 @@ bool CAddonDatabase::GetRepositoryContent(const std::string& id, VECADDONS& addo
builder.SetDescription(m_pDS->fv("description").get_asString());
DeserializeMetadata(m_pDS->fv("metadata").get_asString(), builder);
- auto addon = builder.Build();
+ auto addon = CAddonBuilder::Generate(builder.get(), ADDON_UNKNOWN);
if (addon)
{
if (!result.empty() && result.back()->ID() == addonId)
@@ -1144,3 +1191,29 @@ void CAddonDatabase::OnPostUnInstall(const std::string& addonId)
CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonId.c_str());
}
}
+
+void CAddonDatabase::GetInstallData(const AddonInfoPtr& addon)
+{
+ try
+ {
+ if (nullptr == m_pDB.get())
+ return;
+ if (nullptr == m_pDS.get())
+ return;
+
+ m_pDS->query(PrepareSQL("SELECT * FROM installed WHERE addonID='%s'", addon->ID().c_str()));
+ if (!m_pDS->eof())
+ {
+ CAddonInfoBuilder::SetInstallData(addon,
+ CDateTime::FromDBDateTime(m_pDS->fv(3).get_asString()),
+ CDateTime::FromDBDateTime(m_pDS->fv(4).get_asString()),
+ CDateTime::FromDBDateTime(m_pDS->fv(5).get_asString()),
+ m_pDS->fv(6).get_asString());
+ }
+ m_pDS->close();
+ }
+ catch (...)
+ {
+ CLog::Log(LOGERROR, "CAddonDatabase::{}: failed", __FUNCTION__);
+ }
+}
diff --git a/xbmc/addons/AddonDatabase.h b/xbmc/addons/AddonDatabase.h
index 1651b58d2d..95d9da7e35 100644
--- a/xbmc/addons/AddonDatabase.h
+++ b/xbmc/addons/AddonDatabase.h
@@ -138,6 +138,7 @@ public:
bool SetOrigin(const std::string& addonId, const std::string& origin);
bool SetLastUsed(const std::string& addonId, const CDateTime& dateTime);
+ void GetInstallData(const ADDON::AddonInfoPtr& addon);
protected:
void CreateTables() override;
diff --git a/xbmc/addons/AddonManager.cpp b/xbmc/addons/AddonManager.cpp
index 997c12a3ac..924c883091 100644
--- a/xbmc/addons/AddonManager.cpp
+++ b/xbmc/addons/AddonManager.cpp
@@ -10,9 +10,11 @@
#include "LangInfo.h"
#include "ServiceBroker.h"
+#include "addons/addoninfo/AddonInfoBuilder.h"
#include "events/AddonManagementEvent.h"
#include "events/EventLog.h"
#include "events/NotificationEvent.h"
+#include "filesystem/Directory.h"
#include "filesystem/File.h"
#include "filesystem/SpecialProtocol.h"
#include "utils/StringUtils.h"
@@ -361,8 +363,8 @@ bool CAddonMgr::Init()
return false;
}
- if (!m_database.Open())
- CLog::Log(LOGFATAL, "ADDONS: Failed to open database");
+ if (!m_database.Open())
+ CLog::Log(LOGFATAL, "ADDONS: Failed to open database");
FindAddons();
@@ -561,16 +563,11 @@ bool CAddonMgr::FindInstallableById(const std::string& addonId, AddonPtr& result
bool CAddonMgr::GetInstalledBinaryAddons(BINARY_ADDON_LIST& binaryAddonList)
{
CSingleLock lock(m_critSection);
- if (!m_cp_context)
- return false;
- std::vector<CAddonBuilder> builders;
- m_database.GetInstalled(builders);
-
- for (auto builder : builders)
+ for (auto addon : m_installedAddons)
{
BINARY_ADDON_LIST_ENTRY binaryAddon;
- if (GetInstalledBinaryAddon(builder.GetId(), binaryAddon))
+ if (GetInstalledBinaryAddon(addon.first, binaryAddon))
binaryAddonList.push_back(std::move(binaryAddon));
}
@@ -580,28 +577,14 @@ bool CAddonMgr::GetInstalledBinaryAddons(BINARY_ADDON_LIST& binaryAddonList)
bool CAddonMgr::GetInstalledBinaryAddon(const std::string& addonId, BINARY_ADDON_LIST_ENTRY& binaryAddon)
{
bool ret = false;
- cp_status_t status;
CSingleLock lock(m_critSection);
- cp_plugin_info_t *cp_addon = cp_get_plugin_info(m_cp_context, addonId.c_str(), &status);
- if (status == CP_OK && cp_addon)
+ AddonInfoPtr addon = GetAddonInfo(addonId);
+ if (addon)
{
- cp_extension_t* props = GetFirstExtPoint(cp_addon, ADDON_UNKNOWN);
- if (props != nullptr)
- {
- CAddonBuilder builder;
- std::string value = GetPlatformLibraryName(props->plugin->extensions->configuration);
- if (!value.empty() &&
- props->plugin->plugin_path &&
- strcmp(props->plugin->plugin_path, "") != 0 &&
- Factory(cp_addon, ADDON_UNKNOWN, builder, true))
- {
- binaryAddon = BINARY_ADDON_LIST_ENTRY(!IsAddonDisabled(cp_addon->identifier), std::move(builder.GetAddonInfo()));
- ret = true;
- }
- }
- cp_release_info(m_cp_context, cp_addon);
+ binaryAddon = BINARY_ADDON_LIST_ENTRY(!IsAddonDisabled(addonId), addon);
+ ret = true;
}
return ret;
@@ -610,46 +593,28 @@ bool CAddonMgr::GetInstalledBinaryAddon(const std::string& addonId, BINARY_ADDON
bool CAddonMgr::GetAddonsInternal(const TYPE &type, VECADDONS &addons, bool enabledOnly)
{
CSingleLock lock(m_critSection);
- if (!m_cp_context)
- return false;
- std::vector<CAddonBuilder> builders;
- m_database.GetInstalled(builders);
-
- for (auto& builder : builders)
+ for (const auto& addonInfo : m_installedAddons)
{
- cp_status_t status;
- cp_plugin_info_t* cp_addon = cp_get_plugin_info(m_cp_context, builder.GetId().c_str(), &status);
- if (status == CP_OK && cp_addon)
- {
- if (enabledOnly && IsAddonDisabled(cp_addon->identifier))
- {
- cp_release_info(m_cp_context, cp_addon);
- continue;
- }
+ if (type != ADDON_UNKNOWN && !addonInfo.second->IsType(type))
+ continue;
- //FIXME: hack for skipping special dependency addons (xbmc.python etc.).
- //Will break if any extension point is added to them
- cp_extension_t *props = GetFirstExtPoint(cp_addon, type);
- if (props == nullptr)
- {
- cp_release_info(m_cp_context, cp_addon);
- continue;
- }
+ if (enabledOnly && IsAddonDisabled(addonInfo.second->ID()))
+ continue;
- AddonPtr addon;
- if (Factory(cp_addon, type, builder))
- addon = builder.Build();
- cp_release_info(m_cp_context, cp_addon);
+ //FIXME: hack for skipping special dependency addons (xbmc.python etc.).
+ //Will break if any extension point is added to them
+ if (addonInfo.second->MainType() == ADDON_UNKNOWN)
+ continue;
- if (addon)
- {
- // if the addon has a running instance, grab that
- AddonPtr runningAddon = addon->GetRunningInstance();
- if (runningAddon)
- addon = runningAddon;
- addons.emplace_back(std::move(addon));
- }
+ AddonPtr addon = CAddonBuilder::Generate(addonInfo.second, type);
+ if (addon)
+ {
+ // if the addon has a running instance, grab that
+ AddonPtr runningAddon = addon->GetRunningInstance();
+ if (runningAddon)
+ addon = runningAddon;
+ addons.emplace_back(std::move(addon));
}
}
return addons.size() > 0;
@@ -659,16 +624,13 @@ bool CAddonMgr::GetAddon(const std::string &str, AddonPtr &addon, const TYPE &ty
{
CSingleLock lock(m_critSection);
- cp_status_t status;
- cp_plugin_info_t *cpaddon = cp_get_plugin_info(m_cp_context, str.c_str(), &status);
- if (status == CP_OK && cpaddon)
+ AddonInfoPtr addonInfo = GetAddonInfo(str, type);
+ if (addonInfo)
{
- addon = Factory(cpaddon, type);
- cp_release_info(m_cp_context, cpaddon);
-
+ addon = CAddonBuilder::Generate(addonInfo, type);
if (addon)
{
- if (enabledOnly && IsAddonDisabled(addon->ID()))
+ if (enabledOnly && IsAddonDisabled(addonInfo->ID()))
return false;
// if the addon has a running instance, grab that
@@ -678,8 +640,6 @@ bool CAddonMgr::GetAddon(const std::string &str, AddonPtr &addon, const TYPE &ty
}
return NULL != addon.get();
}
- if (cpaddon)
- cp_release_info(m_cp_context, cpaddon);
return false;
}
@@ -692,47 +652,42 @@ bool CAddonMgr::HasType(const std::string &id, const TYPE &type)
bool CAddonMgr::FindAddons()
{
- bool result = false;
+ ADDON_INFO_LIST installedAddons;
+
+ FindAddons(installedAddons, "special://xbmcbin/addons");
+ FindAddons(installedAddons, "special://xbmc/addons");
+ FindAddons(installedAddons, "special://home/addons");
+
+ std::set<std::string> installed;
+ for (const auto& addon : installedAddons)
+ installed.insert(addon.second->ID());
+
CSingleLock lock(m_critSection);
- if (m_cp_context)
+
+ // Sync with db
+ m_database.SyncInstalled(installed, m_systemAddons, m_optionalAddons);
+ for (const auto& addon : installedAddons)
{
- result = true;
- cp_scan_plugins(m_cp_context, CP_SP_UPGRADE);
+ m_database.GetInstallData(addon.second);
+ CLog::Log(LOGNOTICE, "CAddonMgr::{}: {} v{} installed", __FUNCTION__, addon.second->ID(), addon.second->Version().asString());
+ }
- //Sync with db
- {
- std::set<std::pair<std::string, std::string>> installed;
- cp_status_t status;
- int n;
- cp_plugin_info_t** cp_addons = cp_get_plugins_info(m_cp_context, &status, &n);
- for (int i = 0; i < n; ++i)
- {
- installed.emplace(cp_addons[i]->identifier, cp_addons[i]->version ? cp_addons[i]->version : "");
- }
- cp_release_info(m_cp_context, cp_addons);
- // Log separately so list is sorted
- for (const auto& installedAddon : installed)
- {
- CLog::Log(LOGNOTICE, "ADDON: {} v{} installed", installedAddon.first, installedAddon.second);
- }
+ m_installedAddons = std::move(installedAddons);
- std::set<std::string> installedIdentifiers;
- std::transform(
- installed.cbegin(), installed.cend(),
- std::inserter(installedIdentifiers, installedIdentifiers.begin()),
- [](const decltype(installed)::value_type& p) { return p.first; }
- );
- m_database.SyncInstalled(installedIdentifiers, m_systemAddons, m_optionalAddons);
- }
+ // Reload caches
+ std::set<std::string> tmp;
+ m_database.GetDisabled(tmp);
+ m_disabled = std::move(tmp);
- // Reload caches
- std::set<std::string> tmp;
- m_database.GetDisabled(tmp);
- m_disabled = std::move(tmp);
+ tmp.clear();
+ m_database.GetBlacklisted(tmp);
+ m_updateBlacklist = std::move(tmp);
- tmp.clear();
- m_database.GetBlacklisted(tmp);
- m_updateBlacklist = std::move(tmp);
+ bool result = false;
+ if (m_cp_context)
+ {
+ result = true;
+ cp_scan_plugins(m_cp_context, CP_SP_UPGRADE);
}
return result;
@@ -745,6 +700,8 @@ bool CAddonMgr::UnloadAddon(const std::string& addonId)
if (!IsAddonInstalled(addonId))
return true;
+ m_installedAddons.erase(addonId);
+
if (m_cp_context)
{
if (cp_uninstall_plugin(m_cp_context, addonId.c_str()) == CP_OK)
@@ -838,6 +795,9 @@ void CAddonMgr::UpdateLastUsed(const std::string& id)
{
CSingleLock lock(m_critSection);
m_database.SetLastUsed(id, time);
+ auto addonInfo = GetAddonInfo(id);
+ if (addonInfo)
+ addonInfo->SetLastUsed(time);
}
m_events.Publish(AddonEvents::MetadataChanged(id));
});
@@ -1188,38 +1148,10 @@ std::string CAddonMgr::GetPlatformLibraryName(cp_cfg_element_t *base) const
bool CAddonMgr::LoadAddonDescription(const std::string &directory, AddonPtr &addon)
{
- auto addonXmlPath = CSpecialProtocol::TranslatePath(URIUtils::AddFileToFolder(directory, "addon.xml"));
-
- XFILE::CFile file;
- XFILE::auto_buffer buffer;
- if (file.LoadFile(addonXmlPath, buffer) <= 0)
- {
- CLog::Log(LOGERROR, "Failed to read '%s'", addonXmlPath.c_str());
- return false;
- }
-
- cp_status_t status;
- cp_context_t* context = cp_create_context(&status);
- if (!context)
- return false;
-
- auto info = cp_load_plugin_descriptor_from_memory(context, buffer.get(), buffer.size(), &status);
- if (info)
- {
- // Correct the path. load_plugin_descriptor_from_memory sets it to 'memory'
- info->plugin_path = static_cast<char*>(malloc(directory.length() + 1));
- strncpy(info->plugin_path, directory.c_str(), directory.length());
- info->plugin_path[directory.length()] = '\0';
- addon = Factory(info, ADDON_UNKNOWN);
-
- free(info->plugin_path);
- info->plugin_path = nullptr;
- cp_release_info(context, info);
- }
- else
- CLog::Log(LOGERROR, "Failed to parse '%s'", addonXmlPath.c_str());
+ auto addonInfo = CAddonInfoBuilder::Generate(directory);
+ if (addonInfo)
+ addon = CAddonBuilder::Generate(addonInfo, ADDON_UNKNOWN);
- cp_destroy_context(context);
return addon != nullptr;
}
@@ -1228,49 +1160,28 @@ bool CAddonMgr::AddonsFromRepoXML(const CRepository::DirInfo& repo, const std::s
CXBMCTinyXML doc;
if (!doc.Parse(xml))
{
- CLog::Log(LOGERROR, "CAddonMgr: Failed to parse addons.xml.");
+ CLog::Log(LOGERROR, "CAddonMgr::{}: Failed to parse addons.xml", __FUNCTION__);
return false;
}
if (doc.RootElement() == nullptr || doc.RootElement()->ValueStr() != "addons")
{
- CLog::Log(LOGERROR, "CAddonMgr: Failed to parse addons.xml. Malformed.");
+ CLog::Log(LOGERROR, "CAddonMgr::{}: Failed to parse addons.xml. Malformed", __FUNCTION__);
return false;
}
- // create a context for these addons
- cp_status_t status;
- cp_context_t *context = cp_create_context(&status);
- if (!context)
- return false;
-
// each addon XML should have a UTF-8 declaration
- TiXmlDeclaration decl("1.0", "UTF-8", "");
auto element = doc.RootElement()->FirstChildElement("addon");
while (element)
{
- // dump the XML back to text
- std::string xml;
- xml << decl;
- xml << *element;
- cp_status_t status;
- cp_plugin_info_t *info = cp_load_plugin_descriptor_from_memory(context, xml.c_str(), xml.size(), &status);
- if (info)
- {
- CAddonBuilder builder;
- if (Factory(info, ADDON_UNKNOWN, builder, false, repo))
- {
- auto addon = builder.Build();
- if (addon)
- addons.push_back(std::move(addon));
- }
- free(info->plugin_path);
- info->plugin_path = nullptr;
- cp_release_info(context, info);
- }
+ auto addonInfo = CAddonInfoBuilder::Generate(element, repo);
+ auto addon = CAddonBuilder::Generate(addonInfo, ADDON_UNKNOWN);
+ if (addon)
+ addons.push_back(std::move(addon));
+
element = element->NextSiblingElement("addon");
}
- cp_destroy_context(context);
+
return true;
}
@@ -1360,4 +1271,50 @@ void cp_logger(cp_log_severity_t level, const char *msg, const char *apid, void
CLog::Log(cp_to_clog(level), "ADDON: cpluff: '%s' reports '%s'", apid, msg);
}
+bool CAddonMgr::GetAddonInfos(AddonInfos& addonInfos, TYPE type)
+{
+ CSingleLock lock(m_critSection);
+
+ bool forUnknown = type == ADDON_UNKNOWN;
+ for (auto& info : m_installedAddons)
+ {
+ if (info.second->MainType() != ADDON_UNKNOWN && (forUnknown || info.second->IsType(type)))
+ addonInfos.push_back(info.second);
+ }
+
+ return !addonInfos.empty();
+}
+
+const AddonInfoPtr CAddonMgr::GetAddonInfo(const std::string& id, TYPE type /*= ADDON_UNKNOWN*/)
+{
+ CSingleLock lock(m_critSection);
+
+ auto addon = m_installedAddons.find(id);
+ if (addon != m_installedAddons.end())
+ if ((type == ADDON_UNKNOWN || addon->second->IsType(type)))
+ return addon->second;
+
+ return nullptr;
+}
+
+void CAddonMgr::FindAddons(ADDON_INFO_LIST& addonmap, const std::string& path)
+{
+ CFileItemList items;
+ if (XFILE::CDirectory::GetDirectory(path, items, "", XFILE::DIR_FLAG_NO_FILE_DIRS))
+ {
+ for (int i = 0; i < items.Size(); ++i)
+ {
+ std::string path = items[i]->GetPath();
+ if (XFILE::CFile::Exists(path + "addon.xml"))
+ {
+ AddonInfoPtr addonInfo = CAddonInfoBuilder::Generate(path);
+ if (addonInfo)
+ {
+ addonmap[addonInfo->ID()] = addonInfo;
+ }
+ }
+ }
+ }
+}
+
} /* namespace ADDON */
diff --git a/xbmc/addons/AddonManager.h b/xbmc/addons/AddonManager.h
index 9441f8d519..4d0ebc8143 100644
--- a/xbmc/addons/AddonManager.h
+++ b/xbmc/addons/AddonManager.h
@@ -23,6 +23,7 @@ namespace ADDON
{
typedef std::map<TYPE, VECADDONS> MAPADDONS;
typedef std::map<TYPE, VECADDONS>::iterator IMAPADDONS;
+ typedef std::map<std::string, AddonInfoPtr> ADDON_INFO_LIST;
typedef std::vector<cp_cfg_element_t*> ELEMENTS;
/*!
@@ -278,6 +279,9 @@ namespace ADDON
static bool Factory(const cp_plugin_info_t* plugin, TYPE type, CAddonBuilder& builder, bool ignoreExtensions = false, const CRepository::DirInfo& repo = {});
static void FillCpluffMetadata(const cp_plugin_info_t* plugin, CAddonBuilder& builder, const CRepository::DirInfo& repo);
+ bool GetAddonInfos(AddonInfos& addonInfos, TYPE type);
+ const AddonInfoPtr GetAddonInfo(const std::string& id, TYPE type = ADDON_UNKNOWN);
+
private:
CAddonMgr& operator=(CAddonMgr const&) = delete;
/* libcpluff */
@@ -293,6 +297,8 @@ namespace ADDON
bool GetAddonsInternal(const TYPE &type, VECADDONS &addons, bool enabledOnly);
bool EnableSingle(const std::string& id);
+ void FindAddons(ADDON_INFO_LIST& addonmap, const std::string& path);
+
std::set<std::string> m_disabled;
std::set<std::string> m_updateBlacklist;
static std::map<TYPE, IAddonMgrCallback*> m_managers;
@@ -302,6 +308,7 @@ namespace ADDON
CBlockingEventSource<AddonEvent> m_unloadEvents;
std::set<std::string> m_systemAddons;
std::set<std::string> m_optionalAddons;
+ ADDON_INFO_LIST m_installedAddons;
};
}; /* namespace ADDON */
diff --git a/xbmc/addons/ContextMenuAddon.cpp b/xbmc/addons/ContextMenuAddon.cpp
index aac8328ba2..9aaa77c269 100644
--- a/xbmc/addons/ContextMenuAddon.cpp
+++ b/xbmc/addons/ContextMenuAddon.cpp
@@ -20,6 +20,82 @@
namespace ADDON
{
+CContextMenuAddon::CContextMenuAddon(const AddonInfoPtr& addonInfo)
+ : CAddon(addonInfo, ADDON_CONTEXT_ITEM)
+{
+ std::vector<CContextMenuItem> items;
+
+ const CAddonExtensions* menu = Type(ADDON_CONTEXT_ITEM)->GetElement("menu");
+ if (menu)
+ {
+ int tmp = 0;
+ ParseMenu(menu, "", tmp);
+ }
+ else
+ {
+ //backwards compatibility. add first item definition
+ const CAddonExtensions* elem = Type(ADDON_CONTEXT_ITEM)->GetElement("item");
+ if (elem)
+ {
+ std::string visCondition = elem->GetValue("visible").asString();
+ if (visCondition.empty())
+ visCondition = "false";
+
+ std::string parent = elem->GetValue("parent").asString() == "kodi.core.manage"
+ ? CContextMenuManager::MANAGE.m_groupId : CContextMenuManager::MAIN.m_groupId;
+
+ auto label = elem->GetValue("label").asString();
+ if (StringUtils::IsNaturalNumber(label))
+ label = g_localizeStrings.GetAddonString(ID(), atoi(label.c_str()));
+
+ CContextMenuItem menuItem = CContextMenuItem::CreateItem(label, parent,
+ URIUtils::AddFileToFolder(Path(), Type(ADDON_CONTEXT_ITEM)->LibName()), visCondition, ID());
+
+ m_items.push_back(menuItem);
+ }
+ }
+}
+
+void CContextMenuAddon::ParseMenu(
+ const CAddonExtensions* elem,
+ const std::string& parent,
+ int& anonGroupCount)
+{
+ auto menuId = elem->GetValue("@id").asString();
+ auto menuLabel = elem->GetValue("label").asString();
+ if (StringUtils::IsNaturalNumber(menuLabel))
+ menuLabel = g_localizeStrings.GetAddonString(ID(), std::stoi(menuLabel));
+
+ if (menuId.empty())
+ {
+ //anonymous group. create a new unique internal id.
+ std::stringstream ss;
+ ss << ID() << ++anonGroupCount;
+ menuId = ss.str();
+ }
+
+ m_items.push_back(CContextMenuItem::CreateGroup(menuLabel, parent, menuId, ID()));
+
+ for (const auto subMenu : elem->GetElements("menu"))
+ ParseMenu(&subMenu.second, menuId, anonGroupCount);
+
+ for (const auto element : elem->GetElements("item"))
+ {
+ std::string visCondition = element.second.GetValue("visible").asString();
+ std::string library = element.second.GetValue("@library").asString();
+ std::string label = element.second.GetValue("label").asString();
+ if (StringUtils::IsNaturalNumber(label))
+ label = g_localizeStrings.GetAddonString(ID(), atoi(label.c_str()));
+
+ if (!label.empty() && !library.empty() && !visCondition.empty())
+ {
+ auto menu = CContextMenuItem::CreateItem(label, menuId,
+ URIUtils::AddFileToFolder(Path(), library), visCondition, ID());
+ m_items.push_back(menu);
+ }
+ }
+}
+
void CContextMenuAddon::ParseMenu(
const AddonInfoPtr& addonInfo,
cp_cfg_element_t* elem,
diff --git a/xbmc/addons/ContextMenuAddon.h b/xbmc/addons/ContextMenuAddon.h
index 4c1999bb9c..e0da3dcd31 100644
--- a/xbmc/addons/ContextMenuAddon.h
+++ b/xbmc/addons/ContextMenuAddon.h
@@ -26,12 +26,13 @@ namespace ADDON
public:
static std::unique_ptr<CContextMenuAddon> FromExtension(const AddonInfoPtr& addonInfo, const cp_extension_t* ext);
- explicit CContextMenuAddon(const AddonInfoPtr& addonInfo) : CAddon(addonInfo, ADDON_CONTEXT_ITEM) {}
+ explicit CContextMenuAddon(const AddonInfoPtr& addonInfo);
CContextMenuAddon(const AddonInfoPtr& addonInfo, std::vector<CContextMenuItem> items);
const std::vector<CContextMenuItem>& GetItems() const { return m_items; };
private:
+ void ParseMenu(const CAddonExtensions* elem, const std::string& parent, int& anonGroupCount);
static void ParseMenu(const AddonInfoPtr& addonInfo, cp_cfg_element_t* elem, const std::string& parent,
int& anonGroupCount, std::vector<CContextMenuItem>& items);
diff --git a/xbmc/addons/ImageResource.cpp b/xbmc/addons/ImageResource.cpp
index efc24a22af..8e4b7b7468 100644
--- a/xbmc/addons/ImageResource.cpp
+++ b/xbmc/addons/ImageResource.cpp
@@ -29,6 +29,12 @@ CImageResource::CImageResource(const AddonInfoPtr& addonInfo, std::string type)
{
}
+CImageResource::CImageResource(const AddonInfoPtr& addonInfo)
+ : CResource(addonInfo, ADDON_RESOURCE_IMAGES)
+{
+ m_type = Type(ADDON_RESOURCE_IMAGES)->GetValue("@type").asString();
+}
+
void CImageResource::OnPreUnInstall()
{
CURL xbtUrl;
diff --git a/xbmc/addons/ImageResource.h b/xbmc/addons/ImageResource.h
index 51ceb1f0e1..5cb2f76261 100644
--- a/xbmc/addons/ImageResource.h
+++ b/xbmc/addons/ImageResource.h
@@ -23,7 +23,7 @@ class CImageResource : public CResource
public:
static std::unique_ptr<CImageResource> FromExtension(const AddonInfoPtr& addonInfo, const cp_extension_t* ext);
- explicit CImageResource(const AddonInfoPtr& addonInfo) : CResource(addonInfo, ADDON_RESOURCE_IMAGES) {};
+ explicit CImageResource(const AddonInfoPtr& addonInfo);
CImageResource(const AddonInfoPtr& addonInfo, std::string type);
void OnPreUnInstall() override;
diff --git a/xbmc/addons/LanguageResource.cpp b/xbmc/addons/LanguageResource.cpp
index ca419b6efb..3e839ebfbb 100644
--- a/xbmc/addons/LanguageResource.cpp
+++ b/xbmc/addons/LanguageResource.cpp
@@ -117,6 +117,66 @@ CLanguageResource::CLanguageResource(
m_sortTokens(sortTokens)
{ }
+CLanguageResource::CLanguageResource(const AddonInfoPtr& addonInfo)
+ : CResource(addonInfo, ADDON_RESOURCE_LANGUAGE)
+{
+ // parse <extension> attributes
+ m_locale = CLocale::FromString(Type(ADDON_RESOURCE_LANGUAGE)->GetValue("@locale").asString());
+
+ // parse <charsets>
+ const CAddonExtensions* charsetsElement = Type(ADDON_RESOURCE_LANGUAGE)->GetElement("charsets");
+ if (charsetsElement != nullptr)
+ {
+ m_charsetGui = charsetsElement->GetValue("gui").asString();
+ m_forceUnicodeFont = charsetsElement->GetValue("gui@unicodefont").asBoolean();
+ m_charsetSubtitle = charsetsElement->GetValue("subtitle").asString();
+ }
+
+ // parse <dvd>
+ const CAddonExtensions* dvdElement = Type(ADDON_RESOURCE_LANGUAGE)->GetElement("dvd");
+ if (dvdElement != nullptr)
+ {
+ m_dvdLanguageMenu = dvdElement->GetValue("menu").asString();
+ m_dvdLanguageAudio = dvdElement->GetValue("audio").asString();
+ m_dvdLanguageSubtitle = dvdElement->GetValue("subtitle").asString();
+ }
+ // fall back to the language of the addon if a DVD language is not defined
+ if (m_dvdLanguageMenu.empty())
+ m_dvdLanguageMenu = m_locale.GetLanguageCode();
+ if (m_dvdLanguageAudio.empty())
+ m_dvdLanguageAudio = m_locale.GetLanguageCode();
+ if (m_dvdLanguageSubtitle.empty())
+ m_dvdLanguageSubtitle = m_locale.GetLanguageCode();
+
+ // parse <sorttokens>
+ const CAddonExtensions* sorttokensElement = Type(ADDON_RESOURCE_LANGUAGE)->GetElement("sorttokens");
+ if (sorttokensElement != nullptr)
+ {
+ /* First loop goes around rows e.g.
+ * <token separators="'">L</token>
+ * <token>Le</token>
+ * ...
+ */
+ for (auto values : sorttokensElement->GetValues())
+ {
+ /* Second loop goes around the row parts, e.g.
+ * separators = "'"
+ * token = Le
+ */
+ std::string token = values.second.GetValue("token").asString();
+ std::string separators = values.second.GetValue("token@separators").asString();
+ if (!token.empty())
+ {
+ if (separators.empty())
+ separators = " ._";
+
+ for (auto separator : separators)
+ m_sortTokens.insert(token + separator);
+ }
+ }
+ }
+}
+
bool CLanguageResource::IsInUse() const
{
return StringUtils::EqualsNoCase(CServiceBroker::GetSettingsComponent()->GetSettings()->GetString(CSettings::SETTING_LOCALE_LANGUAGE), ID());
diff --git a/xbmc/addons/LanguageResource.h b/xbmc/addons/LanguageResource.h
index 5b44a2dc56..1cc5f06cc3 100644
--- a/xbmc/addons/LanguageResource.h
+++ b/xbmc/addons/LanguageResource.h
@@ -20,7 +20,7 @@ class CLanguageResource : public CResource
public:
static std::unique_ptr<CLanguageResource> FromExtension(const AddonInfoPtr& addonInfo, const cp_extension_t* ext);
- explicit CLanguageResource(const AddonInfoPtr& addonInfo) : CResource(addonInfo, ADDON_RESOURCE_LANGUAGE), m_forceUnicodeFont(false) {};
+ explicit CLanguageResource(const AddonInfoPtr& addonInfo);
CLanguageResource(const AddonInfoPtr& addonInfo,
const CLocale& locale,
diff --git a/xbmc/addons/PluginSource.cpp b/xbmc/addons/PluginSource.cpp
index d4b2b4a704..0ab04b674a 100644
--- a/xbmc/addons/PluginSource.cpp
+++ b/xbmc/addons/PluginSource.cpp
@@ -48,13 +48,33 @@ std::unique_ptr<CPluginSource> CPluginSource::FromExtension(const AddonInfoPtr&
return std::unique_ptr<CPluginSource>(p);
}
-CPluginSource::CPluginSource(const AddonInfoPtr& addonInfo, TYPE addonType)
- : CAddon(addonInfo, addonType)
+CPluginSource::CPluginSource(const AddonInfoPtr& addonInfo, TYPE addonType) : CAddon(addonInfo, addonType)
{
- std::string provides;
- InfoMap::const_iterator i = m_addonInfo->ExtraInfo().find("provides");
- if (i != m_addonInfo->ExtraInfo().end())
- provides = i->second;
+ std::string provides = addonInfo->Type(addonType)->GetValue("provides").asString();
+ if (!provides.empty())
+ addonInfo->AddExtraInfo("provides", provides);
+ else
+ {
+ const auto& i = addonInfo->ExtraInfo().find("provides");
+ if (i != addonInfo->ExtraInfo().end())
+ provides = i->second;
+ }
+
+ for (auto values : addonInfo->Type(addonType)->GetValues())
+ {
+ if (values.first != "medialibraryscanpath")
+ continue;
+
+ std::string url = "plugin://" + ID() + '/';
+ std::string content = values.second.GetValue("medialibraryscanpath@content").asString();
+ std::string path = values.second.GetValue("medialibraryscanpath").asString();
+ if (!path.empty() && path.front() == '/')
+ path.erase(0, 1);
+ if (path.compare(0, url.size(), url))
+ path.insert(0, url);
+ m_mediaLibraryScanPaths[content].push_back(CURL(path).GetFileName());
+ }
+
SetProvides(provides);
}
diff --git a/xbmc/addons/Repository.cpp b/xbmc/addons/Repository.cpp
index 5a77bc82b7..8e41dc8943 100644
--- a/xbmc/addons/Repository.cpp
+++ b/xbmc/addons/Repository.cpp
@@ -178,6 +178,40 @@ CRepository::CRepository(const AddonInfoPtr& addonInfo, DirList dirs)
}
}
+CRepository::CRepository(const AddonInfoPtr& addonInfo)
+ : CAddon(addonInfo, ADDON_REPOSITORY)
+{
+ DirList dirs;
+ AddonVersion version("0.0.0");
+ AddonInfoPtr addonver = CServiceBroker::GetAddonMgr().GetAddonInfo("xbmc.addon");
+ if (addonver)
+ version = addonver->Version();
+
+ for (auto element : Type(ADDON_REPOSITORY)->GetElements("dir"))
+ {
+ DirInfo dir = ParseDirConfiguration(element.second);
+ if (dir.version <= version)
+ m_dirs.push_back(std::move(dir));
+ }
+ if (!Type(ADDON_REPOSITORY)->GetValue("info").empty())
+ {
+ m_dirs.push_back(ParseDirConfiguration(*Type(ADDON_REPOSITORY)));
+ }
+
+ for (auto const& dir : m_dirs)
+ {
+ CURL datadir(dir.datadir);
+ if (datadir.IsProtocol("http"))
+ {
+ CLog::Log(LOGWARNING, "Repository {} uses plain HTTP for add-on downloads - this is insecure and will make your Kodi installation vulnerable to attacks if enabled!", Name());
+ }
+ else if (datadir.IsProtocol("https") && datadir.HasProtocolOption("verifypeer") && datadir.GetProtocolOption("verifypeer") == "false")
+ {
+ CLog::Log(LOGWARNING, "Repository {} disabled peer verification for add-on downloads - this is insecure and will make your Kodi installation vulnerable to attacks if enabled!", Name());
+ }
+ }
+}
+
bool CRepository::FetchChecksum(const std::string& url, std::string& checksum) noexcept
{
CFile file;
@@ -272,6 +306,43 @@ CRepository::FetchStatus CRepository::FetchIfChanged(const std::string& oldCheck
return STATUS_OK;
}
+CRepository::DirInfo CRepository::ParseDirConfiguration(const CAddonExtensions& configuration)
+{
+ DirInfo dir;
+ dir.checksum = configuration.GetValue("checksum").asString();
+ std::string checksumStr = configuration.GetValue("checksum@verify").asString();
+ if (!checksumStr.empty())
+ {
+ dir.checksumType = CDigest::TypeFromString(checksumStr);
+ }
+ dir.info = configuration.GetValue("info").asString();
+ dir.datadir = configuration.GetValue("datadir").asString();
+ dir.artdir = configuration.GetValue("artdir").asString();
+ if (dir.artdir.empty())
+ {
+ dir.artdir = dir.datadir;
+ }
+
+ std::string hashStr = configuration.GetValue("hashes").asString();
+ StringUtils::ToLower(hashStr);
+ if (hashStr == "true")
+ {
+ // Deprecated alias
+ hashStr = "md5";
+ }
+ if (!hashStr.empty() && hashStr != "false")
+ {
+ dir.hashType = CDigest::TypeFromString(hashStr);
+ if (dir.hashType == CDigest::Type::MD5)
+ {
+ CLog::Log(LOGWARNING, "CRepository::{}: Repository has MD5 hashes enabled - this hash function is broken and will only guard against unintentional data corruption", __FUNCTION__);
+ }
+ }
+
+ dir.version = AddonVersion{configuration.GetValue("@minversion").asString()};
+ return dir;
+}
+
CRepositoryUpdateJob::CRepositoryUpdateJob(const RepositoryPtr& repo) : m_repo(repo) {}
bool CRepositoryUpdateJob::DoWork()
diff --git a/xbmc/addons/Repository.h b/xbmc/addons/Repository.h
index 7fe36090e3..132955a00c 100644
--- a/xbmc/addons/Repository.h
+++ b/xbmc/addons/Repository.h
@@ -38,7 +38,7 @@ namespace ADDON
static std::unique_ptr<CRepository> FromExtension(const AddonInfoPtr& addonInfo, const cp_extension_t* ext);
- explicit CRepository(const AddonInfoPtr& addonInfo) : CAddon(addonInfo, ADDON_REPOSITORY) {};
+ explicit CRepository(const AddonInfoPtr& addonInfo);
CRepository(const AddonInfoPtr& addonInfo, DirList dirs);
enum FetchStatus
@@ -62,6 +62,7 @@ namespace ADDON
static bool FetchIndex(const DirInfo& repo, std::string const& digest, VECADDONS& addons) noexcept;
static DirInfo ParseDirConfiguration(cp_cfg_element_t* configuration);
+ static DirInfo ParseDirConfiguration(const CAddonExtensions& configuration);
DirList m_dirs;
};
diff --git a/xbmc/addons/Scraper.cpp b/xbmc/addons/Scraper.cpp
index 39376d9a00..fbbbd7c449 100644
--- a/xbmc/addons/Scraper.cpp
+++ b/xbmc/addons/Scraper.cpp
@@ -160,7 +160,35 @@ CScraper::CScraper(const AddonInfoPtr& addonInfo, TYPE addonType)
, m_requiressettings(false)
, m_pathContent(CONTENT_NONE)
{
- m_isPython = URIUtils::GetExtension(LibPath()) == ".py";
+ m_requiressettings = addonInfo->Type(addonType)->GetValue("@requiressettings").asBoolean();
+
+ CDateTimeSpan persistence;
+ std::string tmp = addonInfo->Type(addonType)->GetValue("@cachepersistence").asString();
+ if (!tmp.empty())
+ m_persistence.SetFromTimeString(tmp);
+
+ switch (addonType)
+ {
+ case ADDON_SCRAPER_ALBUMS:
+ m_pathContent = CONTENT_ALBUMS;
+ break;
+ case ADDON_SCRAPER_ARTISTS:
+ m_pathContent = CONTENT_ARTISTS;
+ break;
+ case ADDON_SCRAPER_MOVIES:
+ m_pathContent = CONTENT_MOVIES;
+ break;
+ case ADDON_SCRAPER_MUSICVIDEOS:
+ m_pathContent = CONTENT_MUSICVIDEOS;
+ break;
+ case ADDON_SCRAPER_TVSHOWS:
+ m_pathContent = CONTENT_TVSHOWS;
+ break;
+ default:
+ break;
+ }
+
+ m_isPython = URIUtils::GetExtension(addonInfo->Type(addonType)->LibPath()) == ".py";
}
CScraper::CScraper(const AddonInfoPtr& addonInfo,
diff --git a/xbmc/addons/Skin.cpp b/xbmc/addons/Skin.cpp
index 39554a25c2..5c7639f966 100644
--- a/xbmc/addons/Skin.cpp
+++ b/xbmc/addons/Skin.cpp
@@ -218,6 +218,43 @@ CSkinInfo::CSkinInfo(
LoadStartupWindows(nullptr);
}
+CSkinInfo::CSkinInfo(const AddonInfoPtr& addonInfo) : CAddon(addonInfo, ADDON_SKIN)
+{
+ for (auto values : Type(ADDON_SKIN)->GetValues())
+ {
+ if (values.first != "res")
+ continue;
+
+ int width = values.second.GetValue("res@width").asInteger();
+ int height = values.second.GetValue("res@height").asInteger();
+ bool defRes = values.second.GetValue("res@default").asBoolean();
+ std::string folder = values.second.GetValue("res@folder").asString();
+ std::string strAspect = values.second.GetValue("res@aspect").asString();
+ float aspect = 0;
+
+ std::vector<std::string> fracs = StringUtils::Split(strAspect, ':');
+ if (fracs.size() == 2)
+ aspect = (float)(atof(fracs[0].c_str())/atof(fracs[1].c_str()));
+ if (width > 0 && height > 0)
+ {
+ RESOLUTION_INFO res(width, height, aspect, folder);
+ res.strId = strAspect; // for skin usage, store aspect string in strId
+ if (defRes)
+ m_defaultRes = res;
+ m_resolutions.push_back(res);
+ }
+ }
+
+ m_effectsSlowDown = Type(ADDON_SKIN)->GetValue("@effectslowdown").asFloat();
+ if (m_effectsSlowDown == 0.0f)
+ m_effectsSlowDown = 1.f;
+
+ m_debugging = Type(ADDON_SKIN)->GetValue("@debugging").asBoolean();
+
+ m_settingsUpdateHandler.reset(new CSkinSettingUpdateHandler(*this));
+ LoadStartupWindows(nullptr);
+}
+
CSkinInfo::~CSkinInfo() = default;
struct closestRes
diff --git a/xbmc/addons/Skin.h b/xbmc/addons/Skin.h
index ff03faa0b5..fb7721db73 100644
--- a/xbmc/addons/Skin.h
+++ b/xbmc/addons/Skin.h
@@ -97,10 +97,11 @@ public:
static std::unique_ptr<CSkinInfo> FromExtension(const AddonInfoPtr& addonInfo, const cp_extension_t* ext);
+ explicit CSkinInfo(const AddonInfoPtr& addonInfo);
//FIXME: CAddonCallbacksGUI/WindowXML hack
explicit CSkinInfo(
const AddonInfoPtr& addonInfo,
- const RESOLUTION_INFO& resolution = RESOLUTION_INFO());
+ const RESOLUTION_INFO& resolution);
CSkinInfo(
const AddonInfoPtr& addonInfo,
diff --git a/xbmc/addons/Webinterface.cpp b/xbmc/addons/Webinterface.cpp
index 2cc6abe541..77b35e8fbe 100644
--- a/xbmc/addons/Webinterface.cpp
+++ b/xbmc/addons/Webinterface.cpp
@@ -39,6 +39,24 @@ CWebinterface::CWebinterface(const AddonInfoPtr& addonInfo, WebinterfaceType typ
const std::string &entryPoint) : CAddon(addonInfo, ADDON_WEB_INTERFACE), m_type(type), m_entryPoint(entryPoint)
{ }
+CWebinterface::CWebinterface(const AddonInfoPtr& addonInfo)
+ : CAddon(addonInfo, ADDON_WEB_INTERFACE),
+ m_type(WebinterfaceTypeStatic),
+ m_entryPoint(WEBINTERFACE_DEFAULT_ENTRY_POINT)
+{
+ // determine the type of the webinterface
+ std::string webinterfaceType = Type(ADDON_WEB_INTERFACE)->GetValue("@type").asString();
+ if (StringUtils::EqualsNoCase(webinterfaceType, "wsgi"))
+ m_type = WebinterfaceTypeWsgi;
+ else if (!webinterfaceType.empty() && !StringUtils::EqualsNoCase(webinterfaceType, "static") && !StringUtils::EqualsNoCase(webinterfaceType, "html"))
+ CLog::Log(LOGWARNING, "CWebinterface::{}: Addon \"{}\" has specified an unsupported type \"{}\"", ID(), webinterfaceType);
+
+ // determine the entry point of the webinterface
+ std::string entry = Type(ADDON_WEB_INTERFACE)->GetValue("@entry").asString();
+ if (!entry.empty())
+ m_entryPoint = entry;
+}
+
std::string CWebinterface::GetEntryPoint(const std::string &path) const
{
if (m_type == WebinterfaceTypeWsgi)
diff --git a/xbmc/addons/Webinterface.h b/xbmc/addons/Webinterface.h
index 398629afaa..4a3520a1ff 100644
--- a/xbmc/addons/Webinterface.h
+++ b/xbmc/addons/Webinterface.h
@@ -25,10 +25,7 @@ namespace ADDON
public:
static std::unique_ptr<CWebinterface> FromExtension(const AddonInfoPtr& addonInfo, const cp_extension_t* ext);
- explicit CWebinterface(const AddonInfoPtr& addonInfo)
- : CAddon(addonInfo, ADDON_WEB_INTERFACE),
- m_type(WebinterfaceTypeStatic),
- m_entryPoint(WEBINTERFACE_DEFAULT_ENTRY_POINT) {}
+ explicit CWebinterface(const AddonInfoPtr& addonInfo);
CWebinterface(const AddonInfoPtr& addonInfo, WebinterfaceType type, const std::string &entryPoint);
WebinterfaceType GetType() const { return m_type; }
diff --git a/xbmc/games/addons/GameClient.cpp b/xbmc/games/addons/GameClient.cpp
index 7c093e7476..75949586f0 100644
--- a/xbmc/games/addons/GameClient.cpp
+++ b/xbmc/games/addons/GameClient.cpp
@@ -100,38 +100,26 @@ std::unique_ptr<CGameClient> CGameClient::FromExtension(const ADDON::AddonInfoPt
CGameClient::CGameClient(const ADDON::AddonInfoPtr& addonInfo) :
CAddonDll(addonInfo, ADDON::ADDON_GAMEDLL),
m_subsystems(CGameClientSubsystem::CreateSubsystems(*this, m_struct, m_critSection)),
- m_bSupportsVFS(false),
- m_bSupportsStandalone(false),
m_bSupportsAllExtensions(false),
m_bIsPlaying(false),
m_serializeSize(0),
m_region(GAME_REGION_UNKNOWN)
{
- const ADDON::InfoMap& extraInfo = m_addonInfo->ExtraInfo();
- ADDON::InfoMap::const_iterator it;
+ using namespace ADDON;
- it = extraInfo.find(GAME_PROPERTY_EXTENSIONS);
- if (it != extraInfo.end())
- {
- std::vector<std::string> extensions = StringUtils::Split(it->second, EXTENSION_SEPARATOR);
- std::transform(extensions.begin(), extensions.end(),
- std::inserter(m_extensions, m_extensions.begin()), NormalizeExtension);
+ std::vector<std::string> extensions = StringUtils::Split(Type(ADDON_GAMEDLL)->GetValue(GAME_PROPERTY_EXTENSIONS).asString(), EXTENSION_SEPARATOR);
+ std::transform(extensions.begin(), extensions.end(),
+ std::inserter(m_extensions, m_extensions.begin()), NormalizeExtension);
- // Check for wildcard extension
- if (m_extensions.find(EXTENSION_WILDCARD) != m_extensions.end())
- {
- m_bSupportsAllExtensions = true;
- m_extensions.clear();
- }
+ // Check for wildcard extension
+ if (m_extensions.find(EXTENSION_WILDCARD) != m_extensions.end())
+ {
+ m_bSupportsAllExtensions = true;
+ m_extensions.clear();
}
- it = extraInfo.find(GAME_PROPERTY_SUPPORTS_VFS);
- if (it != extraInfo.end())
- m_bSupportsVFS = (it->second == "true");
-
- it = extraInfo.find(GAME_PROPERTY_SUPPORTS_STANDALONE);
- if (it != extraInfo.end())
- m_bSupportsStandalone = (it->second == "true");
+ m_bSupportsVFS = addonInfo->Type(ADDON_GAMEDLL)->GetValue(GAME_PROPERTY_SUPPORTS_VFS).asBoolean();
+ m_bSupportsStandalone = addonInfo->Type(ADDON_GAMEDLL)->GetValue(GAME_PROPERTY_SUPPORTS_STANDALONE).asBoolean();
}
CGameClient::~CGameClient(void)