Skip to content

HTTPS clone URL

Subversion checkout URL

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