bool CAddonInstaller::DoInstall(const AddonPtr &addon, const CStdString &hash, bool update, const CStdString &referer, bool background) { // check whether we already have the addon installing CSingleLock lock(m_critSection); if (m_downloadJobs.find(addon->ID()) != m_downloadJobs.end()) return false; // check whether all the dependencies are available or not // TODO: we currently assume that dependencies will install correctly (and each of their dependencies and so on). // it may be better to install the dependencies first to minimise the chance of an addon becoming orphaned due to // missing deps. if (!CheckDependencies(addon)) { CGUIDialogKaiToast::QueueNotification(addon->Icon(), addon->Name(), g_localizeStrings.Get(24044), TOAST_DISPLAY_TIME, false); return false; } if (background) { unsigned int jobID = CJobManager::GetInstance().AddJob(new CAddonInstallJob(addon, hash, update, referer), this); m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(jobID))); } else { m_downloadJobs.insert(make_pair(addon->ID(), CDownloadJob(0))); lock.Leave(); CAddonInstallJob job(addon, hash, update, referer); if (!job.DoWork()) { // TODO: dump something to debug log? return false; } lock.Enter(); JobMap::iterator i = m_downloadJobs.find(addon->ID()); m_downloadJobs.erase(i); } return true; }
void CAddonInstallJob::ReportInstallError(const CStdString& addonID, const CStdString& fileName) { AddonPtr addon; CAddonDatabase database; database.Open(); database.GetAddon(addonID, addon); if (addon) { AddonPtr addon2; CAddonMgr::Get().GetAddon(addonID, addon2); CGUIDialogKaiToast::QueueNotification(addon->Icon(), addon->Name(), g_localizeStrings.Get(addon2 ? 113 : 114), TOAST_DISPLAY_TIME, false); } else { CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Error, fileName, g_localizeStrings.Get(114), TOAST_DISPLAY_TIME, false); } }
void CGUIDialogAddonInfo::OnUpdate() { if (!m_localAddon) return; CAddonDatabase database; if (!database.Open()) return; std::vector<std::pair<AddonVersion, std::string>> versions; if (!database.GetAvailableVersions(m_localAddon->ID(), versions)) return; CFileItemList items; if (XFILE::CDirectory::GetDirectory("special://home/addons/packages/", items, ".zip", DIR_FLAG_NO_FILE_DIRS)) { for (int i = 0; i < items.Size(); ++i) { std::string packageId; std::string versionString; if (AddonVersion::SplitFileName(packageId, versionString, items[i]->GetLabel())) { if (packageId == m_localAddon->ID()) { std::string hash; std::string path(items[i]->GetPath()); if (database.GetPackageHash(m_localAddon->ID(), items[i]->GetPath(), hash)) { std::string md5 = CUtil::GetFileMD5(path); if (md5 == hash) versions.push_back(std::make_pair(AddonVersion(versionString), LOCAL_CACHE)); } } } } } if (versions.empty()) { CGUIDialogOK::ShowAndGetInput(CVariant{21341}, CVariant{21342}); return; } auto* dialog = static_cast<CGUIDialogSelect*>(g_windowManager.GetWindow(WINDOW_DIALOG_SELECT)); dialog->Reset(); dialog->SetHeading(CVariant{21338}); dialog->SetUseDetails(true); std::stable_sort(versions.begin(), versions.end(), CompareVersion); for (const auto& versionInfo : versions) { CFileItem item(StringUtils::Format(g_localizeStrings.Get(21339).c_str(), versionInfo.first.asString().c_str())); if (versionInfo.first == m_localAddon->Version()) item.Select(true); AddonPtr repo; if (versionInfo.second == LOCAL_CACHE) { item.SetProperty("Addon.Summary", g_localizeStrings.Get(24095)); item.SetIconImage("DefaultAddonRepository.png"); dialog->Add(item); } else if (CAddonMgr::GetInstance().GetAddon(versionInfo.second, repo, ADDON_REPOSITORY)) { item.SetProperty("Addon.Summary", repo->Name()); item.SetIconImage(repo->Icon()); dialog->Add(item); } } dialog->Open(); if (dialog->IsConfirmed()) { Close(); auto selected = versions.at(dialog->GetSelectedLabel()); //turn auto updating off if downgrading if (selected.first < m_localAddon->Version()) CAddonMgr::GetInstance().AddToUpdateBlacklist(m_localAddon->ID()); if (selected.second == LOCAL_CACHE) CAddonInstaller::GetInstance().InstallFromZip(StringUtils::Format("special://home/addons/packages/%s-%s.zip", m_localAddon->ID().c_str(), selected.first.asString().c_str())); else CAddonInstaller::GetInstance().Install(m_addon->ID(), selected.first, selected.second); } }
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; }