2 * Copyright (C) 2013 Arne Morten Kvarving
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 * See LICENSES/README.md for more information.
8 #include "ExtsMimeSupportList.h"
10 #include "ServiceBroker.h"
11 #include "addons/AddonEvents.h"
12 #include "addons/AddonManager.h"
13 #include "addons/addoninfo/AddonInfo.h"
14 #include "addons/addoninfo/AddonType.h"
15 #include "addons/kodi-dev-kit/include/kodi/addon-instance/AudioDecoder.h"
16 #include "guilib/LocalizeStrings.h"
17 #include "utils/URIUtils.h"
18 #include "utils/log.h"
22 using namespace ADDON
;
23 using namespace KODI::ADDONS
;
25 CExtsMimeSupportList::CExtsMimeSupportList(CAddonMgr
& addonMgr
) : m_addonMgr(addonMgr
)
27 m_addonMgr
.Events().Subscribe(this, &CExtsMimeSupportList::OnEvent
);
29 // Load all available audio decoder addons during Kodi start
30 const std::vector
<AddonType
> types
= {AddonType::AUDIODECODER
, AddonType::IMAGEDECODER
};
31 const auto addonInfos
= m_addonMgr
.GetAddonInfos(true, types
);
32 for (const auto& addonInfo
: addonInfos
)
33 m_supportedList
.emplace_back(ScanAddonProperties(addonInfo
->MainType(), addonInfo
));
36 CExtsMimeSupportList::~CExtsMimeSupportList()
38 m_addonMgr
.Events().Unsubscribe(this);
41 void CExtsMimeSupportList::OnEvent(const AddonEvent
& event
)
43 if (typeid(event
) == typeid(AddonEvents::Enabled
) ||
44 typeid(event
) == typeid(AddonEvents::Disabled
) ||
45 typeid(event
) == typeid(AddonEvents::ReInstalled
))
47 if (m_addonMgr
.HasType(event
.addonId
, AddonType::AUDIODECODER
) ||
48 m_addonMgr
.HasType(event
.addonId
, AddonType::IMAGEDECODER
))
49 Update(event
.addonId
);
51 else if (typeid(event
) == typeid(AddonEvents::UnInstalled
))
53 Update(event
.addonId
);
57 void CExtsMimeSupportList::Update(const std::string
& id
)
59 // Stop used instance if present, otherwise the new becomes created on already created addon base one.
61 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
64 std::find_if(m_supportedList
.begin(), m_supportedList
.end(),
65 [&id
](const SupportValues
& addon
) { return addon
.m_addonInfo
->ID() == id
; });
67 if (itAddon
!= m_supportedList
.end())
69 m_supportedList
.erase(itAddon
);
73 // Create and init the new addon instance
74 std::shared_ptr
<CAddonInfo
> addonInfo
= m_addonMgr
.GetAddonInfo(id
, AddonType::UNKNOWN
);
75 if (addonInfo
&& !m_addonMgr
.IsAddonDisabled(id
))
77 if (addonInfo
->HasType(AddonType::AUDIODECODER
) || addonInfo
->HasType(AddonType::IMAGEDECODER
))
79 SupportValues values
= ScanAddonProperties(addonInfo
->MainType(), addonInfo
);
81 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
82 m_supportedList
.emplace_back(values
);
88 CExtsMimeSupportList::SupportValues
CExtsMimeSupportList::ScanAddonProperties(
89 AddonType type
, const std::shared_ptr
<CAddonInfo
>& addonInfo
)
93 values
.m_addonType
= type
;
94 values
.m_addonInfo
= addonInfo
;
95 if (type
== AddonType::AUDIODECODER
)
97 values
.m_codecName
= addonInfo
->Type(type
)->GetValue("@name").asString();
98 values
.m_hasTags
= addonInfo
->Type(type
)->GetValue("@tags").asBoolean();
99 values
.m_hasTracks
= addonInfo
->Type(type
)->GetValue("@tracks").asBoolean();
102 const auto support
= addonInfo
->Type(type
)->GetElement("support");
105 // Scan here about complete defined xml groups with description and maybe icon
107 // `<extension name=".zwdsp">`
108 // ` <description>30246</description>`
110 for (const auto& i
: support
->GetElements())
112 std::string name
= i
.second
.GetValue("@name").asString();
116 const int description
= i
.second
.GetValue("description").asInteger();
117 const std::string icon
=
118 !i
.second
.GetValue("icon").empty()
119 ? URIUtils::AddFileToFolder(addonInfo
->Path(), i
.second
.GetValue("icon").asString())
122 if (i
.first
== "extension")
125 name
.insert(name
.begin(), '.');
126 values
.m_supportedExtensions
.emplace(name
, SupportValue(description
, icon
));
128 else if (i
.first
== "mimetype")
130 values
.m_supportedMimetypes
.emplace(name
, SupportValue(description
, icon
));
131 const std::string extension
= i
.second
.GetValue("extension").asString();
132 if (!extension
.empty())
133 values
.m_supportedExtensions
.emplace(extension
, SupportValue(description
, icon
));
137 // Scan here about small defined xml groups without anything
138 // e.g. `<extension name=".adp"/>`
139 for (const auto& i
: support
->GetValues())
141 for (const auto& j
: i
.second
)
143 std::string name
= j
.second
.asString();
144 if (j
.first
== "extension@name")
147 name
.insert(name
.begin(), '.');
148 values
.m_supportedExtensions
.emplace(name
, SupportValue(-1, ""));
150 else if (j
.first
== "mimetype@name")
151 values
.m_supportedMimetypes
.emplace(name
, SupportValue(-1, ""));
156 // Check addons support tracks, if yes add extension about related entry names
157 // By them addon no more need to add itself on his addon.xml
158 if (values
.m_hasTracks
)
159 values
.m_supportedExtensions
.emplace(
160 "." + values
.m_codecName
+ KODI_ADDON_AUDIODECODER_TRACK_EXT
, SupportValue(-1, ""));
166 std::vector
<CExtsMimeSupportList::SupportValues
> CExtsMimeSupportList::GetSupportedAddonInfos(
169 std::vector
<SupportValues
> addonInfos
;
171 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
173 for (const auto& entry
: m_supportedList
)
175 if (select
== FilterSelect::all
|| (select
== FilterSelect::hasTags
&& entry
.m_hasTags
) ||
176 (select
== FilterSelect::hasTracks
&& entry
.m_hasTracks
))
177 addonInfos
.emplace_back(entry
);
183 bool CExtsMimeSupportList::IsExtensionSupported(const std::string
& ext
)
185 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
187 for (const auto& entry
: m_supportedList
)
189 const auto it
= std::find_if(
190 entry
.m_supportedExtensions
.begin(), entry
.m_supportedExtensions
.end(),
191 [ext
](const std::pair
<std::string
, SupportValue
>& v
) { return v
.first
== ext
; });
192 if (it
!= entry
.m_supportedExtensions
.end())
199 std::vector
<std::pair
<AddonType
, std::shared_ptr
<ADDON::CAddonInfo
>>> CExtsMimeSupportList::
200 GetExtensionSupportedAddonInfos(const std::string
& ext
, FilterSelect select
)
202 std::vector
<std::pair
<AddonType
, std::shared_ptr
<CAddonInfo
>>> addonInfos
;
204 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
206 for (const auto& entry
: m_supportedList
)
208 const auto it
= std::find_if(
209 entry
.m_supportedExtensions
.begin(), entry
.m_supportedExtensions
.end(),
210 [ext
](const std::pair
<std::string
, SupportValue
>& v
) { return v
.first
== ext
; });
211 if (it
!= entry
.m_supportedExtensions
.end() &&
212 (select
== FilterSelect::all
|| (select
== FilterSelect::hasTags
&& entry
.m_hasTags
) ||
213 (select
== FilterSelect::hasTracks
&& entry
.m_hasTracks
)))
214 addonInfos
.emplace_back(entry
.m_addonType
, entry
.m_addonInfo
);
220 bool CExtsMimeSupportList::IsMimetypeSupported(const std::string
& mimetype
)
222 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
224 for (const auto& entry
: m_supportedList
)
227 const auto it
= std::find_if(
228 entry
.m_supportedMimetypes
.begin(), entry
.m_supportedMimetypes
.end(),
229 [mimetype
](const std::pair
<std::string
, SupportValue
>& v
) { return v
.first
== mimetype
; });
230 if (it
!= entry
.m_supportedMimetypes
.end())
237 std::vector
<std::pair
<AddonType
, std::shared_ptr
<CAddonInfo
>>> CExtsMimeSupportList::
238 GetMimetypeSupportedAddonInfos(const std::string
& mimetype
, FilterSelect select
)
240 std::vector
<std::pair
<AddonType
, std::shared_ptr
<CAddonInfo
>>> addonInfos
;
242 std::unique_lock
<CCriticalSection
> lock(m_critSection
);
244 for (const auto& entry
: m_supportedList
)
246 const auto it
= std::find_if(
247 entry
.m_supportedMimetypes
.begin(), entry
.m_supportedMimetypes
.end(),
248 [mimetype
](const std::pair
<std::string
, SupportValue
>& v
) { return v
.first
== mimetype
; });
249 if (it
!= entry
.m_supportedMimetypes
.end() &&
250 (select
== FilterSelect::all
|| (select
== FilterSelect::hasTags
&& entry
.m_hasTags
) ||
251 (select
== FilterSelect::hasTracks
&& entry
.m_hasTracks
)))
252 addonInfos
.emplace_back(entry
.m_addonType
, entry
.m_addonInfo
);
258 std::vector
<AddonSupportEntry
> CExtsMimeSupportList::GetSupportedExtsAndMimeTypes(
259 const std::string
& addonId
)
261 std::vector
<AddonSupportEntry
> list
;
264 std::find_if(m_supportedList
.begin(), m_supportedList
.end(),
265 [addonId
](const SupportValues
& v
) { return v
.m_addonInfo
->ID() == addonId
; });
266 if (it
== m_supportedList
.end())
269 for (const auto& entry
: it
->m_supportedExtensions
)
271 AddonSupportEntry supportEntry
;
272 supportEntry
.m_type
= AddonSupportType::Extension
;
273 supportEntry
.m_name
= entry
.first
;
274 supportEntry
.m_description
=
275 g_localizeStrings
.GetAddonString(addonId
, entry
.second
.m_description
);
276 supportEntry
.m_icon
= entry
.second
.m_icon
;
277 list
.emplace_back(supportEntry
);
279 for (const auto& entry
: it
->m_supportedMimetypes
)
281 AddonSupportEntry supportEntry
;
282 supportEntry
.m_type
= AddonSupportType::Mimetype
;
283 supportEntry
.m_name
= entry
.first
;
284 supportEntry
.m_description
=
285 g_localizeStrings
.GetAddonString(addonId
, entry
.second
.m_description
);
286 supportEntry
.m_icon
= entry
.second
.m_icon
;
287 list
.emplace_back(supportEntry
);