mirror of
https://github.com/nzbget/nzbget.git
synced 2026-01-17 18:37:44 -05:00
593 lines
21 KiB
C++
593 lines
21 KiB
C++
/*
|
|
* This file is part of nzbget. See <http://nzbget.net>.
|
|
*
|
|
* Copyright (C) 2007-2016 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 "Options.h"
|
|
#include "Log.h"
|
|
#include "Util.h"
|
|
#include "NzbFile.h"
|
|
#include "HistoryCoordinator.h"
|
|
#include "DupeCoordinator.h"
|
|
#include "QueueScript.h"
|
|
|
|
bool DupeCoordinator::SameNameOrKey(const char* name1, const char* dupeKey1,
|
|
const char* name2, const char* dupeKey2)
|
|
{
|
|
bool hasDupeKeys = !Util::EmptyStr(dupeKey1) && !Util::EmptyStr(dupeKey2);
|
|
return (hasDupeKeys && !strcasecmp(dupeKey1, dupeKey2)) ||
|
|
(!hasDupeKeys && !strcasecmp(name1, name2));
|
|
}
|
|
|
|
/**
|
|
Check if the title was already downloaded or is already queued:
|
|
- if there is a duplicate with exactly same content (via hash-check)
|
|
in queue or in history - the new item is skipped;
|
|
- if there is a duplicate marked as good in history - the new item is skipped;
|
|
- if there is a duplicate with success-status in dup-history but
|
|
there are no duplicates in recent history - the new item is skipped;
|
|
- if queue has a duplicate with the same or higher score - the new item
|
|
is moved to history as dupe-backup;
|
|
- if queue has a duplicate with lower score - the existing item is moved
|
|
to history as dupe-backup (unless it is in post-processing stage) and
|
|
the new item is added to queue;
|
|
- if queue doesn't have duplicates - the new item is added to queue.
|
|
*/
|
|
void DupeCoordinator::NzbFound(DownloadQueue* downloadQueue, NzbInfo* nzbInfo)
|
|
{
|
|
debug("Checking duplicates for %s", nzbInfo->GetName());
|
|
|
|
// find duplicates in download queue with exactly same content
|
|
for (NzbInfo* queuedNzbInfo : downloadQueue->GetQueue())
|
|
{
|
|
bool sameContent = (nzbInfo->GetFullContentHash() > 0 &&
|
|
nzbInfo->GetFullContentHash() == queuedNzbInfo->GetFullContentHash()) ||
|
|
(nzbInfo->GetFilteredContentHash() > 0 &&
|
|
nzbInfo->GetFilteredContentHash() == queuedNzbInfo->GetFilteredContentHash());
|
|
|
|
// if there is a duplicate with exactly same content (via hash-check)
|
|
// in queue - the new item is skipped
|
|
if (queuedNzbInfo != nzbInfo && sameContent && nzbInfo->GetKind() == NzbInfo::nkNzb)
|
|
{
|
|
BString<1024> message;
|
|
if (!strcmp(nzbInfo->GetName(), queuedNzbInfo->GetName()))
|
|
{
|
|
message.Format("Skipping duplicate %s, already queued", nzbInfo->GetName());
|
|
}
|
|
else
|
|
{
|
|
message.Format("Skipping duplicate %s, already queued as %s",
|
|
nzbInfo->GetName(), queuedNzbInfo->GetName());
|
|
}
|
|
|
|
if (nzbInfo->GetFeedId())
|
|
{
|
|
warn("%s", *message);
|
|
// Flag saying QueueCoordinator to skip nzb-file
|
|
nzbInfo->SetDeleteStatus(NzbInfo::dsManual);
|
|
g_HistoryCoordinator->DeleteDiskFiles(nzbInfo);
|
|
}
|
|
else
|
|
{
|
|
nzbInfo->SetDeleteStatus(NzbInfo::dsCopy);
|
|
nzbInfo->AddMessage(Message::mkWarning, message);
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if download has empty dupekey and empty dupescore - check if download queue
|
|
// or history have an item with the same name and non empty dupekey or dupescore and
|
|
// take these properties from this item
|
|
if (Util::EmptyStr(nzbInfo->GetDupeKey()) && nzbInfo->GetDupeScore() == 0)
|
|
{
|
|
for (NzbInfo* queuedNzbInfo : downloadQueue->GetQueue())
|
|
{
|
|
if (!strcmp(queuedNzbInfo->GetName(), nzbInfo->GetName()) &&
|
|
(!Util::EmptyStr(queuedNzbInfo->GetDupeKey()) || queuedNzbInfo->GetDupeScore() != 0))
|
|
{
|
|
nzbInfo->SetDupeKey(queuedNzbInfo->GetDupeKey());
|
|
nzbInfo->SetDupeScore(queuedNzbInfo->GetDupeScore());
|
|
info("Assigning dupekey %s and dupescore %i to %s from existing queue item with the same name",
|
|
nzbInfo->GetDupeKey(), nzbInfo->GetDupeScore(), nzbInfo->GetName());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (Util::EmptyStr(nzbInfo->GetDupeKey()) && nzbInfo->GetDupeScore() == 0)
|
|
{
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
!strcmp(historyInfo->GetNzbInfo()->GetName(), nzbInfo->GetName()) &&
|
|
(!Util::EmptyStr(historyInfo->GetNzbInfo()->GetDupeKey()) || historyInfo->GetNzbInfo()->GetDupeScore() != 0))
|
|
{
|
|
nzbInfo->SetDupeKey(historyInfo->GetNzbInfo()->GetDupeKey());
|
|
nzbInfo->SetDupeScore(historyInfo->GetNzbInfo()->GetDupeScore());
|
|
info("Assigning dupekey %s and dupescore %i to %s from existing history item with the same name",
|
|
nzbInfo->GetDupeKey(), nzbInfo->GetDupeScore(), nzbInfo->GetName());
|
|
break;
|
|
}
|
|
if (historyInfo->GetKind() == HistoryInfo::hkDup &&
|
|
!strcmp(historyInfo->GetDupInfo()->GetName(), nzbInfo->GetName()) &&
|
|
(!Util::EmptyStr(historyInfo->GetDupInfo()->GetDupeKey()) || historyInfo->GetDupInfo()->GetDupeScore() != 0))
|
|
{
|
|
nzbInfo->SetDupeKey(historyInfo->GetDupInfo()->GetDupeKey());
|
|
nzbInfo->SetDupeScore(historyInfo->GetDupInfo()->GetDupeScore());
|
|
info("Assigning dupekey %s and dupescore %i to %s from existing history item with the same name",
|
|
nzbInfo->GetDupeKey(), nzbInfo->GetDupeScore(), nzbInfo->GetName());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// find duplicates in history
|
|
|
|
bool skip = false;
|
|
bool good = false;
|
|
bool sameContent = false;
|
|
const char* dupeName = nullptr;
|
|
|
|
// find duplicates in history having exactly same content
|
|
// also: nzb-files having duplicates marked as good are skipped
|
|
// also (only in score mode): nzb-files having success-duplicates in dup-history but not having duplicates in recent history are skipped
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
((nzbInfo->GetFullContentHash() > 0 &&
|
|
nzbInfo->GetFullContentHash() == historyInfo->GetNzbInfo()->GetFullContentHash()) ||
|
|
(nzbInfo->GetFilteredContentHash() > 0 &&
|
|
nzbInfo->GetFilteredContentHash() == historyInfo->GetNzbInfo()->GetFilteredContentHash())))
|
|
{
|
|
skip = true;
|
|
sameContent = true;
|
|
dupeName = historyInfo->GetNzbInfo()->GetName();
|
|
break;
|
|
}
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkDup &&
|
|
((nzbInfo->GetFullContentHash() > 0 &&
|
|
nzbInfo->GetFullContentHash() == historyInfo->GetDupInfo()->GetFullContentHash()) ||
|
|
(nzbInfo->GetFilteredContentHash() > 0 &&
|
|
nzbInfo->GetFilteredContentHash() == historyInfo->GetDupInfo()->GetFilteredContentHash())))
|
|
{
|
|
skip = true;
|
|
sameContent = true;
|
|
dupeName = historyInfo->GetDupInfo()->GetName();
|
|
break;
|
|
}
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() != dmForce &&
|
|
historyInfo->GetNzbInfo()->GetMarkStatus() == NzbInfo::ksGood &&
|
|
SameNameOrKey(historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey(),
|
|
nzbInfo->GetName(), nzbInfo->GetDupeKey()))
|
|
{
|
|
skip = true;
|
|
good = true;
|
|
dupeName = historyInfo->GetNzbInfo()->GetName();
|
|
break;
|
|
}
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkDup &&
|
|
historyInfo->GetDupInfo()->GetDupeMode() != dmForce &&
|
|
(historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood ||
|
|
(nzbInfo->GetDupeMode() == dmScore &&
|
|
historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess &&
|
|
nzbInfo->GetDupeScore() <= historyInfo->GetDupInfo()->GetDupeScore())) &&
|
|
SameNameOrKey(historyInfo->GetDupInfo()->GetName(), historyInfo->GetDupInfo()->GetDupeKey(),
|
|
nzbInfo->GetName(), nzbInfo->GetDupeKey()))
|
|
{
|
|
skip = true;
|
|
good = historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood;
|
|
dupeName = historyInfo->GetDupInfo()->GetName();
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!sameContent && nzbInfo->GetDupeHint() != NzbInfo::dhNone)
|
|
{
|
|
// dupe check when "download again" URLs: checking same content only
|
|
return;
|
|
}
|
|
|
|
if (!sameContent && !good && nzbInfo->GetDupeMode() == dmScore)
|
|
{
|
|
// nzb-files having success-duplicates in recent history (with different content) are added to history for backup
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
if ((historyInfo->GetKind() == HistoryInfo::hkNzb ||
|
|
historyInfo->GetKind() == HistoryInfo::hkUrl) &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() != dmForce &&
|
|
SameNameOrKey(historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey(),
|
|
nzbInfo->GetName(), nzbInfo->GetDupeKey()) &&
|
|
nzbInfo->GetDupeScore() <= historyInfo->GetNzbInfo()->GetDupeScore() &&
|
|
historyInfo->GetNzbInfo()->IsDupeSuccess())
|
|
{
|
|
// Flag saying QueueCoordinator to skip nzb-file
|
|
nzbInfo->SetDeleteStatus(NzbInfo::dsDupe);
|
|
info("Collection %s is a duplicate to %s", nzbInfo->GetName(), historyInfo->GetNzbInfo()->GetName());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (skip)
|
|
{
|
|
BString<1024> message;
|
|
if (!strcmp(nzbInfo->GetName(), dupeName))
|
|
{
|
|
message.Format("Skipping duplicate %s, found in history with %s", nzbInfo->GetName(),
|
|
sameContent ? "exactly same content" : good ? "good status" : "success status");
|
|
}
|
|
else
|
|
{
|
|
message.Format("Skipping duplicate %s, found in history %s with %s",
|
|
nzbInfo->GetName(), dupeName,
|
|
sameContent ? "exactly same content" : good ? "good status" : "success status");
|
|
}
|
|
|
|
if (nzbInfo->GetFeedId() && nzbInfo->GetDupeHint() == NzbInfo::dhNone)
|
|
{
|
|
warn("%s", *message);
|
|
// Flag saying QueueCoordinator to skip nzb-file
|
|
nzbInfo->SetDeleteStatus(NzbInfo::dsManual);
|
|
g_HistoryCoordinator->DeleteDiskFiles(nzbInfo);
|
|
}
|
|
else
|
|
{
|
|
nzbInfo->SetDeleteStatus(sameContent ? NzbInfo::dsCopy : NzbInfo::dsGood);
|
|
nzbInfo->AddMessage(Message::mkWarning, message);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// find duplicates in download queue and post-queue and handle both items according to their scores:
|
|
// only one item remains in queue and another one is moved to history as dupe-backup
|
|
if (nzbInfo->GetDupeMode() == dmScore)
|
|
{
|
|
// find duplicates in download queue
|
|
int index = 0;
|
|
for (NzbList::iterator it = downloadQueue->GetQueue()->begin(); it != downloadQueue->GetQueue()->end(); index++)
|
|
{
|
|
NzbInfo* queuedNzbInfo = (*it++).get();
|
|
if (queuedNzbInfo != nzbInfo &&
|
|
queuedNzbInfo->GetDeleteStatus() == NzbInfo::dsNone &&
|
|
(queuedNzbInfo->GetKind() == NzbInfo::nkNzb ||
|
|
(queuedNzbInfo->GetKind() == NzbInfo::nkUrl && nzbInfo->GetKind() == NzbInfo::nkUrl)) &&
|
|
queuedNzbInfo->GetDupeMode() != dmForce &&
|
|
SameNameOrKey(queuedNzbInfo->GetName(), queuedNzbInfo->GetDupeKey(),
|
|
nzbInfo->GetName(), nzbInfo->GetDupeKey()))
|
|
{
|
|
// if queue has a duplicate with the same or higher score - the new item
|
|
// is moved to history as dupe-backup
|
|
if (nzbInfo->GetDupeScore() <= queuedNzbInfo->GetDupeScore())
|
|
{
|
|
// Flag saying QueueCoordinator to skip nzb-file
|
|
nzbInfo->SetDeleteStatus(NzbInfo::dsDupe);
|
|
info("Collection %s is a duplicate to %s", nzbInfo->GetName(), queuedNzbInfo->GetName());
|
|
return;
|
|
}
|
|
|
|
// if queue has a duplicate with lower score - the existing item is moved
|
|
// to history as dupe-backup (unless it is in post-processing stage) and
|
|
// the new item is added to queue (unless it is in post-processing stage)
|
|
if (!queuedNzbInfo->GetPostInfo())
|
|
{
|
|
// the existing queue item is moved to history as dupe-backup
|
|
info("Moving collection %s with lower duplicate score to history", queuedNzbInfo->GetName());
|
|
queuedNzbInfo->SetDeleteStatus(NzbInfo::dsDupe);
|
|
int oldSize = downloadQueue->GetQueue()->size();
|
|
downloadQueue->EditEntry(queuedNzbInfo->GetId(),
|
|
DownloadQueue::eaGroupDelete, nullptr);
|
|
int newSize = downloadQueue->GetQueue()->size();
|
|
index += oldSize == newSize ? 1 : 0;
|
|
it = downloadQueue->GetQueue()->begin() + index;
|
|
index--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
- if download of an item fails and there are duplicates in history -
|
|
return the best duplicate from history to queue for download;
|
|
- if download of an item completes successfully - nothing extra needs to be done;
|
|
*/
|
|
void DupeCoordinator::NzbCompleted(DownloadQueue* downloadQueue, NzbInfo* nzbInfo)
|
|
{
|
|
debug("Processing duplicates for %s", nzbInfo->GetName());
|
|
|
|
if (nzbInfo->GetDupeMode() == dmScore && !nzbInfo->IsDupeSuccess())
|
|
{
|
|
ReturnBestDupe(downloadQueue, nzbInfo, nzbInfo->GetName(), nzbInfo->GetDupeKey());
|
|
}
|
|
}
|
|
|
|
/**
|
|
Returns the best duplicate from history to download queue.
|
|
*/
|
|
void DupeCoordinator::ReturnBestDupe(DownloadQueue* downloadQueue, NzbInfo* nzbInfo, const char* nzbName, const char* dupeKey)
|
|
{
|
|
// check if history (recent or dup) has other success-duplicates or good-duplicates
|
|
bool dupeFound = false;
|
|
int historyScore = 0;
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
bool goodDupe = false;
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() != dmForce &&
|
|
historyInfo->GetNzbInfo()->IsDupeSuccess() &&
|
|
SameNameOrKey(historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey(), nzbName, dupeKey))
|
|
{
|
|
if (!dupeFound || historyInfo->GetNzbInfo()->GetDupeScore() > historyScore)
|
|
{
|
|
historyScore = historyInfo->GetNzbInfo()->GetDupeScore();
|
|
}
|
|
dupeFound = true;
|
|
goodDupe = historyInfo->GetNzbInfo()->GetMarkStatus() == NzbInfo::ksGood;
|
|
}
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkDup &&
|
|
historyInfo->GetDupInfo()->GetDupeMode() != dmForce &&
|
|
(historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess ||
|
|
historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood) &&
|
|
SameNameOrKey(historyInfo->GetDupInfo()->GetName(), historyInfo->GetDupInfo()->GetDupeKey(), nzbName, dupeKey))
|
|
{
|
|
if (!dupeFound || historyInfo->GetDupInfo()->GetDupeScore() > historyScore)
|
|
{
|
|
historyScore = historyInfo->GetDupInfo()->GetDupeScore();
|
|
}
|
|
dupeFound = true;
|
|
goodDupe = historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood;
|
|
}
|
|
|
|
if (goodDupe)
|
|
{
|
|
// another duplicate with good-status exists - exit without moving other dupes to queue
|
|
return;
|
|
}
|
|
}
|
|
|
|
// check if duplicates exist in download queue
|
|
bool queueDupe = false;
|
|
int queueScore = 0;
|
|
for (NzbInfo* queuedNzbInfo : downloadQueue->GetQueue())
|
|
{
|
|
if (queuedNzbInfo != nzbInfo &&
|
|
queuedNzbInfo->GetKind() == NzbInfo::nkNzb &&
|
|
queuedNzbInfo->GetDupeMode() != dmForce &&
|
|
SameNameOrKey(queuedNzbInfo->GetName(), queuedNzbInfo->GetDupeKey(), nzbName, dupeKey) &&
|
|
(!queueDupe || queuedNzbInfo->GetDupeScore() > queueScore))
|
|
{
|
|
queueScore = queuedNzbInfo->GetDupeScore();
|
|
queueDupe = true;
|
|
}
|
|
}
|
|
|
|
// find dupe-backup with highest score, whose score is also higher than other
|
|
// success-duplicates and higher than already queued items
|
|
HistoryInfo* historyDupe = nullptr;
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
if ((historyInfo->GetKind() == HistoryInfo::hkNzb ||
|
|
historyInfo->GetKind() == HistoryInfo::hkUrl) &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() != dmForce &&
|
|
historyInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsDupe &&
|
|
historyInfo->GetNzbInfo()->CalcHealth() >= historyInfo->GetNzbInfo()->CalcCriticalHealth(true) &&
|
|
historyInfo->GetNzbInfo()->GetMarkStatus() != NzbInfo::ksBad &&
|
|
(!dupeFound || historyInfo->GetNzbInfo()->GetDupeScore() > historyScore) &&
|
|
(!queueDupe || historyInfo->GetNzbInfo()->GetDupeScore() > queueScore) &&
|
|
(!historyDupe || historyInfo->GetNzbInfo()->GetDupeScore() > historyDupe->GetNzbInfo()->GetDupeScore()) &&
|
|
SameNameOrKey(historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey(), nzbName, dupeKey))
|
|
{
|
|
historyDupe = historyInfo;
|
|
}
|
|
}
|
|
|
|
// move that dupe-backup from history to download queue
|
|
if (historyDupe)
|
|
{
|
|
info("Found duplicate %s for %s", historyDupe->GetNzbInfo()->GetName(), nzbName);
|
|
historyDupe->GetNzbInfo()->SetDupeHint(NzbInfo::dhRedownloadAuto);
|
|
g_HistoryCoordinator->Redownload(downloadQueue, historyDupe);
|
|
}
|
|
}
|
|
|
|
void DupeCoordinator::HistoryMark(DownloadQueue* downloadQueue, HistoryInfo* historyInfo, NzbInfo::EMarkStatus markStatus)
|
|
{
|
|
const char* markStatusName[] = { "NONE", "bad", "good", "success" };
|
|
|
|
info("Marking %s as %s", historyInfo->GetName(), markStatusName[markStatus]);
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb)
|
|
{
|
|
historyInfo->GetNzbInfo()->SetMarkStatus(markStatus);
|
|
g_QueueScriptCoordinator->EnqueueScript(historyInfo->GetNzbInfo(), QueueScriptCoordinator::qeNzbMarked);
|
|
}
|
|
else if (historyInfo->GetKind() == HistoryInfo::hkDup)
|
|
{
|
|
historyInfo->GetDupInfo()->SetStatus(
|
|
markStatus == NzbInfo::ksGood ? DupInfo::dsGood :
|
|
markStatus == NzbInfo::ksSuccess ? DupInfo::dsSuccess :
|
|
DupInfo::dsBad);
|
|
}
|
|
else
|
|
{
|
|
error("Could not mark %s as bad: history item has wrong type", historyInfo->GetName());
|
|
return;
|
|
}
|
|
|
|
if (!g_Options->GetDupeCheck() ||
|
|
(historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() == dmForce) ||
|
|
(historyInfo->GetKind() == HistoryInfo::hkDup &&
|
|
historyInfo->GetDupInfo()->GetDupeMode() == dmForce))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (markStatus == NzbInfo::ksGood)
|
|
{
|
|
// mark as good
|
|
// moving all duplicates from history to dup-history
|
|
HistoryCleanup(downloadQueue, historyInfo);
|
|
}
|
|
else if (markStatus == NzbInfo::ksBad)
|
|
{
|
|
// mark as bad
|
|
const char* dupeKey = historyInfo->GetKind() == HistoryInfo::hkNzb ? historyInfo->GetNzbInfo()->GetDupeKey() :
|
|
historyInfo->GetKind() == HistoryInfo::hkDup ? historyInfo->GetDupInfo()->GetDupeKey() :
|
|
nullptr;
|
|
ReturnBestDupe(downloadQueue, nullptr, historyInfo->GetName(), dupeKey);
|
|
}
|
|
}
|
|
|
|
void DupeCoordinator::HistoryCleanup(DownloadQueue* downloadQueue, HistoryInfo* markHistoryInfo)
|
|
{
|
|
const char* dupeKey = markHistoryInfo->GetKind() == HistoryInfo::hkNzb ? markHistoryInfo->GetNzbInfo()->GetDupeKey() :
|
|
markHistoryInfo->GetKind() == HistoryInfo::hkDup ? markHistoryInfo->GetDupInfo()->GetDupeKey() :
|
|
nullptr;
|
|
const char* nzbName = markHistoryInfo->GetKind() == HistoryInfo::hkNzb ? markHistoryInfo->GetNzbInfo()->GetName() :
|
|
markHistoryInfo->GetKind() == HistoryInfo::hkDup ? markHistoryInfo->GetDupInfo()->GetName() :
|
|
nullptr;
|
|
bool changed = false;
|
|
int index = 0;
|
|
|
|
// traversing in a reverse order to delete items in order they were added to history
|
|
// (just to produce the log-messages in a more logical order)
|
|
for (HistoryList::reverse_iterator it = downloadQueue->GetHistory()->rbegin(); it != downloadQueue->GetHistory()->rend(); )
|
|
{
|
|
HistoryInfo* historyInfo = (*it).get();
|
|
|
|
if ((historyInfo->GetKind() == HistoryInfo::hkNzb ||
|
|
historyInfo->GetKind() == HistoryInfo::hkUrl) &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() != dmForce &&
|
|
historyInfo->GetNzbInfo()->GetDeleteStatus() == NzbInfo::dsDupe &&
|
|
historyInfo != markHistoryInfo &&
|
|
SameNameOrKey(historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey(), nzbName, dupeKey))
|
|
{
|
|
g_HistoryCoordinator->HistoryHide(downloadQueue, historyInfo, index);
|
|
index++;
|
|
it = downloadQueue->GetHistory()->rbegin() + index;
|
|
changed = true;
|
|
}
|
|
else
|
|
{
|
|
it++;
|
|
index++;
|
|
}
|
|
}
|
|
|
|
if (changed)
|
|
{
|
|
downloadQueue->HistoryChanged();
|
|
downloadQueue->Save();
|
|
}
|
|
}
|
|
|
|
DupeCoordinator::EDupeStatus DupeCoordinator::GetDupeStatus(DownloadQueue* downloadQueue,
|
|
const char* name, const char* dupeKey)
|
|
{
|
|
EDupeStatus statuses = dsNone;
|
|
|
|
// find duplicates in download queue
|
|
for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
|
|
{
|
|
if (SameNameOrKey(name, dupeKey, nzbInfo->GetName(), nzbInfo->GetDupeKey()))
|
|
{
|
|
if (nzbInfo->GetSuccessArticles() + nzbInfo->GetFailedArticles() > 0)
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsDownloading);
|
|
}
|
|
else
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsQueued);
|
|
}
|
|
}
|
|
}
|
|
|
|
// find duplicates in history
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
SameNameOrKey(name, dupeKey, historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey()))
|
|
{
|
|
const char* textStatus = historyInfo->GetNzbInfo()->MakeTextStatus(true);
|
|
if (!strncasecmp(textStatus, "SUCCESS", 7))
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsSuccess);
|
|
}
|
|
else if (!strncasecmp(textStatus, "FAILURE", 7))
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsFailure);
|
|
}
|
|
else if (!strncasecmp(textStatus, "WARNING", 7))
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsWarning);
|
|
}
|
|
}
|
|
|
|
if (historyInfo->GetKind() == HistoryInfo::hkDup &&
|
|
SameNameOrKey(name, dupeKey, historyInfo->GetDupInfo()->GetName(), historyInfo->GetDupInfo()->GetDupeKey()))
|
|
{
|
|
if (historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsSuccess ||
|
|
historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsGood)
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsSuccess);
|
|
}
|
|
else if (historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsFailed ||
|
|
historyInfo->GetDupInfo()->GetStatus() == DupInfo::dsBad)
|
|
{
|
|
statuses = (EDupeStatus)(statuses | dsFailure);
|
|
}
|
|
}
|
|
}
|
|
|
|
return statuses;
|
|
}
|
|
|
|
RawNzbList DupeCoordinator::ListHistoryDupes(DownloadQueue* downloadQueue, NzbInfo* nzbInfo)
|
|
{
|
|
RawNzbList dupeList;
|
|
|
|
if (nzbInfo->GetDupeMode() == dmForce)
|
|
{
|
|
return dupeList;
|
|
}
|
|
|
|
// find duplicates in history
|
|
for (HistoryInfo* historyInfo : downloadQueue->GetHistory())
|
|
{
|
|
if (historyInfo->GetKind() == HistoryInfo::hkNzb &&
|
|
historyInfo->GetNzbInfo()->GetDupeMode() != dmForce &&
|
|
SameNameOrKey(historyInfo->GetNzbInfo()->GetName(), historyInfo->GetNzbInfo()->GetDupeKey(),
|
|
nzbInfo->GetName(), nzbInfo->GetDupeKey()))
|
|
{
|
|
dupeList.push_back(historyInfo->GetNzbInfo());
|
|
}
|
|
}
|
|
|
|
return dupeList;
|
|
}
|