2 * Copyright (C) 2005-2013 Team XBMC
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)
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.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 #include "AddonsDirectory.h"
23 #include "addons/AddonDatabase.h"
24 #include "DirectoryFactory.h"
25 #include "Directory.h"
26 #include "DirectoryCache.h"
28 #include "addons/Repository.h"
29 #include "addons/AddonInstaller.h"
30 #include "addons/PluginSource.h"
31 #include "guilib/TextureManager.h"
33 #include "SpecialProtocol.h"
34 #include "utils/URIUtils.h"
35 #include "utils/StringUtils.h"
38 using namespace ADDON;
43 CAddonsDirectory::CAddonsDirectory(void)
47 CAddonsDirectory::~CAddonsDirectory(void)
50 bool CAddonsDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items)
52 CStdString path1(strPath);
53 URIUtils::RemoveSlashAtEnd(path1);
55 items.ClearProperties();
57 items.SetContent("addons");
60 // get info from repository
61 bool groupAddons = true;
62 bool reposAsFolders = true;
63 if (path.GetHostName().Equals("enabled"))
65 CAddonMgr::Get().GetAllAddons(addons, true);
66 items.SetProperty("reponame",g_localizeStrings.Get(24062));
67 items.SetLabel(g_localizeStrings.Get(24062));
69 else if (path.GetHostName().Equals("disabled"))
70 { // grab all disabled addons, including disabled repositories
71 reposAsFolders = false;
73 CAddonMgr::Get().GetAllAddons(addons, false, true);
74 items.SetProperty("reponame",g_localizeStrings.Get(24039));
75 items.SetLabel(g_localizeStrings.Get(24039));
77 else if (path.GetHostName().Equals("outdated"))
79 reposAsFolders = false;
81 CAddonMgr::Get().GetAllOutdatedAddons(addons);
82 items.SetProperty("reponame",g_localizeStrings.Get(24043));
83 items.SetLabel(g_localizeStrings.Get(24043));
85 else if (path.GetHostName().Equals("repos"))
88 CAddonMgr::Get().GetAddons(ADDON_REPOSITORY,addons,true);
89 items.SetLabel(g_localizeStrings.Get(24033)); // Get Add-ons
91 else if (path.GetHostName().Equals("sources"))
93 return GetScriptsAndPlugins(path.GetFileName(), items);
95 else if (path.GetHostName().Equals("all"))
97 CAddonDatabase database;
99 database.GetAddons(addons);
100 items.SetProperty("reponame",g_localizeStrings.Get(24032));
101 items.SetLabel(g_localizeStrings.Get(24032));
103 else if (path.GetHostName().Equals("search"))
105 CStdString search(path.GetFileName());
106 if (search.empty() && !GetKeyboardInput(16017, search))
109 items.SetProperty("reponame",g_localizeStrings.Get(283));
110 items.SetLabel(g_localizeStrings.Get(283));
112 CAddonDatabase database;
114 database.Search(search, addons);
115 GenerateListing(path, addons, items, true);
117 path.SetFileName(search);
118 items.SetPath(path.Get());
123 reposAsFolders = false;
125 CAddonMgr::Get().GetAddon(path.GetHostName(),addon);
129 // ensure our repos are up to date
130 CAddonInstaller::Get().UpdateRepos(false, true);
131 CAddonDatabase database;
133 database.GetRepository(addon->ID(),addons);
134 items.SetProperty("reponame",addon->Name());
135 items.SetLabel(addon->Name());
138 if (path.GetFileName().empty())
142 for (int i=ADDON_UNKNOWN+1;i<ADDON_VIZ_LIBRARY;++i)
144 for (unsigned int j=0;j<addons.size();++j)
146 if (addons[j]->IsType((TYPE)i))
148 CFileItemPtr item(new CFileItem(TranslateType((TYPE)i,true)));
149 item->SetPath(URIUtils::AddFileToFolder(strPath,TranslateType((TYPE)i,false)));
150 item->m_bIsFolder = true;
151 CStdString thumb = GetIcon((TYPE)i);
152 if (!thumb.empty() && g_TextureManager.HasTexture(thumb))
153 item->SetArt("thumb", thumb);
159 items.SetPath(strPath);
165 TYPE type = TranslateType(path.GetFileName());
166 items.SetProperty("addoncategory",TranslateType(type, true));
167 items.SetLabel(TranslateType(type, true));
168 items.SetPath(strPath);
170 // FIXME: Categorisation of addons needs adding here
171 for (unsigned int j=0;j<addons.size();++j)
173 if (!addons[j]->IsType(type))
174 addons.erase(addons.begin()+j--);
178 items.SetPath(strPath);
179 GenerateListing(path, addons, items, reposAsFolders);
180 // check for available updates
181 if (path.GetHostName().Equals("enabled"))
183 CAddonDatabase database;
185 for (int i=0;i<items.Size();++i)
188 database.GetAddon(items[i]->GetProperty("Addon.ID").asString(),addon2);
189 if (addon2 && addon2->Version() > AddonVersion(items[i]->GetProperty("Addon.Version").asString())
190 && !database.IsAddonBlacklisted(addon2->ID(),addon2->Version().c_str()))
192 items[i]->SetProperty("Addon.Status",g_localizeStrings.Get(24068));
193 items[i]->SetProperty("Addon.UpdateAvail", true);
197 if (path.GetHostName().Equals("repos") && items.Size() > 1)
199 CFileItemPtr item(new CFileItem("addons://all/",true));
200 item->SetLabel(g_localizeStrings.Get(24032));
203 else if (path.GetHostName().Equals("outdated") && items.Size() > 1)
205 CFileItemPtr item(new CFileItem("addons://update_all/", true));
206 item->SetLabel(g_localizeStrings.Get(24122));
207 item->SetSpecialSort(SortSpecialOnTop);
214 void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders)
216 CStdString xbmcPath = CSpecialProtocol::TranslatePath("special://xbmc/addons");
218 for (unsigned i=0; i < addons.size(); i++)
220 AddonPtr addon = addons[i];
222 if (reposAsFolders && addon->Type() == ADDON_REPOSITORY)
223 pItem = FileItemFromAddon(addon, "addons://", true);
225 pItem = FileItemFromAddon(addon, path.Get(), false);
227 if (CAddonMgr::Get().GetAddon(addon->ID(),addon2))
228 pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305));
229 else if (CAddonMgr::Get().IsAddonDisabled(addon->ID()))
230 pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023));
232 if (addon->Props().broken == "DEPSNOTMET")
233 pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24049));
234 else if (!addon->Props().broken.empty())
235 pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098));
236 if (addon2 && addon2->Version() < addon->Version())
238 pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068));
239 pItem->SetProperty("Addon.UpdateAvail", true);
241 CAddonDatabase::SetPropertiesFromAddon(addon,pItem);
246 CFileItemPtr CAddonsDirectory::FileItemFromAddon(const AddonPtr &addon, const CStdString &basePath, bool folder)
249 return CFileItemPtr();
251 // TODO: This can probably be done more efficiently
253 url.SetFileName(addon->ID());
254 CStdString path(url.Get());
256 URIUtils::AddSlashAtEnd(path);
258 CFileItemPtr item(new CFileItem(path, folder));
260 CStdString strLabel(addon->Name());
261 if (url.GetHostName().Equals("search"))
262 strLabel = StringUtils::Format("%s - %s", TranslateType(addon->Type(), true).c_str(), addon->Name().c_str());
264 item->SetLabel(strLabel);
266 if (!(basePath.Equals("addons://") && addon->Type() == ADDON_REPOSITORY))
267 item->SetLabel2(addon->Version().c_str());
268 item->SetArt("thumb", addon->Icon());
269 item->SetLabelPreformated(true);
270 item->SetIconImage("DefaultAddon.png");
271 if (URIUtils::IsInternetStream(addon->FanArt()) || CFile::Exists(addon->FanArt()))
272 item->SetArt("fanart", addon->FanArt());
273 CAddonDatabase::SetPropertiesFromAddon(addon, item);
277 bool CAddonsDirectory::GetScriptsAndPlugins(const CStdString &content, VECADDONS &addons)
279 CPluginSource::Content type = CPluginSource::Translate(content);
280 if (type == CPluginSource::UNKNOWN)
283 VECADDONS tempAddons;
284 CAddonMgr::Get().GetAddons(ADDON_PLUGIN, tempAddons);
285 for (unsigned i=0; i<tempAddons.size(); i++)
287 PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(tempAddons[i]);
288 if (plugin && plugin->Provides(type))
289 addons.push_back(tempAddons[i]);
292 CAddonMgr::Get().GetAddons(ADDON_SCRIPT, tempAddons);
293 for (unsigned i=0; i<tempAddons.size(); i++)
295 PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(tempAddons[i]);
296 if (plugin && plugin->Provides(type))
297 addons.push_back(tempAddons[i]);
302 bool CAddonsDirectory::GetScriptsAndPlugins(const CStdString &content, CFileItemList &items)
307 if (!GetScriptsAndPlugins(content, addons))
310 for (unsigned i=0; i<addons.size(); i++)
312 CFileItemPtr item(FileItemFromAddon(addons[i],
313 addons[i]->Type()==ADDON_PLUGIN?"plugin://":"script://",
314 addons[i]->Type() == ADDON_PLUGIN));
315 PluginPtr plugin = boost::dynamic_pointer_cast<CPluginSource>(addons[i]);
316 if (plugin->ProvidesSeveral())
318 CURL url = item->GetAsUrl();
319 CStdString opt = StringUtils::Format("?content_type=%s",content.c_str());
321 item->SetPath(url.Get());
326 items.Add(GetMoreItem(content));
328 items.SetContent("addons");
329 items.SetLabel(g_localizeStrings.Get(24001)); // Add-ons
331 return items.Size() > 0;
334 CFileItemPtr CAddonsDirectory::GetMoreItem(const CStdString &content)
336 CFileItemPtr item(new CFileItem("addons://more/"+content,false));
337 item->SetLabelPreformated(true);
338 item->SetLabel(g_localizeStrings.Get(21452));
339 item->SetIconImage("DefaultAddon.png");
340 item->SetSpecialSort(SortSpecialOnBottom);