diff --git a/xbmc/addons/AddonInstaller.cpp b/xbmc/addons/AddonInstaller.cpp index 5c67125ed1a73..45f9af9511bd6 100644 --- a/xbmc/addons/AddonInstaller.cpp +++ b/xbmc/addons/AddonInstaller.cpp @@ -21,10 +21,12 @@ #include "AddonInstaller.h" #include "Service.h" #include "utils/log.h" +#include "utils/FileUtils.h" #include "utils/URIUtils.h" #include "Util.h" #include "guilib/LocalizeStrings.h" #include "filesystem/Directory.h" +#include "settings/AdvancedSettings.h" #include "settings/GUISettings.h" #include "settings/Settings.h" #include "ApplicationMessenger.h" @@ -84,6 +86,7 @@ void CAddonInstaller::OnJobComplete(unsigned int jobID, bool success, CJob* job) JobMap::iterator i = find_if(m_downloadJobs.begin(), m_downloadJobs.end(), bind2nd(find_map(), jobID)); if (i != m_downloadJobs.end()) m_downloadJobs.erase(i); + PrunePackageCache(); } lock.Leave(); @@ -381,6 +384,75 @@ bool CAddonInstaller::HasJob(const CStdString& ID) const return m_downloadJobs.find(ID) != m_downloadJobs.end(); } +void CAddonInstaller::PrunePackageCache() +{ + std::map packs; + int64_t size = EnumeratePackageFolder(packs); + if (size < g_advancedSettings.m_addonPackageFolderSize) + return; + + // Prune packages + // 1. Remove the largest packages, leaving at least 2 for each add-on + CFileItemList items; + for (std::map::const_iterator it = packs.begin(); + it != packs.end();++it) + { + it->second->Sort(SORT_METHOD_LABEL,SortOrderDescending); + for (int j=2;jsecond->Size();++j) + items.Add(CFileItemPtr(new CFileItem(*it->second->Get(j)))); + } + items.Sort(SORT_METHOD_SIZE,SortOrderDescending); + int i=0; + while (size > g_advancedSettings.m_addonPackageFolderSize && i < items.Size()) + { + size -= items[i]->m_dwSize; + CFileUtils::DeleteItem(items[i++],true); + } + + if (size > g_advancedSettings.m_addonPackageFolderSize) + { + // 2. Remove the oldest packages (leaving least 1 for each add-on) + items.Clear(); + for (std::map::iterator it = packs.begin(); + it != packs.end();++it) + { + if (it->second->Size() > 1) + items.Add(CFileItemPtr(new CFileItem(*it->second->Get(1)))); + } + items.Sort(SORT_METHOD_DATE,SortOrderAscending); + i=0; + while (size > g_advancedSettings.m_addonPackageFolderSize && i < items.Size()) + { + size -= items[i]->m_dwSize; + CFileUtils::DeleteItem(items[i++],true); + } + } + // clean up our mess + for (std::map::iterator it = packs.begin(); + it != packs.end();++it) + delete it->second; +} + +int64_t CAddonInstaller::EnumeratePackageFolder(std::map& result) +{ + CFileItemList items; + CDirectory::GetDirectory("special://home/addons/packages/",items,".zip",DIR_FLAG_NO_FILE_DIRS); + int64_t size=0; + for (int i=0;im_bIsFolder) + continue; + size += items[i]->m_dwSize; + CStdString pack,dummy; + AddonVersion::SplitFileName(pack,dummy,items[i]->GetLabel()); + if (result.find(pack) == result.end()) + result[pack] = new CFileItemList; + result[pack]->Add(CFileItemPtr(new CFileItem(*items[i]))); + } + + return size; +} + CAddonInstallJob::CAddonInstallJob(const AddonPtr &addon, const CStdString &hash, bool update, const CStdString &referer) : m_addon(addon), m_hash(hash), m_update(update), m_referer(referer) { diff --git a/xbmc/addons/AddonInstaller.h b/xbmc/addons/AddonInstaller.h index f335ebfa64ed7..c68a6533a1adc 100644 --- a/xbmc/addons/AddonInstaller.h +++ b/xbmc/addons/AddonInstaller.h @@ -122,6 +122,9 @@ class CAddonInstaller : public IJobCallback */ bool DoInstall(const ADDON::AddonPtr &addon, const CStdString &hash = "", bool update = false, const CStdString &referer = "", bool background = true); + void PrunePackageCache(); + int64_t EnumeratePackageFolder(std::map& result); + CCriticalSection m_critSection; JobMap m_downloadJobs; CStopWatch m_repoUpdateWatch; ///< repository updates are done based on this counter diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp index bcb5953534168..3c6912b4aad96 100644 --- a/xbmc/settings/AdvancedSettings.cpp +++ b/xbmc/settings/AdvancedSettings.cpp @@ -298,6 +298,7 @@ void CAdvancedSettings::Initialize() m_measureRefreshrate = false; m_cacheMemBufferSize = 1024 * 1024 * 20; + m_addonPackageFolderSize = 200*1024*1024; m_jsonOutputCompact = true; m_jsonTcpPort = 9090; @@ -759,6 +760,7 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file) XMLUtils::GetUInt(pRootElement,"restrictcapsmask", m_RestrictCapsMask); XMLUtils::GetFloat(pRootElement,"sleepbeforeflip", m_sleepBeforeFlip, 0.0f, 1.0f); XMLUtils::GetBoolean(pRootElement,"virtualshares", m_bVirtualShares); + XMLUtils::GetUInt(pRootElement, "packagefoldersize", m_addonPackageFolderSize); //Tuxbox pElement = pRootElement->FirstChildElement("tuxbox"); diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h index 36e02f49cbdf8..4befa28d3bb40 100644 --- a/xbmc/settings/AdvancedSettings.h +++ b/xbmc/settings/AdvancedSettings.h @@ -346,6 +346,7 @@ class CAdvancedSettings bool m_guiVisualizeDirtyRegions; int m_guiAlgorithmDirtyRegions; int m_guiDirtyRegionNoFlipTimeout; + unsigned int m_addonPackageFolderSize; unsigned int m_cacheMemBufferSize;