Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 919 lines (823 sloc) 25.945 kB
074db86 merged: addons-fw branch
elupus authored
1 /*
2 * Copyright (C) 2005-2009 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21 #include "AddonManager.h"
22 #include "Addon.h"
639b314 changed: move addonbrowser to a mediawindow derivate
spiff_ authored
23 #include "AddonDatabase.h"
1b2781c added: basic cpluff support
alcoheca authored
24 #include "DllLibCPluff.h"
074db86 merged: addons-fw branch
elupus authored
25 #include "StringUtils.h"
26 #include "RegExp.h"
27 #include "XMLUtils.h"
639b314 changed: move addonbrowser to a mediawindow derivate
spiff_ authored
28 #include "utils/JobManager.h"
29 #include "utils/SingleLock.h"
074db86 merged: addons-fw branch
elupus authored
30 #include "FileItem.h"
822ca91 added: translatable <description>, <title>, <summary> and <disclaimer…
spiff_ authored
31 #include "LangInfo.h"
074db86 merged: addons-fw branch
elupus authored
32 #include "Settings.h"
33 #include "GUISettings.h"
34 #include "DownloadQueueManager.h"
1b2781c added: basic cpluff support
alcoheca authored
35 #include "AdvancedSettings.h"
dacdca0 changed: moved CAddonStatusHandler to separate files
alcoheca authored
36 #include "log.h"
074db86 merged: addons-fw branch
elupus authored
37
38 #ifdef HAS_VISUALISATION
055f806 cosmetic/tidyup move all addon classes to /xbmc/addons/
alcoheca authored
39 #include "DllVisualisation.h"
40 #include "Visualisation.h"
074db86 merged: addons-fw branch
elupus authored
41 #endif
42 #ifdef HAS_SCREENSAVER
055f806 cosmetic/tidyup move all addon classes to /xbmc/addons/
alcoheca authored
43 #include "DllScreenSaver.h"
44 #include "ScreenSaver.h"
074db86 merged: addons-fw branch
elupus authored
45 #endif
46 //#ifdef HAS_SCRAPERS
055f806 cosmetic/tidyup move all addon classes to /xbmc/addons/
alcoheca authored
47 #include "Scraper.h"
074db86 merged: addons-fw branch
elupus authored
48 //#endif
606248f added: addon repository class
spiff_ authored
49 #include "Repository.h"
553d213 changed: finished moving skins to addon framework
alcoheca authored
50 #include "Skin.h"
af8cb2a Revert "wip"
alcoheca authored
51
88e9b6f changed: expand std namespace
spiff_ authored
52 using namespace std;
53
074db86 merged: addons-fw branch
elupus authored
54 namespace ADDON
55 {
56
57
58 /**********************************************************
59 * CAddonMgr
60 *
61 */
62
63 CAddonMgr* CAddonMgr::m_pInstance = NULL;
88e9b6f changed: expand std namespace
spiff_ authored
64 map<TYPE, IAddonMgrCallback*> CAddonMgr::m_managers;
074db86 merged: addons-fw branch
elupus authored
65
1b2781c added: basic cpluff support
alcoheca authored
66 AddonPtr AddonFactory(const cp_extension_t *props)
67 {
68 const TYPE type = TranslateType(props->ext_point_id);
69 switch (type)
70 {
71 case ADDON_PLUGIN:
72 case ADDON_SCRIPT:
73 return AddonPtr(new CAddon(props->plugin));
74 case ADDON_SCRAPER:
75 return AddonPtr(new CScraper(props->plugin));
76 case ADDON_VIZ:
77 return AddonPtr(new CVisualisation(props->plugin));
78 case ADDON_SCREENSAVER:
79 return AddonPtr(new CScreenSaver(props->plugin));
5ff028a added: skin support via cpluff
alcoheca authored
80 case ADDON_SKIN:
81 return AddonPtr(new CSkinInfo(props->plugin));
1b2781c added: basic cpluff support
alcoheca authored
82 case ADDON_SCRAPER_LIBRARY:
83 case ADDON_VIZ_LIBRARY:
84 return AddonPtr(new CAddonLibrary(props->plugin));
85 default:
86 return AddonPtr();
87 }
88 }
89
074db86 merged: addons-fw branch
elupus authored
90 CAddonMgr::CAddonMgr()
91 {
639b314 changed: move addonbrowser to a mediawindow derivate
spiff_ authored
92 FindAddons();
93 m_watch.StartZero();
074db86 merged: addons-fw branch
elupus authored
94 }
95
96 CAddonMgr::~CAddonMgr()
97 {
1b2781c added: basic cpluff support
alcoheca authored
98 if(m_cpluff)
99 m_cpluff->destroy();
074db86 merged: addons-fw branch
elupus authored
100 }
101
102 CAddonMgr* CAddonMgr::Get()
103 {
104 if (!m_pInstance)
105 {
106 m_pInstance = new CAddonMgr();
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
107 m_pInstance->Init();
074db86 merged: addons-fw branch
elupus authored
108 }
109 return m_pInstance;
110 }
111
112 IAddonMgrCallback* CAddonMgr::GetCallbackForType(TYPE type)
113 {
114 if (m_managers.find(type) == m_managers.end())
115 return NULL;
116 else
117 return m_managers[type];
118 }
119
120 bool CAddonMgr::RegisterAddonMgrCallback(const TYPE type, IAddonMgrCallback* cb)
121 {
122 if (cb == NULL)
123 return false;
124
125 m_managers.erase(type);
126 m_managers[type] = cb;
127
128 return true;
129 }
130
131 void CAddonMgr::UnregisterAddonMgrCallback(TYPE type)
132 {
133 m_managers.erase(type);
134 }
135
1b2781c added: basic cpluff support
alcoheca authored
136 bool CAddonMgr::Init()
137 {
138 m_cpluff = new DllLibCPluff;
139 m_cpluff->Load();
140
141 if (!m_cpluff->IsLoaded())
142 {
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
143 CLog::Log(LOGERROR, "ADDONS: Fatal Error, could not load libcpluff");
144 return false;
1b2781c added: basic cpluff support
alcoheca authored
145 }
146
147 cp_log_severity_t log;
148 if (g_advancedSettings.m_logLevel >= LOG_LEVEL_DEBUG_SAMBA)
149 log = CP_LOG_DEBUG;
150 else if (g_advancedSettings.m_logLevel >= LOG_LEVEL_DEBUG)
151 log = CP_LOG_INFO;
152 else
153 log = CP_LOG_WARNING;
154 m_cpluff->set_fatal_error_handler(cp_fatalErrorHandler);
155
156 cp_status_t status;
157 status = m_cpluff->init();
158 if (status != CP_OK)
159 {
160 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_init() returned status: %i", status);
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
161 return false;
1b2781c added: basic cpluff support
alcoheca authored
162 }
163
164 //TODO could separate addons into different contexts
165 // would allow partial unloading of addon framework
166 m_cp_context = m_cpluff->create_context(&status);
167 assert(m_cp_context);
168 if (!CSpecialProtocol::XBMCIsHome())
169 {
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
170 status = m_cpluff->register_pcollection(m_cp_context, _P("special://home/addons"));
171 }
172 status = m_cpluff->register_pcollection(m_cp_context, _P("special://xbmc/addons"));
173 if (status != CP_OK)
174 {
175 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_pcollection() returned status: %i", status);
176 return false;
1b2781c added: basic cpluff support
alcoheca authored
177 }
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
178
5b793b6 added: missing change from r29798
alcoheca authored
179 status = m_cpluff->register_logger(m_cp_context, cp_logger, &CAddonMgr::m_pInstance, log);
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
180 if (status != CP_OK)
181 {
182 CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_logger() returned status: %i", status);
183 return false;
184 }
1b2781c added: basic cpluff support
alcoheca authored
185
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
186 status = m_cpluff->scan_plugins(m_cp_context, 0);
187 return true;
1b2781c added: basic cpluff support
alcoheca authored
188 }
189
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
190 bool CAddonMgr::HasAddons(const TYPE &type, const CONTENT_TYPE &content/*= CONTENT_NONE*/, bool enabledOnly/*= true*/)
074db86 merged: addons-fw branch
elupus authored
191 {
5ff028a added: skin support via cpluff
alcoheca authored
192 if (type == ADDON_SCREENSAVER || type == ADDON_SKIN)
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
193 {
194 cp_status_t status;
195 int num;
196 CStdString ext_point(TranslateType(type));
197 cp_extension_t **exts = m_cpluff->get_extensions_info(m_cp_context, ext_point.c_str(), &status, &num);
198 if (status == CP_OK)
199 return (num > 0);
200 }
201
af8cb2a Revert "wip"
alcoheca authored
202 if (m_addons.empty())
203 {
204 VECADDONS add;
205 GetAllAddons(add,false);
206 }
207
208 if (content == CONTENT_NONE)
209 return (m_addons.find(type) != m_addons.end());
074db86 merged: addons-fw branch
elupus authored
210
211 VECADDONS addons;
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
212 return GetAddons(type, addons, content, enabledOnly);
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
213
074db86 merged: addons-fw branch
elupus authored
214 }
215
216 bool CAddonMgr::GetAllAddons(VECADDONS &addons, bool enabledOnly/*= true*/)
217 {
af8cb2a Revert "wip"
alcoheca authored
218 VECADDONS temp;
219 if (CAddonMgr::Get()->GetAddons(ADDON_PLUGIN, temp, CONTENT_NONE, enabledOnly))
220 addons.insert(addons.end(), temp.begin(), temp.end());
221 if (CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, temp, CONTENT_NONE, enabledOnly))
222 addons.insert(addons.end(), temp.begin(), temp.end());
223 if (CAddonMgr::Get()->GetAddons(ADDON_SCREENSAVER, temp, CONTENT_NONE, enabledOnly))
224 addons.insert(addons.end(), temp.begin(), temp.end());
225 if (CAddonMgr::Get()->GetAddons(ADDON_SCRIPT, temp, CONTENT_NONE, enabledOnly))
226 addons.insert(addons.end(), temp.begin(), temp.end());
553d213 changed: finished moving skins to addon framework
alcoheca authored
227 if (CAddonMgr::Get()->GetAddons(ADDON_SKIN, temp, CONTENT_NONE, enabledOnly))
228 addons.insert(addons.end(), temp.begin(), temp.end());
af8cb2a Revert "wip"
alcoheca authored
229 if (CAddonMgr::Get()->GetAddons(ADDON_VIZ, temp, CONTENT_NONE, enabledOnly))
230 addons.insert(addons.end(), temp.begin(), temp.end());
231 return !addons.empty();
074db86 merged: addons-fw branch
elupus authored
232 }
233
234 bool CAddonMgr::GetAddons(const TYPE &type, VECADDONS &addons, const CONTENT_TYPE &content/*= CONTENT_NONE*/, bool enabledOnly/*= true*/)
235 {
4e5b98a added: locks to addon manager
spiff_ authored
236 CSingleLock lock(m_critSection);
af8cb2a Revert "wip"
alcoheca authored
237 addons.clear();
5ff028a added: skin support via cpluff
alcoheca authored
238 if (type == ADDON_SCREENSAVER || type == ADDON_SKIN)
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
239 {
240 cp_status_t status;
241 int num;
242 CStdString ext_point(TranslateType(type));
243 cp_extension_t **exts = m_cpluff->get_extensions_info(m_cp_context, ext_point.c_str(), &status, &num);
244 for(int i=0; i <num; i++)
245 {
246 AddonPtr addon(AddonFactory(exts[i]));
247 if (addon)
248 addons.push_back(addon);
249 }
250 m_cpluff->release_info(m_cp_context, exts);
251 return addons.size();
252 }
253
af8cb2a Revert "wip"
alcoheca authored
254 if (m_addons.find(type) != m_addons.end())
255 {
256 IVECADDONS itr = m_addons[type].begin();
257 while (itr != m_addons[type].end())
258 { // filter out what we're not looking for
dea84cb changed: Disabled() -> Enabled() - more intuitive
spiff_ authored
259 if ((enabledOnly && !(*itr)->Enabled())
af8cb2a Revert "wip"
alcoheca authored
260 || (content != CONTENT_NONE && !(*itr)->Supports(content)))
261 {
262 ++itr;
263 continue;
264 }
265 addons.push_back(*itr);
266 ++itr;
267 }
268 }
269 return !addons.empty();
074db86 merged: addons-fw branch
elupus authored
270 }
271
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
272 bool CAddonMgr::GetAddon(const CStdString &str, AddonPtr &addon, const TYPE &type/*=ADDON_UNKNOWN*/, bool enabledOnly/*= true*/)
074db86 merged: addons-fw branch
elupus authored
273 {
4e5b98a added: locks to addon manager
spiff_ authored
274 CSingleLock lock(m_critSection);
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
275 if (type != ADDON_UNKNOWN
276 && type != ADDON_SCREENSAVER
5ff028a added: skin support via cpluff
alcoheca authored
277 && type != ADDON_SKIN
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
278 && m_addons.find(type) == m_addons.end())
074db86 merged: addons-fw branch
elupus authored
279 return false;
280
23d8871 changed: support requesting cpluff addons without type. fixes crash in
alcoheca authored
281 cp_status_t status;
282 cp_plugin_info_t *cpaddon = NULL;
283 cpaddon = m_cpluff->get_plugin_info(m_cp_context, str.c_str(), &status);
284 if (status == CP_OK && cpaddon->extensions)
285 return (addon = AddonFactory(cpaddon->extensions));
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
286
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
287 if (m_idMap[str])
288 {
289 addon = m_idMap[str];
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
290 if(enabledOnly)
dea84cb changed: Disabled() -> Enabled() - more intuitive
spiff_ authored
291 return addon->Enabled();
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
292 else
293 return true;
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
294 }
074db86 merged: addons-fw branch
elupus authored
295
296 VECADDONS &addons = m_addons[type];
297 IVECADDONS adnItr = addons.begin();
298 while (adnItr != addons.end())
299 {
300 //FIXME scrapers were previously registered by filename
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
301 if ((*adnItr)->Name() == str || (type == ADDON_SCRAPER && (*adnItr)->LibName() == str))
074db86 merged: addons-fw branch
elupus authored
302 {
303 addon = (*adnItr);
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
304 if(enabledOnly)
dea84cb changed: Disabled() -> Enabled() - more intuitive
spiff_ authored
305 return addon->Enabled();
cc3b982 fixed: don't crash if an (visualization) addon is disabled
elupus authored
306 else
307 return true;
074db86 merged: addons-fw branch
elupus authored
308 }
309 adnItr++;
310 }
311
312 return false;
313 }
314
315 //TODO handle all 'default' cases here, not just scrapers & vizs
316 bool CAddonMgr::GetDefault(const TYPE &type, AddonPtr &addon, const CONTENT_TYPE &content)
317 {
318 if (type != ADDON_SCRAPER && type != ADDON_VIZ)
319 return false;
320
321 CStdString setting;
322 if (type == ADDON_VIZ)
323 setting = g_guiSettings.GetString("musicplayer.visualisation");
324 else
325 {
326 switch (content)
327 {
328 case CONTENT_MOVIES:
329 {
330 setting = g_guiSettings.GetString("scrapers.moviedefault");
331 break;
332 }
333 case CONTENT_TVSHOWS:
334 {
335 setting = g_guiSettings.GetString("scrapers.tvshowdefault");
336 break;
337 }
338 case CONTENT_MUSICVIDEOS:
339 {
340 setting = g_guiSettings.GetString("scrapers.musicvideodefault");
341 break;
342 }
343 case CONTENT_ALBUMS:
344 case CONTENT_ARTISTS:
345 {
346 setting = g_guiSettings.GetString("musiclibrary.scraper");
347 break;
348 }
349 default:
350 return false;
351 }
352 }
2ca76f9 changed: all addons should be store below either special://home/addon…
alcoheca authored
353 return GetAddon(setting, addon, type);
074db86 merged: addons-fw branch
elupus authored
354 }
355
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
356 CStdString CAddonMgr::GetString(const CStdString &id, const int number)
074db86 merged: addons-fw branch
elupus authored
357 {
7411555 changed: renamed UUID to ID. we now accept any string as an identifier,
alcoheca authored
358 AddonPtr addon = m_idMap[id];
074db86 merged: addons-fw branch
elupus authored
359 if (addon)
360 return addon->GetString(number);
361
362 return "";
363 }
364
af8cb2a Revert "wip"
alcoheca authored
365 void CAddonMgr::FindAddons()
366 {
4e5b98a added: locks to addon manager
spiff_ authored
367 CSingleLock lock(m_critSection);
639b314 changed: move addonbrowser to a mediawindow derivate
spiff_ authored
368 m_addons.clear();
369 m_idMap.clear();
c8f3bba fixed: dependency resolving
spiff_ authored
370
371 // store any addons with unresolved deps, then recheck at the end
372 map<CStdString, AddonPtr> unresolved;
373
28831ed fixed: don't check special://xbmc/addons twice when running with -p
alcoheca authored
374 if (!CSpecialProtocol::XBMCIsHome())
c8f3bba fixed: dependency resolving
spiff_ authored
375 LoadAddons("special://home/addons",unresolved);
376 LoadAddons("special://xbmc/addons",unresolved);
377
378 for (map<CStdString,AddonPtr>::iterator it = unresolved.begin();
379 it != unresolved.end(); ++it)
380 {
381 if (DependenciesMet(it->second))
382 {
383 if (!UpdateIfKnown(it->second))
384 {
385 m_addons[it->second->Type()].push_back(it->second);
386 m_idMap.insert(make_pair(it->first,it->second));
387 }
388 }
389 }
535b4e7 changed: load addons from user directory first, then load from system…
elupus authored
390 }
391
c8f3bba fixed: dependency resolving
spiff_ authored
392 void CAddonMgr::LoadAddons(const CStdString &path,
393 map<CStdString, AddonPtr>& unresolved)
535b4e7 changed: load addons from user directory first, then load from system…
elupus authored
394 {
af8cb2a Revert "wip"
alcoheca authored
395 // parse the user & system dirs for addons of the requested type
396 CFileItemList items;
535b4e7 changed: load addons from user directory first, then load from system…
elupus authored
397 CDirectory::GetDirectory(path, items);
af8cb2a Revert "wip"
alcoheca authored
398
399 // for all folders found
400 for (int i = 0; i < items.Size(); ++i)
401 {
402 CFileItemPtr item = items[i];
403
404 if(!item->m_bIsFolder)
405 continue;
406
407 // read description.xml and populate the addon
408 AddonPtr addon;
409 if (!AddonFromInfoXML(item->m_strPath, addon))
410 continue;
411
535b4e7 changed: load addons from user directory first, then load from system…
elupus authored
412 // only load if addon with same id isn't already loaded
c8f3bba fixed: dependency resolving
spiff_ authored
413 if(m_idMap.find(addon->ID()) != m_idMap.end() ||
414 unresolved.find(addon->ID()) != unresolved.end())
535b4e7 changed: load addons from user directory first, then load from system…
elupus authored
415 {
416 CLog::Log(LOGDEBUG, "ADDON: already loaded id %s, bypassing package", addon->ID().c_str());
417 continue;
418 }
419
af8cb2a Revert "wip"
alcoheca authored
420 // refuse to store addons with missing library
421 CStdString library(CUtil::AddFileToFolder(addon->Path(), addon->LibName()));
422 if (!CFile::Exists(library))
423 {
424 CLog::Log(LOGDEBUG, "ADDON: Missing library file %s, bypassing package", library.c_str());
425 continue;
426 }
427
428 if (!DependenciesMet(addon))
429 {
c8f3bba fixed: dependency resolving
spiff_ authored
430 unresolved.insert(make_pair(addon->ID(),addon));
af8cb2a Revert "wip"
alcoheca authored
431 continue;
432 }
433 else
434 { // everything ok, add to available addons if new
435 if (UpdateIfKnown(addon))
436 continue;
437 else
438 {
439 m_addons[addon->Type()].push_back(addon);
88e9b6f changed: expand std namespace
spiff_ authored
440 m_idMap.insert(make_pair(addon->ID(), addon));
af8cb2a Revert "wip"
alcoheca authored
441 }
442 }
443 }
444 }
445
446 bool CAddonMgr::UpdateIfKnown(AddonPtr &addon)
447 {
448 if (m_addons.find(addon->Type()) != m_addons.end())
449 {
450 for (unsigned i = 0; i < m_addons[addon->Type()].size(); i++)
451 {
452 if (m_addons[addon->Type()][i]->ID() == addon->ID())
453 {
454 //TODO inform any manager first, and request removal
455 //TODO choose most recent version if varying
456 m_addons[addon->Type()][i] = addon;
457 CStdString id = addon->ID();
458 m_idMap.erase(id);
88e9b6f changed: expand std namespace
spiff_ authored
459 m_idMap.insert(make_pair(addon->ID(), addon));
af8cb2a Revert "wip"
alcoheca authored
460 return true;
461 }
462 }
463 }
464 return false;
465 }
466
467 bool CAddonMgr::DependenciesMet(AddonPtr &addon)
468 {
469 if (!addon)
470 return false;
471
4e5b98a added: locks to addon manager
spiff_ authored
472 CSingleLock lock(m_critSection);
af8cb2a Revert "wip"
alcoheca authored
473 ADDONDEPS deps = addon->GetDeps();
474 ADDONDEPS::iterator itr = deps.begin();
475 while (itr != deps.end())
476 {
477 CStdString id;
478 id = (*itr).first;
479 AddonVersion min = (*itr).second.first;
480 AddonVersion max = (*itr).second.second;
481 if (m_idMap.count(id))
482 {
483 AddonPtr dep = m_idMap[id];
484 // we're guaranteed to have at least max OR min here
485 if (!min.str.IsEmpty() && !max.str.IsEmpty())
c8f3bba fixed: dependency resolving
spiff_ authored
486 {
487 if (dep->Version() < min || dep->Version() > max)
488 return false;
489 }
af8cb2a Revert "wip"
alcoheca authored
490 else if (!min.str.IsEmpty())
c8f3bba fixed: dependency resolving
spiff_ authored
491 {
492 if (dep->Version() < min)
493 return false;
494 }
af8cb2a Revert "wip"
alcoheca authored
495 else
c8f3bba fixed: dependency resolving
spiff_ authored
496 {
497 if (dep->Version() > max)
498 return false;
499 }
af8cb2a Revert "wip"
alcoheca authored
500 }
501 itr++;
502 }
c8f3bba fixed: dependency resolving
spiff_ authored
503 return true;
af8cb2a Revert "wip"
alcoheca authored
504 }
505
506 bool CAddonMgr::AddonFromInfoXML(const CStdString &path, AddonPtr &addon)
507 {
508 // First check that we can load description.xml
509 CStdString strPath(CUtil::AddFileToFolder(path, ADDON_METAFILE));
510 if(!CFile::Exists(strPath))
511 return false;
512
513 TiXmlDocument xmlDoc;
514 if (!xmlDoc.LoadFile(strPath))
515 {
516 CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", strPath.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc());
517 return false;
518 }
519
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
520 const TiXmlElement *element = xmlDoc.RootElement();
af8cb2a Revert "wip"
alcoheca authored
521 if (!element || strcmpi(element->Value(), "addoninfo") != 0)
522 {
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
523 CLog::Log(LOGERROR, "ADDON: Error loading %s: cannot find <addon> root element", xmlDoc.Value());
af8cb2a Revert "wip"
alcoheca authored
524 return false;
525 }
526
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
527 return AddonFromInfoXML(element, addon, strPath);
528 }
529
530 bool CAddonMgr::AddonFromInfoXML(const TiXmlElement *rootElement,
531 AddonPtr &addon, const CStdString &strPath)
532 {
af8cb2a Revert "wip"
alcoheca authored
533 /* Steps required to meet package requirements
534 * 1. id exists and is valid
535 * 2. type exists and is valid
536 * 3. version exists
537 * 4. a license is specified
538 * 5. operating system matches ours
539 * 6. summary exists
540 * 7. for scrapers & plugins, support at least one type of content
541 *
542 * NOTE: addon dependencies are handled in ::FindAddons()
543 */
544
545 /* Validate id */
546 CStdString id;
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
547 const TiXmlElement *element = rootElement->FirstChildElement("id");
af8cb2a Revert "wip"
alcoheca authored
548 if (!element)
549 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
550 CLog::Log(LOGERROR, "ADDON: %s missing <id> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
551 return false;
552 }
553 id = element->GetText();
554 //FIXME since we no longer required uuids, should we bother validating anything?
555 if (id.IsEmpty())
556 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
557 CLog::Log(LOGERROR, "ADDON: %s has invalid <id> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
558 return false;
559 }
560
561 /* Validate type */
562 TYPE type;
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
563 element = rootElement->FirstChildElement("type");
af8cb2a Revert "wip"
alcoheca authored
564 if (!element)
565 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
566 CLog::Log(LOGERROR, "ADDON: %s missing <type> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
567 return false;
568 }
569 type = TranslateType(element->GetText());
570 if (type == ADDON_UNKNOWN)
571 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
572 CLog::Log(LOGERROR, "ADDON: %s has invalid type identifier: '%d'", rootElement->GetDocument()->Value(), type);
af8cb2a Revert "wip"
alcoheca authored
573 return false;
574 }
575
576 /* Retrieve Name */
577 CStdString name;
822ca91 added: translatable <description>, <title>, <summary> and <disclaimer…
spiff_ authored
578 if (!GetTranslatedString(rootElement,"title",name))
af8cb2a Revert "wip"
alcoheca authored
579 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
580 CLog::Log(LOGERROR, "ADDON: %s missing <title> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
581 return false;
582 }
583
584 /* Retrieve version */
585 CStdString version;
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
586 element = rootElement->FirstChildElement("version");
af8cb2a Revert "wip"
alcoheca authored
587 if (!element)
588 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
589 CLog::Log(LOGERROR, "ADDON: %s missing <version> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
590 return false;
591 }
592 /* Validate version */
593 version = element->GetText();
594 CRegExp versionRE;
595 versionRE.RegComp(ADDON_VERSION_RE.c_str());
596 if (versionRE.RegFind(version.c_str()) != 0)
597 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
598 CLog::Log(LOGERROR, "ADDON: %s has invalid <version> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
599 return false;
600 }
601
602 /* Path, ID & Version are valid */
603 AddonProps addonProps(id, type, version);
604 addonProps.name = name;
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
605 CUtil::GetDirectory(strPath,addonProps.path);
a594abe changed: move addon thumbs back to a fixed image (icon.png). We stil…
jmarshallnz authored
606 /* Set Icon */
607 addonProps.icon = "icon.png";
e90479d added: addon changelog support
spiff_ authored
608 /* Set Changelog */
609 addonProps.changelog = CUtil::AddFileToFolder(addonProps.path,"changelog.txt");
d9e6ddf added: fanart support for addons
spiff_ authored
610 /* Set Fanart */
d3c62cd fixed: Addon changelogs weren't being read.
jmarshallnz authored
611 addonProps.fanart = CUtil::AddFileToFolder(addonProps.path,"fanart.jpg");
af8cb2a Revert "wip"
alcoheca authored
612
613 /* Retrieve license */
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
614 element = rootElement->FirstChildElement("license");
af8cb2a Revert "wip"
alcoheca authored
615 /* if (!element)
616 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
617 CLog::Log(LOGERROR, "ADDON: %s missing <license> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
618 return false;
619 }
620 addonProps.license = element->GetText();*/
621
622 /* Retrieve platforms which this addon supports */
623 CStdString platform;
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
624 element = rootElement->FirstChildElement("platforms")->FirstChildElement("platform");
af8cb2a Revert "wip"
alcoheca authored
625 if (!element)
626 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
627 CLog::Log(LOGERROR, "ADDON: %s missing <platforms> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
628 return false;
629 }
630
631 bool all(false);
88e9b6f changed: expand std namespace
spiff_ authored
632 set<CStdString> platforms;
af8cb2a Revert "wip"
alcoheca authored
633 do
634 {
635 CStdString platform = element->GetText();
636 if (platform == "all")
637 {
638 all = true;
639 break;
640 }
641 platforms.insert(platform);
642 element = element->NextSiblingElement("platform");
643 } while (element != NULL);
644
645 if (!all)
646 {
647 #if defined(_LINUX) && !defined(__APPLE__)
648 if (!platforms.count("linux"))
649 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
650 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Linux, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
651 return false;
652 }
78d5324 added: separate addon platforms for windows+dx and windows+opengl
spiff_ authored
653 #elif defined(_WIN32) && defined(HAS_SDL_OPENGL)
654 if (!platforms.count("windows-gl") && !platforms.count("windows"))
af8cb2a Revert "wip"
alcoheca authored
655 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
656 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Windows/OpenGL, ignoring", rootElement->GetDocument()->Value());
78d5324 added: separate addon platforms for windows+dx and windows+opengl
spiff_ authored
657 return false;
658 }
659 #elif defined(_WIN32) && defined(HAS_DX)
660 if (!platforms.count("windows-dx") && !platforms.count("windows"))
661 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
662 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Windows/DirectX, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
663 return false;
664 }
665 #elif defined(__APPLE__)
666 if (!platforms.count("osx"))
667 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
668 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under OSX, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
669 return false;
670 }
671 #elif defined(_XBOX)
672 if (!platforms.count("xbox"))
673 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
674 CLog::Log(LOGNOTICE, "ADDON: %s is not supported under XBOX, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
675 return false;
676 }
677 #endif
678 }
679
680 /* Retrieve summary */
d10c108 fixed: missing addon summary.
jmarshallnz authored
681 if (!GetTranslatedString(rootElement,"summary",addonProps.summary))
af8cb2a Revert "wip"
alcoheca authored
682 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
683 CLog::Log(LOGERROR, "ADDON: %s missing <summary> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
684 return false;
685 }
686
687 if (addonProps.type == ADDON_SCRAPER || addonProps.type == ADDON_PLUGIN)
688 {
689 /* Retrieve content types that this addon supports */
690 CStdString platform;
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
691 if (rootElement->FirstChildElement("supportedcontent"))
af8cb2a Revert "wip"
alcoheca authored
692 {
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
693 element = rootElement->FirstChildElement("supportedcontent")->FirstChildElement("content");
af8cb2a Revert "wip"
alcoheca authored
694 }
695 if (!element)
696 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
697 CLog::Log(LOGERROR, "ADDON: %s missing <supportedcontent> element, ignoring", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
698 return false;
699 }
700
88e9b6f changed: expand std namespace
spiff_ authored
701 set<CONTENT_TYPE> contents;
af8cb2a Revert "wip"
alcoheca authored
702 do
703 {
704 CONTENT_TYPE content = TranslateContent(element->GetText());
705 if (content != CONTENT_NONE)
706 {
707 contents.insert(content);
708 }
709 element = element->NextSiblingElement("content");
710 } while (element != NULL);
711
712 if (contents.empty())
713 {
714 CLog::Log(LOGERROR, "ADDON: %s %s supports no available content-types, ignoring", TranslateType(addonProps.type).c_str(), addonProps.name.c_str());
715 return false;
716 }
717 else
718 {
719 addonProps.contents = contents;
720 }
721 }
722
723 /*** Beginning of optional fields ***/
309adab changed: Read addon icon from the <icon> tag rather than assuming def…
jmarshallnz authored
724 /* Retrieve icon */
725 element = rootElement->FirstChildElement("icon");
726 if (element)
727 addonProps.icon = element->GetText();
728
af8cb2a Revert "wip"
alcoheca authored
729 /* Retrieve description */
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
730 element = rootElement->FirstChildElement("description");
822ca91 added: translatable <description>, <title>, <summary> and <disclaimer…
spiff_ authored
731 GetTranslatedString(rootElement,"description",addonProps.description);
af8cb2a Revert "wip"
alcoheca authored
732
733 /* Retrieve author */
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
734 element = rootElement->FirstChildElement("author");
af8cb2a Revert "wip"
alcoheca authored
735 if (element)
736 addonProps.author = element->GetText();
737
738 /* Retrieve disclaimer */
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
739 element = rootElement->FirstChildElement("disclaimer");
822ca91 added: translatable <description>, <title>, <summary> and <disclaimer…
spiff_ authored
740 GetTranslatedString(rootElement,"disclaimer",addonProps.disclaimer);
af8cb2a Revert "wip"
alcoheca authored
741
742 /* Retrieve library file name */
743 // will be replaced with default library name if unspecified
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
744 element = rootElement->FirstChildElement("library");
af8cb2a Revert "wip"
alcoheca authored
745 if (element)
746 addonProps.libname = element->GetText();
747
748 //TODO move this to addon specific class, if it's needed at all..
749 #ifdef _WIN32
750 /* Retrieve WIN32 library file name in case it is present
751 * This is required for no overwrite to the fixed WIN32 add-on's
752 * during compile time
753 */
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
754 element = rootElement->FirstChildElement("librarywin32");
af8cb2a Revert "wip"
alcoheca authored
755 if (element) // If it is found overwrite standard library name
756 addonProps.libname = element->GetText();
757 #endif
758
759 /* Retrieve dependencies that this addon requires */
4ccec44 changed: refactor addon info loading to make it reusable elsewhere
spiff_ authored
760 element = rootElement->FirstChildElement("dependencies");
af8cb2a Revert "wip"
alcoheca authored
761 if (element)
762 {
763 element = element->FirstChildElement("dependency");
764 if (!element)
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
765 CLog::Log(LOGDEBUG, "ADDON: %s missing at least one <dependency> element, will ignore this dependency", rootElement->GetDocument()->Value());
af8cb2a Revert "wip"
alcoheca authored
766 else
767 {
768 do
769 {
8a457f5 fixed: somebody must have had a blond moment - you can't check a stds…
spiff_ authored
770 const char* min = element->Attribute("minversion");
771 const char* max = element->Attribute("maxversion");
772 const char* id = element->GetText();
773 if (!id || (!min && !max))
af8cb2a Revert "wip"
alcoheca authored
774 {
349765e cleanup: Removed unnecessary code and changed logging code in addons …
jmarshallnz authored
775 CLog::Log(LOGDEBUG, "ADDON: %s malformed <dependency> element, will ignore this dependency", rootElement->GetDocument()->Value());
8a457f5 fixed: somebody must have had a blond moment - you can't check a stds…
spiff_ authored
776 element = element->NextSiblingElement("dependency");
af8cb2a Revert "wip"
alcoheca authored
777 continue;
778 }
8a457f5 fixed: somebody must have had a blond moment - you can't check a stds…
spiff_ authored
779 addonProps.dependencies.insert(make_pair(CStdString(id), make_pair(AddonVersion(min?min:""), AddonVersion(max?max:""))));
af8cb2a Revert "wip"
alcoheca authored
780 element = element->NextSiblingElement("dependency");
781 } while (element != NULL);
782 }
783 }
784
785 /*** end of optional fields ***/
786
787 /* Create an addon object and store in a shared_ptr */
eca3c5b changed: refactor
spiff_ authored
788 addon = AddonFromProps(addonProps);
789
790 return addon.get() != NULL;
791 }
792
822ca91 added: translatable <description>, <title>, <summary> and <disclaimer…
spiff_ authored
793 bool CAddonMgr::GetTranslatedString(const TiXmlElement *xmldoc, const char *tag, CStdString& data)
794 {
795 const TiXmlElement *element = xmldoc->FirstChildElement(tag);
796 const TiXmlElement *enelement = NULL;
797 while (element)
798 {
799 const char* lang = element->Attribute("lang");
800 if (lang && strcmp(lang,g_langInfo.GetDVDAudioLanguage().c_str()) == 0)
801 break;
802 if (!lang || strcmp(lang,"en") == 0)
803 enelement = element;
804 element = element->NextSiblingElement(tag);
805 }
806 if (!element)
807 element = enelement;
808 if (element)
809 data = element->GetText();
810
811 return element != NULL;
812 }
813
eca3c5b changed: refactor
spiff_ authored
814 AddonPtr CAddonMgr::AddonFromProps(AddonProps& addonProps)
815 {
816 switch (addonProps.type)
af8cb2a Revert "wip"
alcoheca authored
817 {
818 case ADDON_PLUGIN:
819 case ADDON_SCRIPT:
eca3c5b changed: refactor
spiff_ authored
820 return AddonPtr(new CAddon(addonProps));
af8cb2a Revert "wip"
alcoheca authored
821 case ADDON_SCRAPER:
eca3c5b changed: refactor
spiff_ authored
822 return AddonPtr(new CScraper(addonProps));
553d213 changed: finished moving skins to addon framework
alcoheca authored
823 case ADDON_SKIN:
824 return AddonPtr(new CSkinInfo(addonProps));
af8cb2a Revert "wip"
alcoheca authored
825 case ADDON_VIZ:
eca3c5b changed: refactor
spiff_ authored
826 return AddonPtr(new CVisualisation(addonProps));
af8cb2a Revert "wip"
alcoheca authored
827 case ADDON_SCREENSAVER:
eca3c5b changed: refactor
spiff_ authored
828 return AddonPtr(new CScreenSaver(addonProps));
af8cb2a Revert "wip"
alcoheca authored
829 case ADDON_SCRAPER_LIBRARY:
830 case ADDON_VIZ_LIBRARY:
6433385 added: script-library addon-type
spiff_ authored
831 case ADDON_SCRIPT_LIBRARY:
eca3c5b changed: refactor
spiff_ authored
832 return AddonPtr(new CAddonLibrary(addonProps));
606248f added: addon repository class
spiff_ authored
833 case ADDON_REPOSITORY:
834 return AddonPtr(new CRepository(addonProps));
af8cb2a Revert "wip"
alcoheca authored
835 default:
eca3c5b changed: refactor
spiff_ authored
836 break;
af8cb2a Revert "wip"
alcoheca authored
837 }
eca3c5b changed: refactor
spiff_ authored
838 return AddonPtr();
af8cb2a Revert "wip"
alcoheca authored
839 }
840
639b314 changed: move addonbrowser to a mediawindow derivate
spiff_ authored
841 void CAddonMgr::UpdateRepos()
842 {
843 CSingleLock lock(m_critSection);
844 if (m_watch.GetElapsedSeconds() < 600)
845 return;
846 m_watch.StartZero();
847 VECADDONS addons;
848 GetAddons(ADDON_REPOSITORY,addons);
849 for (unsigned int i=0;i<addons.size();++i)
850 {
851 RepositoryPtr repo = boost::dynamic_pointer_cast<CRepository>(addons[i]);
852 if (repo->LastUpdate()+CDateTimeSpan(0,6,0,0) < CDateTime::GetCurrentDateTime())
853 {
854 CLog::Log(LOGDEBUG,"Checking repository %s for updates",repo->Name().c_str());
9617e5e cosmetics
spiff_ authored
855 CJobManager::GetInstance().AddJob(new CRepositoryUpdateJob(repo),this);
639b314 changed: move addonbrowser to a mediawindow derivate
spiff_ authored
856 }
857 }
858 }
859
860 void CAddonMgr::OnJobComplete(unsigned int jobID, bool success, CJob* job)
861 {
862 if (!success)
863 return;
864
865 ((CRepositoryUpdateJob*)job)->m_repo->SetUpdated(CDateTime::GetCurrentDateTime());
866 }
867
1b2781c added: basic cpluff support
alcoheca authored
868 /*
869 * libcpluff interaction
870 */
871
b6076e5 changed: screensavers are now supported via cpluff schema
alcoheca authored
872 CStdString CAddonMgr::GetExtValue(cp_cfg_element_t *base, const char *path)
873 {
874 const char *value = NULL;
875 if (base && (value = m_cpluff->lookup_cfg_value(base, path)))
876 return CStdString(value);
877 else return CStdString();
878 }
879
1b2781c added: basic cpluff support
alcoheca authored
880 void CAddonMgr::CPluffFatalError(const char *msg)
881 {
882 CLog::Log(LOGERROR, "ADDONS: CPluffFatalError(%s)", msg);
883 }
884
885 int cp_to_clog(cp_log_severity_t lvl)
886 {
887 if( lvl == CP_LOG_DEBUG )
888 return 0;
889 else if (lvl == CP_LOG_INFO)
890 return 1;
891 else if (lvl == CP_LOG_WARNING)
892 return 3;
893 else
894 return 4;
895 }
896
897 cp_log_severity_t clog_to_cp(int lvl)
898 {
899 if (lvl >= 4)
900 return CP_LOG_ERROR;
901 else if (lvl == 3)
902 return CP_LOG_WARNING;
903 else if (lvl >= 1)
904 return CP_LOG_INFO;
905 else
906 return CP_LOG_DEBUG;
907 }
908
909 void CAddonMgr::CPluffLog(cp_log_severity_t level, const char *msg, const char *apid, void *user_data)
910 {
911 if(!apid)
5b793b6 added: missing change from r29798
alcoheca authored
912 CLog::Log(cp_to_clog(level), "ADDON: cpluff: '%s'", msg);
1b2781c added: basic cpluff support
alcoheca authored
913 else
5b793b6 added: missing change from r29798
alcoheca authored
914 CLog::Log(cp_to_clog(level), "ADDON: cpluff: '%s' reports '%s'", apid, msg);
1b2781c added: basic cpluff support
alcoheca authored
915 }
916
074db86 merged: addons-fw branch
elupus authored
917 } /* namespace ADDON */
918
Something went wrong with that request. Please try again.