~ubuntu-branches/debian/sid/kodi/sid

« back to all changes in this revision

Viewing changes to xbmc/addons/AddonManager.cpp

  • Committer: Package Import Robot
  • Author(s): Balint Reczey
  • Date: 2015-08-18 14:16:59 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20150818141659-4lgq2pksj7918osz
Tags: 15.1+dfsg1-1
* New upstream release 15.0
  See http://www.kodi.tv/kodi-15-0-isengard-one-release-to-rule-them-all/
* Depend on libav.*-dev provided by src:ffmpeg
* Recommend udisks2 instead of udisks.
  Udisks has been removed from unstable but support for udisks2 is not
  implemented yet.
* Ship patch helping Jessie backports
* Refresh patches
* Eliminate __DATE__ macros from source to make build more reproducible
* Build-depend on libsdl2.*-dev instead of libsdl.*-dev
* Build-depend on libgif-dev
* Drop obsoleted fix of installed header's include paths
* Refresh include file list included by kodi-addons-dev
* Build depend on libcec (>= 3)
* Build-depend on groovy2 instead of groovy
* Sort build dependencies
* Fix packaging repository URL
* Remove removed files from debian/copyright
* Fix filenames with spaces in debian/copyright
* Ship TexturePacker in kodi-addons-dev in /usr/lib/kodi
* Build depend on libcec-platform-dev
* Stop using embedded gnulib modules in rsxs screensaver (Closes: #795813)
* Add missing copyright paragraphs to d/copyright
* Stop marking files as excluded which are removed from upstream tarball
  already
* Bump standards version to 3.9.6
* New upstream release 15.1
  See http://kodi.tv/kodi-15-1-isengard-maintenance-release/
* Move TexturePacker to kodi-bin
* Stop building TexturePacker statically

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 *  <http://www.gnu.org/licenses/>.
18
18
 *
19
19
 */
 
20
#include <memory>
20
21
#include "AddonManager.h"
21
22
#include "Addon.h"
22
23
#include "AudioEncoder.h"
 
24
#include "AudioDecoder.h"
 
25
#include "ContextMenuManager.h"
23
26
#include "DllLibCPluff.h"
 
27
#include "LanguageResource.h"
 
28
#include "UISoundsResource.h"
24
29
#include "utils/StringUtils.h"
25
30
#include "utils/JobManager.h"
26
31
#include "threads/SingleLock.h"
27
 
#include "FileItem.h"
28
32
#include "LangInfo.h"
29
33
#include "settings/AdvancedSettings.h"
30
34
#include "settings/Settings.h"
37
41
#include "ScreenSaver.h"
38
42
#endif
39
43
#ifdef HAS_PVRCLIENTS
40
 
#include "DllPVRClient.h"
41
44
#include "pvr/addons/PVRClient.h"
42
45
#endif
43
46
//#ifdef HAS_SCRAPERS
47
50
#include "Repository.h"
48
51
#include "Skin.h"
49
52
#include "Service.h"
 
53
#include "ContextItemAddon.h"
50
54
#include "Util.h"
 
55
#include "addons/Webinterface.h"
51
56
 
52
57
using namespace std;
53
58
using namespace XFILE;
86
91
    case ADDON_SCRIPT_LYRICS:
87
92
    case ADDON_SCRIPT_MODULE:
88
93
    case ADDON_SUBTITLE_MODULE:
89
 
    case ADDON_WEB_INTERFACE:
90
94
      return AddonPtr(new CAddon(props));
 
95
    case ADDON_WEB_INTERFACE:
 
96
      return AddonPtr(new CWebinterface(props));
91
97
    case ADDON_SCRIPT_WEATHER:
92
98
      {
93
99
        // Eden (API v2.0) broke old weather add-ons
114
120
    case ADDON_SCREENSAVER:
115
121
    case ADDON_PVRDLL:
116
122
    case ADDON_AUDIOENCODER:
 
123
    case ADDON_AUDIODECODER:
117
124
      { // begin temporary platform handling for Dlls
118
125
        // ideally platforms issues will be handled by C-Pluff
119
126
        // this is not an attempt at a solution
138
145
          tograb = "@library_android";
139
146
#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
140
147
          tograb = "@library_linux";
141
 
#elif defined(TARGET_WINDOWS) && defined(HAS_SDL_OPENGL)
142
 
          tograb = "@library_wingl";
143
148
#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
144
149
          tograb = "@library_windx";
145
150
#elif defined(TARGET_DARWIN)
162
167
        }
163
168
        else if (type == ADDON_AUDIOENCODER)
164
169
          return AddonPtr(new CAudioEncoder(props));
 
170
        else if (type == ADDON_AUDIODECODER)
 
171
          return AddonPtr(new CAudioDecoder(props));
165
172
        else
166
173
          return AddonPtr(new CScreenSaver(props));
167
174
      }
168
175
    case ADDON_SKIN:
169
176
      return AddonPtr(new CSkinInfo(props));
 
177
    case ADDON_RESOURCE_LANGUAGE:
 
178
      return AddonPtr(new CLanguageResource(props));
 
179
    case ADDON_RESOURCE_UISOUNDS:
 
180
      return AddonPtr(new CUISoundsResource(props));
170
181
    case ADDON_VIZ_LIBRARY:
171
182
      return AddonPtr(new CAddonLibrary(props));
172
183
    case ADDON_REPOSITORY:
173
184
      return AddonPtr(new CRepository(props));
 
185
    case ADDON_CONTEXT_ITEM:
 
186
      return AddonPtr(new CContextItemAddon(props));
174
187
    default:
175
188
      break;
176
189
  }
208
221
}
209
222
 
210
223
CAddonMgr::CAddonMgr()
211
 
{
212
 
  m_cpluff = NULL;
213
 
}
 
224
  : m_cp_context(nullptr),
 
225
  m_cpluff(nullptr)
 
226
{ }
214
227
 
215
228
CAddonMgr::~CAddonMgr()
216
229
{
275
288
  m_cp_context = m_cpluff->create_context(&status);
276
289
  assert(m_cp_context);
277
290
  status = m_cpluff->register_pcollection(m_cp_context, CSpecialProtocol::TranslatePath("special://home/addons").c_str());
 
291
  if (status != CP_OK)
 
292
  {
 
293
    CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_pcollection() returned status: %i", status);
 
294
    return false;
 
295
  }
 
296
 
278
297
  status = m_cpluff->register_pcollection(m_cp_context, CSpecialProtocol::TranslatePath("special://xbmc/addons").c_str());
 
298
  if (status != CP_OK)
 
299
  {
 
300
    CLog::Log(LOGERROR, "ADDONS: Fatal Error, cp_register_pcollection() returned status: %i", status);
 
301
    return false;
 
302
  }
 
303
 
279
304
  status = m_cpluff->register_pcollection(m_cp_context, CSpecialProtocol::TranslatePath("special://xbmcbin/addons").c_str());
280
305
  if (status != CP_OK)
281
306
  {
293
318
 
294
319
  FindAddons();
295
320
 
 
321
  // disable some system addons by default because they are optional
 
322
  VECADDONS addons;
 
323
  GetAddons(ADDON_PVRDLL, addons);
 
324
  GetAddons(ADDON_AUDIODECODER, addons);
 
325
  std::string systemAddonsPath = CSpecialProtocol::TranslatePath("special://xbmc/addons");
 
326
  for (auto &addon : addons)
 
327
  {
 
328
    if (StringUtils::StartsWith(addon->Path(), systemAddonsPath))
 
329
    {
 
330
      if (!m_database.IsSystemAddonRegistered(addon->ID()))
 
331
      {
 
332
        m_database.DisableAddon(addon->ID());
 
333
        m_database.AddSystemAddon(addon->ID());
 
334
      }
 
335
    }
 
336
  }
 
337
 
 
338
  std::vector<std::string> disabled;
 
339
  m_database.GetDisabled(disabled);
 
340
  m_disabled.insert(disabled.begin(), disabled.end());
 
341
 
296
342
  VECADDONS repos;
297
343
  if (GetAddons(ADDON_REPOSITORY, repos))
298
344
  {
322
368
  return GetAddons(type, addons, enabled);
323
369
}
324
370
 
325
 
bool CAddonMgr::GetAllAddons(VECADDONS &addons, bool enabled /*= true*/, bool allowRepos /* = false */)
 
371
bool CAddonMgr::GetAllAddons(VECADDONS &addons, bool enabled /*= true*/)
326
372
{
327
 
  for (int i = ADDON_UNKNOWN+1; i < ADDON_MAX; ++i)
 
373
  CSingleLock lock(m_critSection);
 
374
  if (!m_cp_context)
 
375
    return false;
 
376
 
 
377
  cp_status_t status;
 
378
  int num;
 
379
  cp_plugin_info_t **cpaddons = m_cpluff->get_plugins_info(m_cp_context, &status, &num);
 
380
 
 
381
  for (int i = 0; i < num; ++i)
328
382
  {
329
 
    if (!allowRepos && ADDON_REPOSITORY == (TYPE)i)
330
 
      continue;
331
 
    VECADDONS temp;
332
 
    if (CAddonMgr::Get().GetAddons((TYPE)i, temp, enabled))
333
 
      addons.insert(addons.end(), temp.begin(), temp.end());
 
383
    const cp_plugin_info_t *cpaddon = cpaddons[i];
 
384
    if (cpaddon->extensions && IsAddonDisabled(cpaddon->identifier) != enabled)
 
385
    {
 
386
      //Get the first extension only
 
387
      AddonPtr addon = Factory(&cpaddon->extensions[0]);
 
388
      if (addon)
 
389
      {
 
390
        if (enabled)
 
391
        {
 
392
          // if the addon has a running instance, grab that
 
393
          AddonPtr runningAddon = addon->GetRunningInstance();
 
394
          if (runningAddon)
 
395
            addon = runningAddon;
 
396
        }
 
397
        addons.push_back(addon);
 
398
      }
 
399
    }
334
400
  }
 
401
  m_cpluff->release_info(m_cp_context, cpaddons);
335
402
  return !addons.empty();
336
403
}
337
404
 
391
458
      {
392
459
        // Ignore duplicates due to add-ons with multiple extension points
393
460
        bool found = false;
394
 
        for (VECADDONS::const_iterator addonIt = addons.begin(); addonIt != addons.end(); addonIt++)
 
461
        for (VECADDONS::const_iterator addonIt = addons.begin(); addonIt != addons.end(); ++addonIt)
395
462
        {
396
463
          if ((*addonIt)->ID() == temp[j]->ID())
397
464
            found = true;
423
490
bool CAddonMgr::GetAddons(const TYPE &type, VECADDONS &addons, bool enabled /* = true */)
424
491
{
425
492
  CSingleLock lock(m_critSection);
426
 
  addons.clear();
427
493
  if (!m_cp_context)
428
494
    return false;
429
495
  cp_status_t status;
512
578
  case ADDON_WEB_INTERFACE:
513
579
    setting = CSettings::Get().GetString("services.webskin");
514
580
    break;
 
581
  case ADDON_RESOURCE_LANGUAGE:
 
582
    setting = CSettings::Get().GetString("locale.language");
 
583
    break;
515
584
  default:
516
585
    return false;
517
586
  }
543
612
  case ADDON_SCRAPER_TVSHOWS:
544
613
    CSettings::Get().SetString("scrapers.tvshowsdefault",addonID);
545
614
    break;
 
615
  case ADDON_RESOURCE_LANGUAGE:
 
616
    CSettings::Get().SetString("locale.language", addonID);
 
617
    break;
546
618
  default:
547
619
    return false;
548
620
  }
572
644
  NotifyObservers(ObservableMessageAddons);
573
645
}
574
646
 
575
 
void CAddonMgr::RemoveAddon(const std::string& ID)
 
647
void CAddonMgr::UnregisterAddon(const std::string& ID)
576
648
{
 
649
  CSingleLock lock(m_critSection);
 
650
  m_disabled.erase(ID);
577
651
  if (m_cpluff && m_cp_context)
578
652
  {
579
 
    m_cpluff->uninstall_plugin(m_cp_context,ID.c_str());
 
653
    m_cpluff->uninstall_plugin(m_cp_context, ID.c_str());
580
654
    SetChanged();
 
655
    lock.Leave();
581
656
    NotifyObservers(ObservableMessageAddons);
582
657
  }
583
658
}
584
659
 
585
 
bool CAddonMgr::DisableAddon(const std::string& ID, bool disable)
586
 
{
587
 
  CSingleLock lock(m_critSection);
588
 
  if (m_database.DisableAddon(ID, disable))
589
 
  {
590
 
    m_disabled[ID] = disable;
591
 
    return true;
592
 
  }
593
 
 
594
 
  return false;
 
660
bool CAddonMgr::DisableAddon(const std::string& id)
 
661
{
 
662
  CSingleLock lock(m_critSection);
 
663
  if (m_disabled.find(id) != m_disabled.end())
 
664
    return true; //already disabled
 
665
 
 
666
  if (!CanAddonBeDisabled(id))
 
667
    return false;
 
668
  if (!m_database.DisableAddon(id))
 
669
    return false;
 
670
  if (!m_disabled.insert(id).second)
 
671
    return false;
 
672
 
 
673
  //success
 
674
  ADDON::OnDisabled(id);
 
675
  return true;
 
676
}
 
677
 
 
678
bool CAddonMgr::EnableAddon(const std::string& id)
 
679
{
 
680
  CSingleLock lock(m_critSection);
 
681
  if (m_disabled.find(id) == m_disabled.end())
 
682
    return true; //already enabled
 
683
 
 
684
  if (!m_database.DisableAddon(id, false))
 
685
    return false;
 
686
  if (m_disabled.erase(id) == 0)
 
687
    return false;
 
688
 
 
689
  //success
 
690
  ADDON::OnEnabled(id);
 
691
  return true;
595
692
}
596
693
 
597
694
bool CAddonMgr::IsAddonDisabled(const std::string& ID)
598
695
{
599
696
  CSingleLock lock(m_critSection);
600
 
  std::map<std::string, bool>::const_iterator it = m_disabled.find(ID);
601
 
  if (it != m_disabled.end())
602
 
    return it->second;
603
 
 
604
 
  bool ret = m_database.IsAddonDisabled(ID);
605
 
  m_disabled.insert(pair<std::string, bool>(ID, ret));
606
 
 
607
 
  return ret;
 
697
  return m_disabled.find(ID) != m_disabled.end();
 
698
}
 
699
 
 
700
bool CAddonMgr::CanAddonBeDisabled(const std::string& ID)
 
701
{
 
702
  if (ID.empty())
 
703
    return false;
 
704
 
 
705
  CSingleLock lock(m_critSection);
 
706
  AddonPtr localAddon;
 
707
  // can't disable an addon that isn't installed
 
708
  if (!GetAddon(ID, localAddon, ADDON_UNKNOWN, false))
 
709
    return false;
 
710
 
 
711
  // can't disable an addon that is in use
 
712
  if (localAddon->IsInUse())
 
713
    return false;
 
714
 
 
715
  // installed PVR addons can always be disabled
 
716
  if (localAddon->Type() == ADDON_PVRDLL)
 
717
    return true;
 
718
 
 
719
  // installed audio decoder addons can always be disabled
 
720
  if (localAddon->Type() == ADDON_AUDIODECODER)
 
721
    return true;
 
722
 
 
723
  // installed audio encoder addons can always be disabled
 
724
  if (localAddon->Type() == ADDON_AUDIOENCODER)
 
725
    return true;
 
726
 
 
727
  std::string systemAddonsPath = CSpecialProtocol::TranslatePath("special://xbmc/addons");
 
728
  // can't disable system addons
 
729
  if (StringUtils::StartsWith(localAddon->Path(), systemAddonsPath))
 
730
    return false;
 
731
 
 
732
  return true;
 
733
}
 
734
 
 
735
bool CAddonMgr::IsAddonInstalled(const std::string& ID)
 
736
{
 
737
  AddonPtr tmp;
 
738
  return GetAddon(ID, tmp, ADDON_UNKNOWN, false);
 
739
}
 
740
 
 
741
bool CAddonMgr::CanAddonBeInstalled(const std::string& ID)
 
742
{
 
743
  if (ID.empty())
 
744
    return false;
 
745
 
 
746
  CSingleLock lock(m_critSection);
 
747
  // can't install already installed addon
 
748
  if (IsAddonInstalled(ID))
 
749
    return false;
 
750
 
 
751
  // can't install broken addons
 
752
  if (!m_database.IsAddonBroken(ID).empty())
 
753
    return false;
 
754
 
 
755
  return true;
 
756
}
 
757
 
 
758
bool CAddonMgr::CanAddonBeInstalled(const AddonPtr& addon)
 
759
{
 
760
  if (addon == NULL)
 
761
    return false;
 
762
 
 
763
  CSingleLock lock(m_critSection);
 
764
  // can't install already installed addon
 
765
  if (IsAddonInstalled(addon->ID()))
 
766
    return false;
 
767
 
 
768
  // can't install broken addons
 
769
  if (!addon->Props().broken.empty())
 
770
    return false;
 
771
 
 
772
  return true;
608
773
}
609
774
 
610
775
std::string CAddonMgr::GetTranslatedString(const cp_cfg_element_t *root, const char *tag)
612
777
  if (!root)
613
778
    return "";
614
779
 
615
 
  const cp_cfg_element_t *eng = NULL;
 
780
  std::map<std::string, std::string> translatedValues;
616
781
  for (unsigned int i = 0; i < root->num_children; i++)
617
782
  {
618
783
    const cp_cfg_element_t &child = root->children[i];
619
784
    if (strcmp(tag, child.name) == 0)
620
 
    { // see if we have a "lang" attribute
 
785
    {
 
786
      // see if we have a "lang" attribute
621
787
      const char *lang = m_cpluff->lookup_cfg_value((cp_cfg_element_t*)&child, "@lang");
622
 
      if (lang && 0 == strcmp(lang,g_langInfo.GetLanguageLocale(true).c_str()))
623
 
        return child.value ? child.value : "";
624
 
      if (!lang || 0 == strcmp(lang, "en"))
625
 
        eng = &child;
 
788
      if (lang != NULL && g_langInfo.GetLocale().Matches(lang))
 
789
        translatedValues.insert(std::make_pair(lang, child.value != NULL ? child.value : ""));
 
790
      else if (lang == NULL || strcmp(lang, "en") == 0 || strcmp(lang, "en_GB") == 0)
 
791
        translatedValues.insert(std::make_pair("en_GB", child.value != NULL ? child.value : ""));
626
792
    }
627
793
  }
628
 
  return (eng && eng->value) ? eng->value : "";
 
794
 
 
795
  // put together a list of languages
 
796
  std::set<std::string> languages;
 
797
  for (auto const& translatedValue : translatedValues)
 
798
    languages.insert(translatedValue.first);
 
799
 
 
800
  // find the language from the list that matches the current locale best
 
801
  std::string matchingLanguage = g_langInfo.GetLocale().FindBestMatch(languages);
 
802
  if (matchingLanguage.empty())
 
803
    matchingLanguage = "en_GB";
 
804
 
 
805
  auto const& translatedValue = translatedValues.find(matchingLanguage);
 
806
  if (translatedValue != translatedValues.end())
 
807
    return translatedValue->second;
 
808
 
 
809
  return "";
629
810
}
630
811
 
631
812
AddonPtr CAddonMgr::AddonFromProps(AddonProps& addonProps)
640
821
    case ADDON_SCRIPT_WEATHER:
641
822
    case ADDON_SCRIPT_MODULE:
642
823
    case ADDON_SUBTITLE_MODULE:
643
 
    case ADDON_WEB_INTERFACE:
644
824
      return AddonPtr(new CAddon(addonProps));
 
825
    case ADDON_WEB_INTERFACE:
 
826
      return AddonPtr(new CWebinterface(addonProps));
645
827
    case ADDON_SERVICE:
646
828
      return AddonPtr(new CService(addonProps));
647
829
    case ADDON_SCRAPER_ALBUMS:
665
847
      return AddonPtr(new PVR::CPVRClient(addonProps));
666
848
    case ADDON_AUDIOENCODER:
667
849
      return AddonPtr(new CAudioEncoder(addonProps));
 
850
    case ADDON_AUDIODECODER:
 
851
      return AddonPtr(new CAudioDecoder(addonProps));
 
852
    case ADDON_RESOURCE_LANGUAGE:
 
853
      return AddonPtr(new CLanguageResource(addonProps));
 
854
    case ADDON_RESOURCE_UISOUNDS:
 
855
      return AddonPtr(new CUISoundsResource(addonProps));
668
856
    case ADDON_REPOSITORY:
669
857
      return AddonPtr(new CRepository(addonProps));
 
858
    case ADDON_CONTEXT_ITEM:
 
859
      return AddonPtr(new CContextItemAddon(addonProps));
670
860
    default:
671
861
      break;
672
862
  }
681
871
{
682
872
  if (!plugin || !plugin->num_extensions)
683
873
    return false;
684
 
  const cp_extension_t *metadata = GetExtension(plugin, "xbmc.addon.metadata");
 
874
  const cp_extension_t *metadata = GetExtension(plugin, "xbmc.addon.metadata"); //<! backword compatibilty
 
875
  if (!metadata)
 
876
    metadata = CAddonMgr::Get().GetExtension(plugin, "kodi.addon.metadata");
685
877
  if (!metadata)
686
878
    return false;
687
879
 
696
888
      if (*platform == "android")
697
889
#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD)
698
890
      if (*platform == "linux")
699
 
#elif defined(TARGET_WINDOWS) && defined(HAS_SDL_OPENGL)
700
 
      if (*platform == "wingl")
701
891
#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
702
892
      if (*platform == "windx")
703
893
#elif defined(TARGET_DARWIN_OSX)
718
908
  return true; // assume no <platform> is equivalent to <platform>all</platform>
719
909
}
720
910
 
721
 
const cp_cfg_element_t *CAddonMgr::GetExtElement(cp_cfg_element_t *base, const char *path)
 
911
cp_cfg_element_t *CAddonMgr::GetExtElement(cp_cfg_element_t *base, const char *path)
722
912
{
723
 
  const cp_cfg_element_t *element = NULL;
 
913
  cp_cfg_element_t *element = NULL;
724
914
  if (base)
725
915
    element = m_cpluff->lookup_cfg_element(base, path);
726
916
  return element;
785
975
    return AddonPtr(new CAddon(info));
786
976
  }
787
977
 
788
 
  // grab a relevant extension point, ignoring our xbmc.addon.metadata extension point
 
978
  // grab a relevant extension point, ignoring our kodi.addon.metadata extension point
789
979
  for (unsigned int i = 0; i < info->num_extensions; ++i)
790
980
  {
791
 
    if (0 != strcmp("xbmc.addon.metadata", info->extensions[i].ext_point_id) &&
 
981
    if (0 != strcmp("xbmc.addon.metadata" , info->extensions[i].ext_point_id) && //<! backword compatibilty
 
982
        0 != strcmp("kodi.addon.metadata" , info->extensions[i].ext_point_id) &&
792
983
        (type.empty() || 0 == strcmp(type.c_str(), info->extensions[i].ext_point_id)))
793
984
    { // note that Factory takes care of whether or not we have platform support
794
985
      return Factory(&info->extensions[i]);
876
1067
  bool ret = true;
877
1068
  for (IVECADDONS it = services.begin(); it != services.end(); ++it)
878
1069
  {
879
 
    boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(*it);
 
1070
    std::shared_ptr<CService> service = std::dynamic_pointer_cast<CService>(*it);
880
1071
    if (service)
881
1072
    {
882
1073
      if ( (beforelogin && service->GetStartOption() == CService::STARTUP)
898
1089
 
899
1090
  for (IVECADDONS it = services.begin(); it != services.end(); ++it)
900
1091
  {
901
 
    boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(*it);
 
1092
    std::shared_ptr<CService> service = std::dynamic_pointer_cast<CService>(*it);
902
1093
    if (service)
903
1094
    {
904
1095
      if ( (onlylogin && service->GetStartOption() == CService::LOGIN)