bool CAddonMgr::GetAllOutdatedAddons(VECADDONS &addons, bool enabled /*= true*/) { CSingleLock lock(m_critSection); for (int i = ADDON_UNKNOWN+1; i < ADDON_VIZ_LIBRARY; ++i) { VECADDONS temp; if (CAddonMgr::Get().GetAddons((TYPE)i, temp, enabled)) { AddonPtr repoAddon; for (unsigned int j = 0; j < temp.size(); j++) { // Ignore duplicates due to add-ons with multiple extension points bool found = false; for (VECADDONS::const_iterator addonIt = addons.begin(); addonIt != addons.end(); addonIt++) { if ((*addonIt)->ID() == temp[j]->ID()) found = true; } if (found || !m_database.GetAddon(temp[j]->ID(), repoAddon)) continue; if (temp[j]->Version() < repoAddon->Version() && !m_database.IsAddonBlacklisted(temp[j]->ID(), repoAddon->Version().c_str())) addons.push_back(repoAddon); } } } return !addons.empty(); }
bool CAddonInstallJob::Install(const CStdString &installFrom) { CStdString addonFolder(installFrom); URIUtils::RemoveSlashAtEnd(addonFolder); addonFolder = URIUtils::AddFileToFolder("special://home/addons/", URIUtils::GetFileName(addonFolder)); CFileItemList install; install.Add(CFileItemPtr(new CFileItem(installFrom, true))); install[0]->Select(true); CFileOperationJob job(CFileOperationJob::ActionReplace, install, "special://home/addons/"); AddonPtr addon; if (!job.DoWork() || !CAddonMgr::Get().LoadAddonDescription(addonFolder, addon)) { // failed extraction or failed to load addon description CStdString addonID = URIUtils::GetFileName(addonFolder); ReportInstallError(addonID, addonID); CLog::Log(LOGERROR,"Could not read addon description of %s", addonID.c_str()); DeleteAddon(addonFolder); return false; } // resolve dependencies CAddonMgr::Get().FindAddons(); // needed as GetDeps() grabs directly from c-pluff via the addon manager ADDONDEPS deps = addon->GetDeps(); CStdString referer; referer.Format("Referer=%s-%s.zip",addon->ID().c_str(),addon->Version().c_str()); for (ADDONDEPS::iterator it = deps.begin(); it != deps.end(); ++it) { if (it->first.Equals("xbmc.metadata")) continue; AddonPtr dependency; if (!CAddonMgr::Get().GetAddon(it->first,dependency) || dependency->Version() < it->second.first) { bool force=(dependency != NULL); // dependency is already queued up for install - ::Install will fail // instead we wait until the Job has finished. note that we // recall install on purpose in case prior installation failed if (CAddonInstaller::Get().HasJob(it->first)) { while (CAddonInstaller::Get().HasJob(it->first)) Sleep(50); force = false; } // don't have the addon or the addon isn't new enough - grab it (no new job for these) if (!CAddonInstaller::Get().Install(it->first, force, referer, false)) { DeleteAddon(addonFolder); return false; } } } return true; }
CFileItemPtr CAddonsDirectory::FileItemFromAddon(AddonPtr &addon, const CStdString &basePath, bool folder) { if (!addon) return CFileItemPtr(); // TODO: This can probably be done more efficiently CURL url(basePath); url.SetFileName(addon->ID()); CStdString path(url.Get()); if (folder) URIUtils::AddSlashAtEnd(path); CFileItemPtr item(new CFileItem(path, folder)); CStdString strLabel(addon->Name()); if (url.GetHostName().Equals("search")) strLabel.Format("%s - %s", TranslateType(addon->Type(), true), addon->Name()); item->SetLabel(strLabel); if (!(basePath.Equals("addons://") && addon->Type() == ADDON_REPOSITORY)) item->SetLabel2(addon->Version().c_str()); item->SetArt("thumb", addon->Icon()); item->SetLabelPreformated(true); item->SetIconImage("DefaultAddon.png"); if (!addon->FanArt().IsEmpty() && (URIUtils::IsInternetStream(addon->FanArt()) || CFile::Exists(addon->FanArt()))) { item->SetArt("fanart", addon->FanArt()); } CAddonDatabase::SetPropertiesFromAddon(addon, item); return item; }
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon, CFileItemPtr& pItem) { pItem->SetProperty("Addon.ID", addon->ID()); pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true)); pItem->SetProperty("Addon.intType", TranslateType(addon->Type())); pItem->SetProperty("Addon.Name", addon->Name()); pItem->SetProperty("Addon.Version", addon->Version().asString()); pItem->SetProperty("Addon.Summary", addon->Summary()); pItem->SetProperty("Addon.Description", addon->Description()); pItem->SetProperty("Addon.Creator", addon->Author()); pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); pItem->SetProperty("Addon.Rating", addon->Stars()); std::string starrating = StringUtils::Format("rating%d.png", addon->Stars()); pItem->SetProperty("Addon.StarRating",starrating); pItem->SetProperty("Addon.Path", addon->Path()); if (addon->Props().broken == "DEPSNOTMET") pItem->SetProperty("Addon.Broken", g_localizeStrings.Get(24044)); else pItem->SetProperty("Addon.Broken", addon->Props().broken); std::map<std::string,std::string>::iterator it = addon->Props().extrainfo.find("language"); if (it != addon->Props().extrainfo.end()) pItem->SetProperty("Addon.Language", it->second); }
void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders) { CStdString xbmcPath = _P("special://xbmc/addons"); items.ClearItems(); for (unsigned i=0; i < addons.size(); i++) { AddonPtr addon = addons[i]; CFileItemPtr pItem; if (reposAsFolders && addon->Type() == ADDON_REPOSITORY) pItem = FileItemFromAddon(addon, "addons://", true); else pItem = FileItemFromAddon(addon, path.Get(), false); AddonPtr addon2; if (CAddonMgr::Get().GetAddon(addon->ID(),addon2)) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305)); else if ((addon->Type() == ADDON_PVRDLL) && (CStdString(pItem->GetProperty("Addon.Path").asString()).Left(xbmcPath.size()).Equals(xbmcPath))) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023)); if (!addon->Props().broken.IsEmpty()) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098)); if (addon2 && addon2->Version() < addon->Version()) { pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); pItem->SetProperty("Addon.UpdateAvail", true); } CAddonDatabase::SetPropertiesFromAddon(addon,pItem); items.Add(pItem); } }
void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders) { CStdString xbmcPath = CSpecialProtocol::TranslatePath("special://xbmc/addons"); items.ClearItems(); CAddonDatabase db; db.Open(); for (unsigned i=0; i < addons.size(); i++) { AddonPtr addon = addons[i]; CFileItemPtr pItem; if (reposAsFolders && addon->Type() == ADDON_REPOSITORY) pItem = FileItemFromAddon(addon, "addons://", true); else pItem = FileItemFromAddon(addon, path.Get(), false); AddonPtr addon2; if (CAddonMgr::Get().GetAddon(addon->ID(),addon2)) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305)); else if (db.IsOpen() && db.IsAddonDisabled(addon->ID())) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023)); if (!addon->Props().broken.IsEmpty()) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098)); if (addon2 && addon2->Version() < addon->Version()) { pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); pItem->SetProperty("Addon.UpdateAvail", true); } CAddonDatabase::SetPropertiesFromAddon(addon,pItem); items.Add(pItem); } db.Close(); }
void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items, bool reposAsFolders) { items.ClearItems(); for (unsigned i=0; i < addons.size(); i++) { AddonPtr addon = addons[i]; CFileItemPtr pItem; if (reposAsFolders && addon->Type() == ADDON_REPOSITORY) pItem = FileItemFromAddon(addon, "addons://", true); else pItem = FileItemFromAddon(addon, path.Get(), false); AddonPtr addon2; if (CAddonMgr::Get().GetAddon(addon->ID(),addon2)) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(305)); else if (CAddonMgr::Get().IsAddonDisabled(addon->ID())) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24023)); if (addon->Props().broken == "DEPSNOTMET") pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24049)); else if (!addon->Props().broken.empty()) pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24098)); if (addon2 && addon2->Version() < addon->Version()) { pItem->SetProperty("Addon.Status",g_localizeStrings.Get(24068)); pItem->SetProperty("Addon.UpdateAvail", true); } CAddonDatabase::SetPropertiesFromAddon(addon,pItem); items.Add(pItem); } }
std::unique_ptr<CRepository> CRepository::FromExtension(CAddonInfo addonInfo, const cp_extension_t* ext) { DirList dirs; AddonVersion version("0.0.0"); AddonPtr addonver; if (CServiceBroker::GetAddonMgr().GetAddon("xbmc.addon", addonver)) version = addonver->Version(); for (size_t i = 0; i < ext->configuration->num_children; ++i) { cp_cfg_element_t* element = &ext->configuration->children[i]; if(element->name && strcmp(element->name, "dir") == 0) { DirInfo dir = ParseDirConfiguration(element); if (dir.version <= version) { dirs.push_back(std::move(dir)); } } } if (!CServiceBroker::GetAddonMgr().GetExtValue(ext->configuration, "info").empty()) { dirs.push_back(ParseDirConfiguration(ext->configuration)); } return std::unique_ptr<CRepository>(new CRepository(std::move(addonInfo), std::move(dirs))); }
bool CRepositoryUpdateJob::DoWork() { CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] checking for updates.", m_repo->ID().c_str()); CAddonDatabase database; database.Open(); std::string oldChecksum; if (database.GetRepoChecksum(m_repo->ID(), oldChecksum) == -1) oldChecksum = ""; std::string newChecksum; VECADDONS addons; auto status = m_repo->FetchIfChanged(oldChecksum, newChecksum, addons); database.SetLastChecked(m_repo->ID(), m_repo->Version(), CDateTime::GetCurrentDateTime().GetAsDBDateTime()); MarkFinished(); if (status == CRepository::STATUS_ERROR) return false; if (status == CRepository::STATUS_NOT_MODIFIED) { CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] checksum not changed.", m_repo->ID().c_str()); return true; } //Invalidate art. { CTextureDatabase textureDB; textureDB.Open(); textureDB.BeginMultipleExecute(); for (const auto& addon : addons) { AddonPtr oldAddon; if (database.GetAddon(addon->ID(), oldAddon) && addon->Version() > oldAddon->Version()) { if (!oldAddon->Icon().empty() || !oldAddon->Art().empty() || !oldAddon->Screenshots().empty()) CLog::Log(LOGDEBUG, "CRepository: invalidating cached art for '%s'", addon->ID().c_str()); if (!oldAddon->Icon().empty()) textureDB.InvalidateCachedTexture(oldAddon->Icon()); for (const auto& path : oldAddon->Screenshots()) textureDB.InvalidateCachedTexture(path); for (const auto& art : oldAddon->Art()) textureDB.InvalidateCachedTexture(art.second); } } textureDB.CommitMultipleExecute(); } database.UpdateRepositoryContent(m_repo->ID(), m_repo->Version(), newChecksum, addons); return true; }
int CAddonDatabase::AddAddon(const AddonPtr& addon, int idRepo) { try { if (NULL == m_pDB.get()) return -1; if (NULL == m_pDS.get()) return -1; bool bDisablePVRAddon = addon->Type() == ADDON_PVRDLL && !HasAddon(addon->ID()); CStdString sql = PrepareSQL("insert into addon (id, type, name, summary," "description, stars, path, icon, changelog, " "fanart, addonID, version, author, disclaimer, minversion)" " values(NULL, '%s', '%s', '%s', '%s', %i," "'%s', '%s', '%s', '%s', '%s','%s','%s','%s','%s')", TranslateType(addon->Type(),false).c_str(), addon->Name().c_str(), addon->Summary().c_str(), addon->Description().c_str(),addon->Stars(), addon->Path().c_str(), addon->Props().icon.c_str(), addon->ChangeLog().c_str(),addon->FanArt().c_str(), addon->ID().c_str(), addon->Version().c_str(), addon->Author().c_str(),addon->Disclaimer().c_str(), addon->MinVersion().c_str()); m_pDS->exec(sql.c_str()); int idAddon = (int)m_pDS->lastinsertid(); sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon); m_pDS->exec(sql.c_str()); const InfoMap &info = addon->ExtraInfo(); for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i) { sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str()); m_pDS->exec(sql.c_str()); } const ADDONDEPS &deps = addon->GetDeps(); for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i) { sql = PrepareSQL("insert into dependencies(id, addon, version, optional) values (%i, '%s', '%s', %i)", idAddon, i->first.c_str(), i->second.first.c_str(), i->second.second ? 1 : 0); m_pDS->exec(sql.c_str()); } // these need to be configured if (bDisablePVRAddon) DisableAddon(addon->ID(), true); return idAddon; } catch (...) { CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str()); } return -1; }
bool CAddonMgr::GetAllOutdatedAddons(VECADDONS &addons, bool enabled /*= true*/) { CSingleLock lock(m_critSection); for (int i = ADDON_UNKNOWN+1; i < ADDON_VIZ_LIBRARY; ++i) { VECADDONS temp; if (CAddonMgr::Get().GetAddons((TYPE)i, temp, enabled)) { AddonPtr repoAddon; for (unsigned int j = 0; j < temp.size(); j++) { if (!m_database.GetAddon(temp[j]->ID(), repoAddon)) continue; if (temp[j]->Version() < repoAddon->Version() && !m_database.IsAddonBlacklisted(temp[j]->ID(), repoAddon->Version().c_str())) addons.push_back(repoAddon); } } } return !addons.empty(); }
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon, CFileItemPtr& pItem) { pItem->SetProperty("Addon.ID", addon->ID()); pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true)); pItem->SetProperty("Addon.intType", TranslateType(addon->Type())); pItem->SetProperty("Addon.Name", addon->Name()); pItem->SetProperty("Addon.Version", addon->Version().c_str()); pItem->SetProperty("Addon.Summary", addon->Summary()); pItem->SetProperty("Addon.Description", addon->Description()); pItem->SetProperty("Addon.Creator", addon->Author()); pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); pItem->SetProperty("Addon.Rating", addon->Stars()); CStdString starrating; starrating.Format("rating%d.png", addon->Stars()); pItem->SetProperty("Addon.StarRating",starrating); pItem->SetProperty("Addon.Path", addon->Path()); pItem->SetProperty("Addon.Broken", addon->Props().broken); }
int CAddonDatabase::AddAddon(const AddonPtr& addon, int idRepo) { try { if (NULL == m_pDB.get()) return -1; if (NULL == m_pDS.get()) return -1; CStdString sql = PrepareSQL("insert into addon (id, type, name, summary," "description, stars, path, icon, changelog, " "fanart, addonID, version, author, disclaimer)" " values(NULL, '%s', '%s', '%s', '%s', %i," "'%s', '%s', '%s', '%s', '%s','%s','%s','%s')", TranslateType(addon->Type(),false).c_str(), addon->Name().c_str(), addon->Summary().c_str(), addon->Description().c_str(),addon->Stars(), addon->Path().c_str(), addon->Props().icon.c_str(), addon->ChangeLog().c_str(),addon->FanArt().c_str(), addon->ID().c_str(), addon->Version().str.c_str(), addon->Author().c_str(),addon->Disclaimer().c_str()); m_pDS->exec(sql.c_str()); int idAddon = (int)m_pDS->lastinsertid(); sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon); m_pDS->exec(sql.c_str()); const InfoMap &info = addon->ExtraInfo(); for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i) { sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str()); m_pDS->exec(sql.c_str()); } return idAddon; } catch (...) { CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str()); } return -1; }
bool CAddonInstallJob::Install(const CStdString &installFrom) { CStdString addonFolder(installFrom); URIUtils::RemoveSlashAtEnd(addonFolder); addonFolder = URIUtils::AddFileToFolder("special://home/addons/", URIUtils::GetFileName(addonFolder)); CFileItemList install; install.Add(CFileItemPtr(new CFileItem(installFrom, true))); install[0]->Select(true); CFileOperationJob job(CFileOperationJob::ActionReplace, install, "special://home/addons/"); AddonPtr addon; if (!job.DoWork() || !CAddonMgr::Get().LoadAddonDescription(addonFolder, addon)) { // failed extraction or failed to load addon description CStdString addonID = URIUtils::GetFileName(addonFolder); ReportInstallError(addonID, addonID); CLog::Log(LOGERROR,"Could not read addon description of %s", addonID.c_str()); CFileItemList list; list.Add(CFileItemPtr(new CFileItem(addonFolder, true))); list[0]->Select(true); CJobManager::GetInstance().AddJob(new CFileOperationJob(CFileOperationJob::ActionDelete, list, ""), NULL); return false; } // resolve dependencies ADDONDEPS deps = addon->GetDeps(); CStdString referer; referer.Format("Referer=%s-%s.zip",addon->ID().c_str(),addon->Version().str.c_str()); for (ADDONDEPS::iterator it = deps.begin(); it != deps.end(); ++it) { if (it->first.Equals("xbmc.metadata")) continue; AddonPtr dependency; if (!CAddonMgr::Get().GetAddon(it->first,dependency)) CAddonInstaller::Get().Install(it->first, false, referer, false); // no new job for these } return true; }
static CVariant Serialize(const AddonPtr& addon) { CVariant variant; variant["addonid"] = addon->ID(); variant["type"] = CAddonInfo::TranslateType(addon->Type(), false); variant["name"] = addon->Name(); variant["version"] = addon->Version().asString(); variant["summary"] = addon->Summary(); variant["description"] = addon->Description(); variant["path"] = addon->Path(); variant["author"] = addon->Author(); variant["thumbnail"] = addon->Icon(); variant["disclaimer"] = addon->Disclaimer(); variant["fanart"] = addon->FanArt(); variant["dependencies"] = CVariant(CVariant::VariantTypeArray); for (const auto& dep : addon->GetDependencies()) { CVariant info(CVariant::VariantTypeObject); info["addonid"] = dep.id; info["version"] = dep.requiredVersion.asString(); info["optional"] = dep.optional; variant["dependencies"].push_back(std::move(info)); } if (addon->Broken().empty()) variant["broken"] = false; else variant["broken"] = addon->Broken(); variant["extrainfo"] = CVariant(CVariant::VariantTypeArray); for (const auto& kv : addon->ExtraInfo()) { CVariant info(CVariant::VariantTypeObject); info["key"] = kv.first; info["value"] = kv.second; variant["extrainfo"].push_back(std::move(info)); } variant["rating"] = -1; return variant; }
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon, CFileItemPtr& pItem) { pItem->SetProperty("Addon.ID", addon->ID()); pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true)); pItem->SetProperty("Addon.intType", TranslateType(addon->Type())); pItem->SetProperty("Addon.Name", addon->Name()); pItem->SetProperty("Addon.Version", addon->Version().c_str()); pItem->SetProperty("Addon.Summary", addon->Summary()); pItem->SetProperty("Addon.Description", addon->Description()); pItem->SetProperty("Addon.Creator", addon->Author()); pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); pItem->SetProperty("Addon.Rating", addon->Stars()); CStdString starrating; starrating.Format("rating%d.png", addon->Stars()); pItem->SetProperty("Addon.StarRating",starrating); pItem->SetProperty("Addon.Path", addon->Path()); pItem->SetProperty("Addon.Broken", addon->Props().broken); std::map<CStdString,CStdString>::iterator it = addon->Props().extrainfo.find("language"); if (it != addon->Props().extrainfo.end()) pItem->SetProperty("Addon.Language", it->second); }
std::unique_ptr<CRepository> CRepository::FromExtension(CAddonInfo addonInfo, const cp_extension_t* ext) { DirList dirs; AddonVersion version("0.0.0"); AddonPtr addonver; if (CServiceBroker::GetAddonMgr().GetAddon("xbmc.addon", addonver)) version = addonver->Version(); for (size_t i = 0; i < ext->configuration->num_children; ++i) { if(ext->configuration->children[i].name && strcmp(ext->configuration->children[i].name, "dir") == 0) { AddonVersion min_version(CServiceBroker::GetAddonMgr().GetExtValue(&ext->configuration->children[i], "@minversion")); if (min_version <= version) { DirInfo dir; dir.version = min_version; dir.checksum = CServiceBroker::GetAddonMgr().GetExtValue(&ext->configuration->children[i], "checksum"); dir.info = CServiceBroker::GetAddonMgr().GetExtValue(&ext->configuration->children[i], "info"); dir.datadir = CServiceBroker::GetAddonMgr().GetExtValue(&ext->configuration->children[i], "datadir"); dir.hashes = CServiceBroker::GetAddonMgr().GetExtValue(&ext->configuration->children[i], "hashes") == "true"; dirs.push_back(std::move(dir)); } } } if (!CServiceBroker::GetAddonMgr().GetExtValue(ext->configuration, "info").empty()) { DirInfo info; info.checksum = CServiceBroker::GetAddonMgr().GetExtValue(ext->configuration, "checksum"); info.info = CServiceBroker::GetAddonMgr().GetExtValue(ext->configuration, "info"); info.datadir = CServiceBroker::GetAddonMgr().GetExtValue(ext->configuration, "datadir"); info.hashes = CServiceBroker::GetAddonMgr().GetExtValue(ext->configuration, "hashes") == "true"; dirs.push_back(std::move(info)); } return std::unique_ptr<CRepository>(new CRepository(std::move(addonInfo), std::move(dirs))); }
bool CRepositoryUpdateJob::DoWork() { CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] checking for updates.", m_repo->ID().c_str()); CAddonDatabase database; database.Open(); std::string oldChecksum; if (database.GetRepoChecksum(m_repo->ID(), oldChecksum) == -1) oldChecksum = ""; std::string newChecksum; VECADDONS addons; auto status = m_repo->FetchIfChanged(oldChecksum, newChecksum, addons); database.SetLastChecked(m_repo->ID(), m_repo->Version(), CDateTime::GetCurrentDateTime().GetAsDBDateTime()); MarkFinished(); if (status == CRepository::STATUS_ERROR) return false; if (status == CRepository::STATUS_NOT_MODIFIED) { CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] checksum not changed.", m_repo->ID().c_str()); return true; } //Invalidate art. { CTextureDatabase textureDB; textureDB.Open(); textureDB.BeginMultipleExecute(); for (const auto& addon : addons) { AddonPtr oldAddon; if (database.GetAddon(addon->ID(), oldAddon) && addon->Version() > oldAddon->Version()) { if (!oldAddon->Icon().empty() || !oldAddon->FanArt().empty() || !oldAddon->Screenshots().empty()) CLog::Log(LOGDEBUG, "CRepository: invalidating cached art for '%s'", addon->ID().c_str()); if (!oldAddon->Icon().empty()) textureDB.InvalidateCachedTexture(oldAddon->Icon()); if (!oldAddon->FanArt().empty()) textureDB.InvalidateCachedTexture(oldAddon->Icon()); for (const auto& path : oldAddon->Screenshots()) textureDB.InvalidateCachedTexture(path); } } textureDB.CommitMultipleExecute(); } database.UpdateRepositoryContent(m_repo->ID(), m_repo->Version(), newChecksum, addons); //Notify about broken status changes for (const auto& addon : addons) { AddonPtr localAddon; if (!CAddonMgr::GetInstance().GetAddon(addon->ID(), localAddon)) continue; if (localAddon && localAddon->Version() > addon->Version()) //We have a newer version locally continue; AddonPtr oldAddon; database.GetAddon(addon->ID(), oldAddon); if (database.GetAddonVersion(addon->ID()).first > addon->Version()) //Newer version in db (ie. in a different repo) continue; std::string broken = addon->Broken(); bool isBroken = !addon->Broken().empty(); bool isBrokenInDb = oldAddon && !oldAddon->Broken().empty(); if (isBroken && !isBrokenInDb) { //newly broken if (HELPERS::ShowYesNoDialogLines(CVariant{addon->Name()}, CVariant{24096}, CVariant{24097}, CVariant{""}) == DialogResponse::YES) { CAddonMgr::GetInstance().DisableAddon(addon->ID()); } CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' marked broken. reason: \"%s\"", m_repo->ID().c_str(), addon->ID().c_str(), broken.c_str()); CEventLog::GetInstance().Add(EventPtr(new CAddonManagementEvent(addon, 24096))); } else if (!isBroken && isBrokenInDb) { //Unbroken CLog::Log(LOGDEBUG, "CRepositoryUpdateJob[%s] addon '%s' unbroken", m_repo->ID().c_str(), addon->ID().c_str()); } } return true; }