mirror of
https://github.com/nzbget/nzbget.git
synced 2025-12-24 06:37:44 -05:00
931 lines
21 KiB
C++
931 lines
21 KiB
C++
/*
|
|
* This file is part of nzbget. See <http://nzbget.net>.
|
|
*
|
|
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
|
* Copyright (C) 2007-2019 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
|
|
#include "nzbget.h"
|
|
#include "DownloadInfo.h"
|
|
#include "DiskState.h"
|
|
#include "Options.h"
|
|
#include "Util.h"
|
|
#include "FileSystem.h"
|
|
|
|
int FileInfo::m_idGen = 0;
|
|
int FileInfo::m_idMax = 0;
|
|
int NzbInfo::m_idGen = 0;
|
|
int NzbInfo::m_idMax = 0;
|
|
DownloadQueue* DownloadQueue::g_DownloadQueue = nullptr;
|
|
bool DownloadQueue::g_Loaded = false;
|
|
|
|
void NzbParameterList::SetParameter(const char* name, const char* value)
|
|
{
|
|
bool emptyVal = Util::EmptyStr(value);
|
|
|
|
iterator pos = std::find_if(begin(), end(),
|
|
[name](NzbParameter& parameter)
|
|
{
|
|
return !strcasecmp(parameter.GetName(), name);
|
|
});
|
|
|
|
if (emptyVal && pos != end())
|
|
{
|
|
erase(pos);
|
|
}
|
|
else if (pos != end())
|
|
{
|
|
pos->SetValue(value);
|
|
}
|
|
else if (!emptyVal)
|
|
{
|
|
emplace_back(name, value);
|
|
}
|
|
}
|
|
|
|
NzbParameter* NzbParameterList::Find(const char* name)
|
|
{
|
|
for (NzbParameter& parameter : this)
|
|
{
|
|
if (!strcasecmp(parameter.GetName(), name))
|
|
{
|
|
return ¶meter;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void NzbParameterList::CopyFrom(NzbParameterList* sourceParameters)
|
|
{
|
|
for (NzbParameter& parameter : sourceParameters)
|
|
{
|
|
SetParameter(parameter.GetName(), parameter.GetValue());
|
|
}
|
|
}
|
|
|
|
|
|
ScriptStatus::EStatus ScriptStatusList::CalcTotalStatus()
|
|
{
|
|
ScriptStatus::EStatus status = ScriptStatus::srNone;
|
|
|
|
for (ScriptStatus& scriptStatus : this)
|
|
{
|
|
// Failure-Status overrides Success-Status
|
|
if ((scriptStatus.GetStatus() == ScriptStatus::srSuccess && status == ScriptStatus::srNone) ||
|
|
(scriptStatus.GetStatus() == ScriptStatus::srFailure))
|
|
{
|
|
status = scriptStatus.GetStatus();
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
void ServerStatList::StatOp(int serverId, int successArticles, int failedArticles, EStatOperation statOperation)
|
|
{
|
|
ServerStat* serverStat = nullptr;
|
|
for (ServerStat& serverStat1 : this)
|
|
{
|
|
if (serverStat1.GetServerId() == serverId)
|
|
{
|
|
serverStat = &serverStat1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!serverStat)
|
|
{
|
|
emplace_back(serverId);
|
|
serverStat = &back();
|
|
}
|
|
|
|
switch (statOperation)
|
|
{
|
|
case soSet:
|
|
serverStat->SetSuccessArticles(successArticles);
|
|
serverStat->SetFailedArticles(failedArticles);
|
|
break;
|
|
|
|
case soAdd:
|
|
serverStat->SetSuccessArticles(serverStat->GetSuccessArticles() + successArticles);
|
|
serverStat->SetFailedArticles(serverStat->GetFailedArticles() + failedArticles);
|
|
break;
|
|
|
|
case soSubtract:
|
|
serverStat->SetSuccessArticles(serverStat->GetSuccessArticles() - successArticles);
|
|
serverStat->SetFailedArticles(serverStat->GetFailedArticles() - failedArticles);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ServerStatList::ListOp(ServerStatList* serverStats, EStatOperation statOperation)
|
|
{
|
|
for (ServerStat& serverStat : serverStats)
|
|
{
|
|
StatOp(serverStat.GetServerId(), serverStat.GetSuccessArticles(), serverStat.GetFailedArticles(), statOperation);
|
|
}
|
|
}
|
|
|
|
|
|
void NzbInfo::SetId(int id)
|
|
{
|
|
m_id = id;
|
|
if (m_idMax < m_id)
|
|
{
|
|
m_idMax = m_id;
|
|
}
|
|
}
|
|
|
|
void NzbInfo::ResetGenId(bool max)
|
|
{
|
|
if (max)
|
|
{
|
|
m_idGen = m_idMax;
|
|
}
|
|
else
|
|
{
|
|
m_idGen = 0;
|
|
m_idMax = 0;
|
|
}
|
|
}
|
|
|
|
int NzbInfo::GenerateId()
|
|
{
|
|
return ++m_idGen;
|
|
}
|
|
|
|
void NzbInfo::SetUrl(const char* url)
|
|
{
|
|
m_url = url;
|
|
|
|
if (!m_name)
|
|
{
|
|
CString nzbNicename = MakeNiceUrlName(url, m_filename);
|
|
SetName(nzbNicename);
|
|
}
|
|
}
|
|
|
|
void NzbInfo::SetFilename(const char* filename)
|
|
{
|
|
bool hadFilename = !Util::EmptyStr(m_filename);
|
|
m_filename = filename;
|
|
|
|
if ((!m_name || !hadFilename) && !Util::EmptyStr(filename))
|
|
{
|
|
CString nzbNicename = MakeNiceNzbName(m_filename, true);
|
|
SetName(nzbNicename);
|
|
}
|
|
}
|
|
|
|
CString NzbInfo::MakeNiceNzbName(const char * nzbFilename, bool removeExt)
|
|
{
|
|
BString<1024> nicename = FileSystem::BaseFileName(nzbFilename);
|
|
if (removeExt)
|
|
{
|
|
// wipe out ".nzb"
|
|
char* p = strrchr(nicename, '.');
|
|
if (p && !strcasecmp(p, ".nzb")) *p = '\0';
|
|
}
|
|
CString validname = FileSystem::MakeValidFilename(nicename);
|
|
return validname;
|
|
}
|
|
|
|
CString NzbInfo::MakeNiceUrlName(const char* urlStr, const char* nzbFilename)
|
|
{
|
|
CString urlNicename;
|
|
URL url(urlStr);
|
|
|
|
if (!Util::EmptyStr(nzbFilename))
|
|
{
|
|
CString nzbNicename = MakeNiceNzbName(nzbFilename, true);
|
|
urlNicename.Format("%s @ %s", *nzbNicename, url.GetHost());
|
|
}
|
|
else if (url.IsValid())
|
|
{
|
|
urlNicename.Format("%s%s", url.GetHost(), url.GetResource());
|
|
}
|
|
else
|
|
{
|
|
urlNicename = urlStr;
|
|
}
|
|
|
|
return urlNicename;
|
|
}
|
|
|
|
void NzbInfo::BuildDestDirName()
|
|
{
|
|
if (Util::EmptyStr(g_Options->GetInterDir()))
|
|
{
|
|
m_destDir = BuildFinalDirName();
|
|
}
|
|
else
|
|
{
|
|
m_destDir.Format("%s%c%s.#%i", g_Options->GetInterDir(), PATH_SEPARATOR, GetName(), GetId());
|
|
}
|
|
}
|
|
|
|
CString NzbInfo::BuildFinalDirName()
|
|
{
|
|
CString finalDir = g_Options->GetDestDir();
|
|
bool useCategory = !m_category.Empty();
|
|
|
|
if (useCategory)
|
|
{
|
|
Options::Category* category = g_Options->FindCategory(m_category, false);
|
|
if (category && !Util::EmptyStr(category->GetDestDir()))
|
|
{
|
|
finalDir = category->GetDestDir();
|
|
useCategory = false;
|
|
}
|
|
}
|
|
|
|
if (g_Options->GetAppendCategoryDir() && useCategory)
|
|
{
|
|
CString categoryDir = FileSystem::MakeValidFilename(m_category, true);
|
|
// we can't format with "finalDir.Format" because one of the parameter is "finalDir" itself.
|
|
finalDir = CString::FormatStr("%s%c%s", *finalDir, PATH_SEPARATOR, *categoryDir);
|
|
}
|
|
|
|
finalDir.AppendFmt("%c%s", PATH_SEPARATOR, GetName());
|
|
|
|
return finalDir;
|
|
}
|
|
|
|
int NzbInfo::CalcHealth()
|
|
{
|
|
if (m_currentFailedSize == 0 || m_size == m_parSize)
|
|
{
|
|
return 1000;
|
|
}
|
|
|
|
int health = (int)((m_size - m_parSize -
|
|
(m_currentFailedSize - m_parCurrentFailedSize)) * 1000 / (m_size - m_parSize));
|
|
|
|
if (health == 1000 && m_currentFailedSize - m_parCurrentFailedSize > 0)
|
|
{
|
|
health = 999;
|
|
}
|
|
|
|
return health;
|
|
}
|
|
|
|
int NzbInfo::CalcCriticalHealth(bool allowEstimation)
|
|
{
|
|
if (m_size == 0)
|
|
{
|
|
return 1000;
|
|
}
|
|
|
|
if (m_size == m_parSize)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int64 goodParSize = m_parSize - m_parCurrentFailedSize;
|
|
int criticalHealth = (int)((m_size - goodParSize*2) * 1000 / (m_size - goodParSize));
|
|
|
|
if (goodParSize*2 > m_size)
|
|
{
|
|
criticalHealth = 0;
|
|
}
|
|
else if (criticalHealth == 1000 && m_parSize > 0)
|
|
{
|
|
criticalHealth = 999;
|
|
}
|
|
|
|
if (criticalHealth == 1000 && allowEstimation)
|
|
{
|
|
// using empirical critical health 85%, to avoid false alarms for downloads with renamed par-files
|
|
criticalHealth = 850;
|
|
}
|
|
|
|
return criticalHealth;
|
|
}
|
|
|
|
void NzbInfo::UpdateMinMaxTime()
|
|
{
|
|
m_minTime = 0;
|
|
m_maxTime = 0;
|
|
|
|
bool first = true;
|
|
for (FileInfo* fileInfo : &m_fileList)
|
|
{
|
|
if (first)
|
|
{
|
|
m_minTime = fileInfo->GetTime();
|
|
m_maxTime = fileInfo->GetTime();
|
|
first = false;
|
|
}
|
|
if (fileInfo->GetTime() > 0)
|
|
{
|
|
if (fileInfo->GetTime() < m_minTime)
|
|
{
|
|
m_minTime = fileInfo->GetTime();
|
|
}
|
|
if (fileInfo->GetTime() > m_maxTime)
|
|
{
|
|
m_maxTime = fileInfo->GetTime();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NzbInfo::AddMessage(Message::EKind kind, const char * text, bool print)
|
|
{
|
|
if (print)
|
|
{
|
|
switch (kind)
|
|
{
|
|
case Message::mkDetail:
|
|
detail("%s", text);
|
|
break;
|
|
|
|
case Message::mkInfo:
|
|
info("%s", text);
|
|
break;
|
|
|
|
case Message::mkWarning:
|
|
warn("%s", text);
|
|
break;
|
|
|
|
case Message::mkError:
|
|
error("%s", text);
|
|
break;
|
|
|
|
case Message::mkDebug:
|
|
debug("%s", text);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Guard guard(m_logMutex);
|
|
|
|
m_messages.emplace_back(++m_idMessageGen, kind, Util::CurrentTime(), text);
|
|
|
|
if (g_Options->GetServerMode() && g_Options->GetNzbLog())
|
|
{
|
|
g_DiskState->AppendNzbMessage(m_id, kind, text);
|
|
m_messageCount++;
|
|
}
|
|
|
|
while (m_messages.size() > (uint32)g_Options->GetLogBuffer())
|
|
{
|
|
m_messages.pop_front();
|
|
}
|
|
|
|
m_cachedMessageCount = m_messages.size();
|
|
}
|
|
|
|
void NzbInfo::PrintMessage(Message::EKind kind, const char* format, ...)
|
|
{
|
|
char tmp2[1024];
|
|
|
|
va_list ap;
|
|
va_start(ap, format);
|
|
vsnprintf(tmp2, 1024, format, ap);
|
|
tmp2[1024-1] = '\0';
|
|
va_end(ap);
|
|
|
|
AddMessage(kind, tmp2);
|
|
}
|
|
|
|
void NzbInfo::ClearMessages()
|
|
{
|
|
Guard guard(m_logMutex);
|
|
m_messages.clear();
|
|
m_cachedMessageCount = 0;
|
|
}
|
|
|
|
void NzbInfo::MoveFileList(NzbInfo* srcNzbInfo)
|
|
{
|
|
m_fileList = std::move(*srcNzbInfo->GetFileList());
|
|
for (FileInfo* fileInfo : &m_fileList)
|
|
{
|
|
fileInfo->SetNzbInfo(this);
|
|
}
|
|
|
|
SetFullContentHash(srcNzbInfo->GetFullContentHash());
|
|
SetFilteredContentHash(srcNzbInfo->GetFilteredContentHash());
|
|
|
|
SetFileCount(srcNzbInfo->GetFileCount());
|
|
SetPausedFileCount(srcNzbInfo->GetPausedFileCount());
|
|
SetRemainingParCount(srcNzbInfo->GetRemainingParCount());
|
|
|
|
SetSize(srcNzbInfo->GetSize());
|
|
SetRemainingSize(srcNzbInfo->GetRemainingSize());
|
|
SetPausedSize(srcNzbInfo->GetPausedSize());
|
|
SetSuccessSize(srcNzbInfo->GetSuccessSize());
|
|
SetCurrentSuccessSize(srcNzbInfo->GetCurrentSuccessSize());
|
|
SetFailedSize(srcNzbInfo->GetFailedSize());
|
|
SetCurrentFailedSize(srcNzbInfo->GetCurrentFailedSize());
|
|
|
|
SetParSize(srcNzbInfo->GetParSize());
|
|
SetParSuccessSize(srcNzbInfo->GetParSuccessSize());
|
|
SetParCurrentSuccessSize(srcNzbInfo->GetParCurrentSuccessSize());
|
|
SetParFailedSize(srcNzbInfo->GetParFailedSize());
|
|
SetParCurrentFailedSize(srcNzbInfo->GetParCurrentFailedSize());
|
|
|
|
SetTotalArticles(srcNzbInfo->GetTotalArticles());
|
|
SetSuccessArticles(srcNzbInfo->GetSuccessArticles());
|
|
SetFailedArticles(srcNzbInfo->GetFailedArticles());
|
|
SetCurrentSuccessArticles(srcNzbInfo->GetSuccessArticles());
|
|
SetCurrentFailedArticles(srcNzbInfo->GetFailedArticles());
|
|
|
|
SetMinTime(srcNzbInfo->GetMinTime());
|
|
SetMaxTime(srcNzbInfo->GetMaxTime());
|
|
}
|
|
|
|
void NzbInfo::EnterPostProcess()
|
|
{
|
|
m_postInfo = std::make_unique<PostInfo>();
|
|
m_postInfo->SetNzbInfo(this);
|
|
}
|
|
|
|
void NzbInfo::LeavePostProcess()
|
|
{
|
|
m_postInfo.reset();
|
|
ClearMessages();
|
|
}
|
|
|
|
void NzbInfo::SetActiveDownloads(int activeDownloads)
|
|
{
|
|
if (((m_activeDownloads == 0 && activeDownloads > 0) ||
|
|
(m_activeDownloads > 0 && activeDownloads == 0)) &&
|
|
m_kind == NzbInfo::nkNzb)
|
|
{
|
|
if (activeDownloads > 0)
|
|
{
|
|
m_downloadStartTime = Util::CurrentTime();
|
|
m_downloadStartSec = m_downloadSec;
|
|
}
|
|
else
|
|
{
|
|
m_downloadSec = m_downloadStartSec + (int)(Util::CurrentTime() - m_downloadStartTime);
|
|
m_downloadStartTime = 0;
|
|
m_changed = true;
|
|
}
|
|
}
|
|
else if (activeDownloads > 0)
|
|
{
|
|
m_downloadSec = m_downloadStartSec + (int)(Util::CurrentTime() - m_downloadStartTime);
|
|
m_changed = true;
|
|
}
|
|
m_activeDownloads = activeDownloads;
|
|
}
|
|
|
|
bool NzbInfo::IsDupeSuccess()
|
|
{
|
|
bool failure =
|
|
m_markStatus != NzbInfo::ksSuccess &&
|
|
m_markStatus != NzbInfo::ksGood &&
|
|
(m_deleteStatus != NzbInfo::dsNone ||
|
|
m_markStatus == NzbInfo::ksBad ||
|
|
m_parStatus == NzbInfo::psFailure ||
|
|
m_unpackStatus == NzbInfo::usFailure ||
|
|
m_unpackStatus == NzbInfo::usPassword ||
|
|
m_urlStatus == NzbInfo::lsFailed ||
|
|
m_urlStatus == NzbInfo::lsScanSkipped ||
|
|
m_urlStatus == NzbInfo::lsScanFailed ||
|
|
(m_parStatus == NzbInfo::psSkipped &&
|
|
m_unpackStatus == NzbInfo::usSkipped &&
|
|
CalcHealth() < CalcCriticalHealth(true)));
|
|
return !failure;
|
|
}
|
|
|
|
const char* NzbInfo::MakeTextStatus(bool ignoreScriptStatus)
|
|
{
|
|
const char* status = "FAILURE/INTERNAL_ERROR";
|
|
|
|
if (m_kind == NzbInfo::nkNzb)
|
|
{
|
|
int health = CalcHealth();
|
|
int criticalHealth = CalcCriticalHealth(false);
|
|
ScriptStatus::EStatus scriptStatus = ignoreScriptStatus ? ScriptStatus::srSuccess : m_scriptStatuses.CalcTotalStatus();
|
|
|
|
if (m_markStatus == NzbInfo::ksBad)
|
|
{
|
|
status = "FAILURE/BAD";
|
|
}
|
|
else if (m_markStatus == NzbInfo::ksGood)
|
|
{
|
|
status = "SUCCESS/GOOD";
|
|
}
|
|
else if (m_markStatus == NzbInfo::ksSuccess)
|
|
{
|
|
status = "SUCCESS/MARK";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsHealth)
|
|
{
|
|
status = "FAILURE/HEALTH";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsManual)
|
|
{
|
|
status = "DELETED/MANUAL";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsDupe)
|
|
{
|
|
status = "DELETED/DUPE";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsBad)
|
|
{
|
|
status = "FAILURE/BAD";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsGood)
|
|
{
|
|
status = "DELETED/GOOD";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsCopy)
|
|
{
|
|
status = "DELETED/COPY";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsScan)
|
|
{
|
|
status = "FAILURE/SCAN";
|
|
}
|
|
else if (m_parStatus == NzbInfo::psFailure)
|
|
{
|
|
status = "FAILURE/PAR";
|
|
}
|
|
else if (m_unpackStatus == NzbInfo::usFailure)
|
|
{
|
|
status = "FAILURE/UNPACK";
|
|
}
|
|
else if (m_moveStatus == NzbInfo::msFailure)
|
|
{
|
|
status = "FAILURE/MOVE";
|
|
}
|
|
else if (m_parStatus == NzbInfo::psManual)
|
|
{
|
|
status = "WARNING/DAMAGED";
|
|
}
|
|
else if (m_parStatus == NzbInfo::psRepairPossible)
|
|
{
|
|
status = "WARNING/REPAIRABLE";
|
|
}
|
|
else if ((m_parStatus == NzbInfo::psNone || m_parStatus == NzbInfo::psSkipped) &&
|
|
(m_unpackStatus == NzbInfo::usNone || m_unpackStatus == NzbInfo::usSkipped) &&
|
|
health < criticalHealth)
|
|
{
|
|
status = "FAILURE/HEALTH";
|
|
}
|
|
else if ((m_parStatus == NzbInfo::psNone || m_parStatus == NzbInfo::psSkipped) &&
|
|
(m_unpackStatus == NzbInfo::usNone || m_unpackStatus == NzbInfo::usSkipped) &&
|
|
health < 1000 && health >= criticalHealth)
|
|
{
|
|
status = "WARNING/HEALTH";
|
|
}
|
|
else if ((m_parStatus == NzbInfo::psNone || m_parStatus == NzbInfo::psSkipped) &&
|
|
(m_unpackStatus == NzbInfo::usNone || m_unpackStatus == NzbInfo::usSkipped) &&
|
|
scriptStatus != ScriptStatus::srFailure && health == 1000)
|
|
{
|
|
status = "SUCCESS/HEALTH";
|
|
}
|
|
else if (m_unpackStatus == NzbInfo::usSpace)
|
|
{
|
|
status = "WARNING/SPACE";
|
|
}
|
|
else if (m_unpackStatus == NzbInfo::usPassword)
|
|
{
|
|
status = "WARNING/PASSWORD";
|
|
}
|
|
else if ((m_unpackStatus == NzbInfo::usSuccess ||
|
|
((m_unpackStatus == NzbInfo::usNone || m_unpackStatus == NzbInfo::usSkipped) &&
|
|
m_parStatus == NzbInfo::psSuccess)) &&
|
|
scriptStatus == ScriptStatus::srSuccess)
|
|
{
|
|
status = "SUCCESS/ALL";
|
|
}
|
|
else if (m_unpackStatus == NzbInfo::usSuccess && scriptStatus == ScriptStatus::srNone)
|
|
{
|
|
status = "SUCCESS/UNPACK";
|
|
}
|
|
else if (m_parStatus == NzbInfo::psSuccess && scriptStatus == ScriptStatus::srNone)
|
|
{
|
|
status = "SUCCESS/PAR";
|
|
}
|
|
else if (scriptStatus == ScriptStatus::srFailure)
|
|
{
|
|
status = "WARNING/SCRIPT";
|
|
}
|
|
}
|
|
else if (m_kind == NzbInfo::nkUrl)
|
|
{
|
|
if (m_deleteStatus == NzbInfo::dsManual)
|
|
{
|
|
status = "DELETED/MANUAL";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsDupe)
|
|
{
|
|
status = "DELETED/DUPE";
|
|
}
|
|
else if (m_deleteStatus == NzbInfo::dsGood)
|
|
{
|
|
status = "DELETED/GOOD";
|
|
}
|
|
else
|
|
{
|
|
const char* urlStatusName[] = { "FAILURE/INTERNAL_ERROR", "FAILURE/INTERNAL_ERROR", "FAILURE/INTERNAL_ERROR",
|
|
"FAILURE/FETCH", "FAILURE/INTERNAL_ERROR", "WARNING/SKIPPED", "FAILURE/SCAN" };
|
|
status = urlStatusName[m_urlStatus];
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void NzbInfo::UpdateCurrentStats()
|
|
{
|
|
m_pausedFileCount = 0;
|
|
m_remainingParCount = 0;
|
|
m_remainingSize = 0;
|
|
m_pausedSize = 0;
|
|
m_currentSuccessArticles = m_successArticles;
|
|
m_currentFailedArticles = m_failedArticles;
|
|
m_currentSuccessSize = m_successSize;
|
|
m_currentFailedSize = m_failedSize;
|
|
m_parCurrentSuccessSize = m_parSuccessSize;
|
|
m_parCurrentFailedSize = m_parFailedSize;
|
|
m_extraPriority = 0;
|
|
|
|
m_currentServerStats.ListOp(&m_serverStats, ServerStatList::soSet);
|
|
|
|
for (FileInfo* fileInfo : &m_fileList)
|
|
{
|
|
m_remainingSize += fileInfo->GetRemainingSize();
|
|
m_currentSuccessArticles += fileInfo->GetSuccessArticles();
|
|
m_currentFailedArticles += fileInfo->GetFailedArticles();
|
|
m_currentSuccessSize += fileInfo->GetSuccessSize();
|
|
m_currentFailedSize += fileInfo->GetFailedSize();
|
|
m_extraPriority += fileInfo->GetExtraPriority() ? 1 : 0;
|
|
|
|
if (fileInfo->GetPaused())
|
|
{
|
|
m_pausedFileCount++;
|
|
m_pausedSize += fileInfo->GetRemainingSize();
|
|
}
|
|
if (fileInfo->GetParFile())
|
|
{
|
|
m_remainingParCount++;
|
|
m_parCurrentSuccessSize += fileInfo->GetSuccessSize();
|
|
m_parCurrentFailedSize += fileInfo->GetFailedSize();
|
|
}
|
|
|
|
m_currentServerStats.ListOp(fileInfo->GetServerStats(), ServerStatList::soAdd);
|
|
}
|
|
}
|
|
|
|
void NzbInfo::UpdateCompletedStats(FileInfo* fileInfo)
|
|
{
|
|
m_successSize += fileInfo->GetSuccessSize();
|
|
m_failedSize += fileInfo->GetFailedSize();
|
|
m_failedArticles += fileInfo->GetFailedArticles();
|
|
m_successArticles += fileInfo->GetSuccessArticles();
|
|
m_extraPriority -= fileInfo->GetExtraPriority() ? 1 : 0;
|
|
|
|
if (fileInfo->GetParFile())
|
|
{
|
|
m_parSuccessSize += fileInfo->GetSuccessSize();
|
|
m_parFailedSize += fileInfo->GetFailedSize();
|
|
m_remainingParCount--;
|
|
}
|
|
|
|
if (fileInfo->GetPaused())
|
|
{
|
|
m_pausedFileCount--;
|
|
}
|
|
|
|
m_serverStats.ListOp(fileInfo->GetServerStats(), ServerStatList::soAdd);
|
|
}
|
|
|
|
void NzbInfo::UpdateDeletedStats(FileInfo* fileInfo)
|
|
{
|
|
m_fileCount--;
|
|
m_size -= fileInfo->GetSize();
|
|
m_currentSuccessSize -= fileInfo->GetSuccessSize();
|
|
m_failedSize -= fileInfo->GetMissedSize();
|
|
m_failedArticles -= fileInfo->GetMissedArticles();
|
|
m_currentFailedSize -= fileInfo->GetFailedSize() + fileInfo->GetMissedSize();
|
|
m_totalArticles -= fileInfo->GetTotalArticles();
|
|
m_currentSuccessArticles -= fileInfo->GetSuccessArticles();
|
|
m_currentFailedArticles -= fileInfo->GetFailedArticles() + fileInfo->GetMissedArticles();
|
|
m_remainingSize -= fileInfo->GetRemainingSize();
|
|
m_extraPriority -= fileInfo->GetExtraPriority() ? 1 : 0;
|
|
|
|
if (fileInfo->GetParFile())
|
|
{
|
|
m_remainingParCount--;
|
|
m_parSize -= fileInfo->GetSize();
|
|
m_parCurrentSuccessSize -= fileInfo->GetSuccessSize();
|
|
m_parFailedSize -= fileInfo->GetMissedSize();
|
|
m_parCurrentFailedSize -= fileInfo->GetFailedSize() + fileInfo->GetMissedSize();
|
|
}
|
|
|
|
if (fileInfo->GetPaused())
|
|
{
|
|
m_pausedFileCount--;
|
|
m_pausedSize -= fileInfo->GetRemainingSize();
|
|
}
|
|
|
|
m_currentServerStats.ListOp(fileInfo->GetServerStats(), ServerStatList::soSubtract);
|
|
}
|
|
|
|
bool NzbInfo::IsDownloadCompleted(bool ignorePausedPars)
|
|
{
|
|
if (m_activeDownloads)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (FileInfo* fileInfo : &m_fileList)
|
|
{
|
|
if ((!fileInfo->GetPaused() || !ignorePausedPars || !fileInfo->GetParFile()) &&
|
|
!fileInfo->GetDeleted())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ArticleInfo::AttachSegment(std::unique_ptr<SegmentData> content, int64 offset, int size)
|
|
{
|
|
m_segmentContent = std::move(content);
|
|
m_segmentOffset = offset;
|
|
m_segmentSize = size;
|
|
}
|
|
|
|
void ArticleInfo::DiscardSegment()
|
|
{
|
|
m_segmentContent.reset();
|
|
}
|
|
|
|
|
|
void FileInfo::SetId(int id)
|
|
{
|
|
m_id = id;
|
|
if (m_idMax < m_id)
|
|
{
|
|
m_idMax = m_id;
|
|
}
|
|
}
|
|
|
|
void FileInfo::ResetGenId(bool max)
|
|
{
|
|
if (max)
|
|
{
|
|
m_idGen = m_idMax;
|
|
}
|
|
else
|
|
{
|
|
m_idGen = 0;
|
|
m_idMax = 0;
|
|
}
|
|
}
|
|
|
|
void FileInfo::SetPaused(bool paused)
|
|
{
|
|
if (m_paused != paused && m_nzbInfo)
|
|
{
|
|
m_nzbInfo->SetPausedFileCount(m_nzbInfo->GetPausedFileCount() + (paused ? 1 : -1));
|
|
m_nzbInfo->SetPausedSize(m_nzbInfo->GetPausedSize() + (paused ? m_remainingSize : - m_remainingSize));
|
|
}
|
|
m_paused = paused;
|
|
}
|
|
|
|
void FileInfo::SetExtraPriority(bool extraPriority)
|
|
{
|
|
if (m_extraPriority != extraPriority && m_nzbInfo)
|
|
{
|
|
m_nzbInfo->SetExtraPriority(m_nzbInfo->GetExtraPriority() + (extraPriority ? 1 : -1));
|
|
}
|
|
m_extraPriority = extraPriority;
|
|
}
|
|
|
|
void FileInfo::MakeValidFilename()
|
|
{
|
|
m_filename = FileSystem::MakeValidFilename(m_filename);
|
|
}
|
|
|
|
void FileInfo::SetActiveDownloads(int activeDownloads)
|
|
{
|
|
m_activeDownloads = activeDownloads;
|
|
|
|
if (m_activeDownloads > 0 && !m_outputFileMutex)
|
|
{
|
|
m_outputFileMutex = std::make_unique<Mutex>();
|
|
}
|
|
else if (m_activeDownloads == 0)
|
|
{
|
|
m_outputFileMutex.reset();
|
|
}
|
|
}
|
|
|
|
|
|
CompletedFile::CompletedFile(int id, const char* filename, const char* origname, EStatus status,
|
|
uint32 crc, bool parFile, const char* hash16k, const char* parSetId) :
|
|
m_id(id), m_filename(filename), m_origname(origname), m_status(status),
|
|
m_crc(crc), m_parFile(parFile), m_hash16k(hash16k), m_parSetId(parSetId)
|
|
{
|
|
if (FileInfo::m_idMax < m_id)
|
|
{
|
|
FileInfo::m_idMax = m_id;
|
|
}
|
|
}
|
|
|
|
|
|
void DupInfo::SetId(int id)
|
|
{
|
|
m_id = id;
|
|
if (NzbInfo::m_idMax < m_id)
|
|
{
|
|
NzbInfo::m_idMax = m_id;
|
|
}
|
|
}
|
|
|
|
|
|
HistoryInfo::~HistoryInfo()
|
|
{
|
|
if ((m_kind == hkNzb || m_kind == hkUrl) && m_info)
|
|
{
|
|
delete (NzbInfo*)m_info;
|
|
}
|
|
else if (m_kind == hkDup && m_info)
|
|
{
|
|
delete (DupInfo*)m_info;
|
|
}
|
|
}
|
|
|
|
int HistoryInfo::GetId()
|
|
{
|
|
if ((m_kind == hkNzb || m_kind == hkUrl))
|
|
{
|
|
return ((NzbInfo*)m_info)->GetId();
|
|
}
|
|
else // if (m_eKind == hkDup)
|
|
{
|
|
return ((DupInfo*)m_info)->GetId();
|
|
}
|
|
}
|
|
|
|
const char* HistoryInfo::GetName()
|
|
{
|
|
if (m_kind == hkNzb || m_kind == hkUrl)
|
|
{
|
|
return GetNzbInfo()->GetName();
|
|
}
|
|
else if (m_kind == hkDup)
|
|
{
|
|
return GetDupInfo()->GetName();
|
|
}
|
|
else
|
|
{
|
|
return "<unknown>";
|
|
}
|
|
}
|
|
|
|
|
|
void DownloadQueue::CalcRemainingSize(int64* remaining, int64* remainingForced)
|
|
{
|
|
int64 remainingSize = 0;
|
|
int64 remainingForcedSize = 0;
|
|
|
|
for (NzbInfo* nzbInfo : &m_queue)
|
|
{
|
|
for (FileInfo* fileInfo : nzbInfo->GetFileList())
|
|
{
|
|
if (!fileInfo->GetPaused() && !fileInfo->GetDeleted())
|
|
{
|
|
remainingSize += fileInfo->GetRemainingSize();
|
|
if (nzbInfo->GetForcePriority())
|
|
{
|
|
remainingForcedSize += fileInfo->GetRemainingSize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*remaining = remainingSize;
|
|
|
|
if (remainingForced)
|
|
{
|
|
*remainingForced = remainingForcedSize;
|
|
}
|
|
}
|