2
* This file is part of nzbget
4
* Copyright (C) 2007-2014 Andrey Prygunkov <hugbug@users.sourceforge.net>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
* $Date: 2014-10-09 23:11:42 +0200 (Thu, 09 Oct 2014) $
46
#include "PrePostProcessor.h"
49
#include "HistoryCoordinator.h"
50
#include "DupeCoordinator.h"
51
#include "PostScript.h"
53
#include "Scheduler.h"
57
#include "StatMeter.h"
58
#include "QueueScript.h"
60
extern HistoryCoordinator* g_pHistoryCoordinator;
61
extern DupeCoordinator* g_pDupeCoordinator;
62
extern Options* g_pOptions;
63
extern Scheduler* g_pScheduler;
64
extern Scanner* g_pScanner;
65
extern StatMeter* g_pStatMeter;
66
extern QueueScriptCoordinator* g_pQueueScriptCoordinator;
68
PrePostProcessor::PrePostProcessor()
70
debug("Creating PrePostProcessor");
74
m_szPauseReason = NULL;
76
m_DownloadQueueObserver.m_pOwner = this;
77
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
78
pDownloadQueue->Attach(&m_DownloadQueueObserver);
79
DownloadQueue::Unlock();
82
PrePostProcessor::~PrePostProcessor()
84
debug("Destroying PrePostProcessor");
87
void PrePostProcessor::Run()
89
debug("Entering PrePostProcessor-loop");
91
while (!DownloadQueue::IsLoaded())
96
if (g_pOptions->GetServerMode() && g_pOptions->GetSaveQueue() && g_pOptions->GetReloadQueue())
98
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
99
SanitisePostQueue(pDownloadQueue);
100
DownloadQueue::Unlock();
103
g_pScheduler->FirstCheck();
105
int iDiskSpaceInterval = 1000;
106
int iSchedulerInterval = 1000;
107
int iHistoryInterval = 600000;
108
const int iStepMSec = 200;
112
// check incoming nzb directory
115
if (!g_pOptions->GetPauseDownload() &&
116
g_pOptions->GetDiskSpace() > 0 && !g_pStatMeter->GetStandBy() &&
117
iDiskSpaceInterval >= 1000)
119
// check free disk space every 1 second
121
iDiskSpaceInterval = 0;
123
iDiskSpaceInterval += iStepMSec;
125
// check post-queue every 200 msec
128
if (iSchedulerInterval >= 1000)
130
// check scheduler tasks every 1 second
131
g_pScheduler->IntervalCheck();
132
iSchedulerInterval = 0;
134
iSchedulerInterval += iStepMSec;
136
if (iHistoryInterval >= 600000)
138
// check history (remove old entries) every 10 minutes
139
g_pHistoryCoordinator->IntervalCheck();
140
iHistoryInterval = 0;
142
iHistoryInterval += iStepMSec;
144
Util::SetStandByMode(!m_pCurJob);
146
usleep(iStepMSec * 1000);
149
g_pHistoryCoordinator->Cleanup();
151
debug("Exiting PrePostProcessor-loop");
154
void PrePostProcessor::Stop()
157
DownloadQueue::Lock();
159
#ifndef DISABLE_PARCHECK
160
m_ParCoordinator.Stop();
163
if (m_pCurJob && m_pCurJob->GetPostInfo() &&
164
(m_pCurJob->GetPostInfo()->GetStage() == PostInfo::ptUnpacking ||
165
m_pCurJob->GetPostInfo()->GetStage() == PostInfo::ptExecutingScript) &&
166
m_pCurJob->GetPostInfo()->GetPostThread())
168
Thread* pPostThread = m_pCurJob->GetPostInfo()->GetPostThread();
169
m_pCurJob->GetPostInfo()->SetPostThread(NULL);
170
pPostThread->SetAutoDestroy(true);
174
DownloadQueue::Unlock();
177
void PrePostProcessor::DownloadQueueUpdate(Subject* Caller, void* Aspect)
184
DownloadQueue::Aspect* pQueueAspect = (DownloadQueue::Aspect*)Aspect;
185
if (pQueueAspect->eAction == DownloadQueue::eaNzbFound)
187
NZBFound(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
189
else if (pQueueAspect->eAction == DownloadQueue::eaNzbAdded)
191
NZBAdded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
193
else if (pQueueAspect->eAction == DownloadQueue::eaNzbDeleted &&
194
pQueueAspect->pNZBInfo->GetDeleting() &&
195
!pQueueAspect->pNZBInfo->GetPostInfo() &&
196
!pQueueAspect->pNZBInfo->GetParCleanup() &&
197
pQueueAspect->pNZBInfo->GetFileList()->empty())
199
// the deleting of nzbs is usually handled via eaFileDeleted-event, but when deleting nzb without
200
// any files left the eaFileDeleted-event is not fired and we need to process eaNzbDeleted-event instead
201
info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
202
NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
204
else if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted ||
205
pQueueAspect->eAction == DownloadQueue::eaFileDeleted))
207
if (pQueueAspect->eAction == DownloadQueue::eaFileCompleted && !pQueueAspect->pNZBInfo->GetPostInfo())
209
g_pQueueScriptCoordinator->EnqueueScript(pQueueAspect->pNZBInfo, QueueScriptCoordinator::qeFileDownloaded);
213
#ifndef DISABLE_PARCHECK
214
!m_ParCoordinator.AddPar(pQueueAspect->pFileInfo, pQueueAspect->eAction == DownloadQueue::eaFileDeleted) &&
216
IsNZBFileCompleted(pQueueAspect->pNZBInfo, true, false) &&
217
!pQueueAspect->pNZBInfo->GetPostInfo() &&
218
(!pQueueAspect->pFileInfo->GetPaused() || IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, false)))
220
if ((pQueueAspect->eAction == DownloadQueue::eaFileCompleted ||
221
(pQueueAspect->pFileInfo->GetAutoDeleted() &&
222
IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))) &&
223
pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() != NZBInfo::dsHealth)
225
info("Collection %s completely downloaded", pQueueAspect->pNZBInfo->GetName());
226
g_pQueueScriptCoordinator->EnqueueScript(pQueueAspect->pNZBInfo, QueueScriptCoordinator::qeNzbDownloaded);
227
NZBDownloaded(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
229
else if ((pQueueAspect->eAction == DownloadQueue::eaFileDeleted ||
230
(pQueueAspect->eAction == DownloadQueue::eaFileCompleted &&
231
pQueueAspect->pFileInfo->GetNZBInfo()->GetDeleteStatus() > NZBInfo::dsNone)) &&
232
!pQueueAspect->pNZBInfo->GetParCleanup() &&
233
IsNZBFileCompleted(pQueueAspect->pNZBInfo, false, true))
235
info("Collection %s deleted from queue", pQueueAspect->pNZBInfo->GetName());
236
NZBDeleted(pQueueAspect->pDownloadQueue, pQueueAspect->pNZBInfo);
242
void PrePostProcessor::NZBFound(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
244
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce)
246
g_pDupeCoordinator->NZBFound(pDownloadQueue, pNZBInfo);
250
void PrePostProcessor::NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
252
if (g_pOptions->GetParCheck() != Options::pcForce)
254
m_ParCoordinator.PausePars(pDownloadQueue, pNZBInfo);
257
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
258
pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe)
260
NZBCompleted(pDownloadQueue, pNZBInfo, false);
264
g_pQueueScriptCoordinator->EnqueueScript(pNZBInfo, QueueScriptCoordinator::qeNzbAdded);
268
void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
270
if (!pNZBInfo->GetPostInfo() && g_pOptions->GetDecode())
272
info("Queueing %s for post-processing", pNZBInfo->GetName());
274
pNZBInfo->EnterPostProcess();
277
if (pNZBInfo->GetParStatus() == NZBInfo::psNone &&
278
g_pOptions->GetParCheck() != Options::pcAlways &&
279
g_pOptions->GetParCheck() != Options::pcForce)
281
pNZBInfo->SetParStatus(NZBInfo::psSkipped);
284
if (pNZBInfo->GetRenameStatus() == NZBInfo::rsNone && !g_pOptions->GetParRename())
286
pNZBInfo->SetRenameStatus(NZBInfo::rsSkipped);
289
pDownloadQueue->Save();
293
NZBCompleted(pDownloadQueue, pNZBInfo, true);
297
void PrePostProcessor::NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
299
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone)
301
pNZBInfo->SetDeleteStatus(NZBInfo::dsManual);
303
pNZBInfo->SetDeleting(false);
305
DeleteCleanup(pNZBInfo);
307
if (pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth ||
308
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad)
310
NZBDownloaded(pDownloadQueue, pNZBInfo);
314
NZBCompleted(pDownloadQueue, pNZBInfo, true);
318
void PrePostProcessor::NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue)
320
bool bAddToHistory = g_pOptions->GetKeepHistory() > 0 && !pNZBInfo->GetAvoidHistory();
323
g_pHistoryCoordinator->AddToHistory(pDownloadQueue, pNZBInfo);
325
pNZBInfo->SetAvoidHistory(false);
327
bool bNeedSave = bAddToHistory;
329
if (g_pOptions->GetDupeCheck() && pNZBInfo->GetDupeMode() != dmForce &&
330
(pNZBInfo->GetDeleteStatus() == NZBInfo::dsNone ||
331
pNZBInfo->GetDeleteStatus() == NZBInfo::dsHealth ||
332
pNZBInfo->GetDeleteStatus() == NZBInfo::dsBad))
334
g_pDupeCoordinator->NZBCompleted(pDownloadQueue, pNZBInfo);
340
g_pHistoryCoordinator->DeleteDiskFiles(pNZBInfo);
341
pDownloadQueue->GetQueue()->Remove(pNZBInfo);
345
if (bSaveQueue && bNeedSave)
347
pDownloadQueue->Save();
351
void PrePostProcessor::DeleteCleanup(NZBInfo* pNZBInfo)
353
if ((g_pOptions->GetDeleteCleanupDisk() && pNZBInfo->GetCleanupDisk()) ||
354
pNZBInfo->GetDeleteStatus() == NZBInfo::dsDupe)
356
// download was cancelled, deleting already downloaded files from disk
357
for (CompletedFiles::reverse_iterator it = pNZBInfo->GetCompletedFiles()->rbegin(); it != pNZBInfo->GetCompletedFiles()->rend(); it++)
359
CompletedFile* pCompletedFile = *it;
361
char szFullFileName[1024];
362
snprintf(szFullFileName, 1024, "%s%c%s", pNZBInfo->GetDestDir(), (int)PATH_SEPARATOR, pCompletedFile->GetFileName());
363
szFullFileName[1024-1] = '\0';
365
if (Util::FileExists(szFullFileName))
367
detail("Deleting file %s", pCompletedFile->GetFileName());
368
remove(szFullFileName);
372
// delete .out.tmp-files and _brokenlog.txt
373
DirBrowser dir(pNZBInfo->GetDestDir());
374
while (const char* szFilename = dir.Next())
376
int iLen = strlen(szFilename);
377
if ((iLen > 8 && !strcmp(szFilename + iLen - 8, ".out.tmp")) || !strcmp(szFilename, "_brokenlog.txt"))
379
char szFullFilename[1024];
380
snprintf(szFullFilename, 1024, "%s%c%s", pNZBInfo->GetDestDir(), PATH_SEPARATOR, szFilename);
381
szFullFilename[1024-1] = '\0';
383
detail("Deleting file %s", szFilename);
384
remove(szFullFilename);
388
// delete old directory (if empty)
389
if (Util::DirEmpty(pNZBInfo->GetDestDir()))
391
rmdir(pNZBInfo->GetDestDir());
396
void PrePostProcessor::CheckDiskSpace()
398
long long lFreeSpace = Util::FreeDiskSize(g_pOptions->GetDestDir());
399
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
401
warn("Low disk space on %s. Pausing download", g_pOptions->GetDestDir());
402
g_pOptions->SetPauseDownload(true);
405
if (!Util::EmptyStr(g_pOptions->GetInterDir()))
407
lFreeSpace = Util::FreeDiskSize(g_pOptions->GetInterDir());
408
if (lFreeSpace > -1 && lFreeSpace / 1024 / 1024 < g_pOptions->GetDiskSpace())
410
warn("Low disk space on %s. Pausing download", g_pOptions->GetInterDir());
411
g_pOptions->SetPauseDownload(true);
416
void PrePostProcessor::CheckPostQueue()
418
DownloadQueue* pDownloadQueue = DownloadQueue::Lock();
420
if (!m_pCurJob && m_iJobCount > 0)
422
m_pCurJob = GetNextJob(pDownloadQueue);
427
PostInfo* pPostInfo = m_pCurJob->GetPostInfo();
428
if (!pPostInfo->GetWorking() && !IsNZBFileDownloading(m_pCurJob))
430
#ifndef DISABLE_PARCHECK
431
if (pPostInfo->GetRequestParCheck() &&
432
(pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped ||
433
(pPostInfo->GetForceRepair() && !pPostInfo->GetNZBInfo()->GetParFull())) &&
434
g_pOptions->GetParCheck() != Options::pcManual)
436
pPostInfo->SetForceParFull(pPostInfo->GetNZBInfo()->GetParStatus() > NZBInfo::psSkipped);
437
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psNone);
438
pPostInfo->SetRequestParCheck(false);
439
pPostInfo->SetStage(PostInfo::ptQueued);
440
pPostInfo->GetNZBInfo()->GetScriptStatuses()->Clear();
441
DeletePostThread(pPostInfo);
443
else if (pPostInfo->GetRequestParCheck() && pPostInfo->GetNZBInfo()->GetParStatus() <= NZBInfo::psSkipped &&
444
g_pOptions->GetParCheck() == Options::pcManual)
446
pPostInfo->SetRequestParCheck(false);
447
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psManual);
448
DeletePostThread(pPostInfo);
450
if (!pPostInfo->GetNZBInfo()->GetFileList()->empty())
452
info("Downloading all remaining files for manual par-check for %s", pPostInfo->GetNZBInfo()->GetName());
453
pDownloadQueue->EditEntry(pPostInfo->GetNZBInfo()->GetID(), DownloadQueue::eaGroupResume, 0, NULL);
454
pPostInfo->SetStage(PostInfo::ptFinished);
458
info("There are no par-files remain for download for %s", pPostInfo->GetNZBInfo()->GetName());
459
pPostInfo->SetStage(PostInfo::ptQueued);
464
if (pPostInfo->GetDeleted())
466
pPostInfo->SetStage(PostInfo::ptFinished);
469
if (pPostInfo->GetStage() == PostInfo::ptQueued &&
470
(!g_pOptions->GetPausePostProcess() || pPostInfo->GetNZBInfo()->GetForcePriority()))
472
DeletePostThread(pPostInfo);
473
StartJob(pDownloadQueue, pPostInfo);
475
else if (pPostInfo->GetStage() == PostInfo::ptFinished)
477
UpdatePauseState(false, NULL);
478
JobCompleted(pDownloadQueue, pPostInfo);
480
else if (!g_pOptions->GetPausePostProcess())
482
error("Internal error: invalid state in post-processor");
483
// TODO: cancel (delete) current job
488
DownloadQueue::Unlock();
491
NZBInfo* PrePostProcessor::GetNextJob(DownloadQueue* pDownloadQueue)
493
NZBInfo* pNZBInfo = NULL;
495
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
497
NZBInfo* pNZBInfo1 = *it;
498
if (pNZBInfo1->GetPostInfo() && !g_pQueueScriptCoordinator->HasJob(pNZBInfo1->GetID()) &&
499
(!pNZBInfo || pNZBInfo1->GetPriority() > pNZBInfo->GetPriority()) &&
500
(!g_pOptions->GetPausePostProcess() || pNZBInfo1->GetForcePriority()))
502
pNZBInfo = pNZBInfo1;
510
* Reset the state of items after reloading from disk and
511
* delete items which could not be resumed.
512
* Also count the number of post-jobs.
514
void PrePostProcessor::SanitisePostQueue(DownloadQueue* pDownloadQueue)
516
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
518
NZBInfo* pNZBInfo = *it;
519
PostInfo* pPostInfo = pNZBInfo->GetPostInfo();
523
if (pPostInfo->GetStage() == PostInfo::ptExecutingScript ||
524
!Util::DirectoryExists(pNZBInfo->GetDestDir()))
526
pPostInfo->SetStage(PostInfo::ptFinished);
530
pPostInfo->SetStage(PostInfo::ptQueued);
536
void PrePostProcessor::DeletePostThread(PostInfo* pPostInfo)
538
delete pPostInfo->GetPostThread();
539
pPostInfo->SetPostThread(NULL);
542
void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
544
if (!pPostInfo->GetStartTime())
546
pPostInfo->SetStartTime(time(NULL));
549
#ifndef DISABLE_PARCHECK
550
if (pPostInfo->GetNZBInfo()->GetRenameStatus() == NZBInfo::rsNone &&
551
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
553
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-rename");
554
m_ParCoordinator.StartParRenameJob(pPostInfo);
557
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone &&
558
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone)
560
if (m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
562
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-check");
563
m_ParCoordinator.StartParCheckJob(pPostInfo);
567
info("Nothing to par-check for %s", pPostInfo->GetNZBInfo()->GetName());
568
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSkipped);
569
pPostInfo->SetWorking(false);
570
pPostInfo->SetStage(PostInfo::ptQueued);
574
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
575
pPostInfo->GetNZBInfo()->CalcHealth() < pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) &&
576
pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) < 1000 &&
577
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
579
warn("Skipping par-check for %s due to health %.1f%% below critical %.1f%%", pPostInfo->GetNZBInfo()->GetName(),
580
pPostInfo->GetNZBInfo()->CalcHealth() / 10.0, pPostInfo->GetNZBInfo()->CalcCriticalHealth(false) / 10.0);
581
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
584
else if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSkipped &&
585
pPostInfo->GetNZBInfo()->GetFailedSize() - pPostInfo->GetNZBInfo()->GetParFailedSize() > 0 &&
586
m_ParCoordinator.FindMainPars(pPostInfo->GetNZBInfo()->GetDestDir(), NULL))
588
info("Collection %s with health %.1f%% needs par-check",
589
pPostInfo->GetNZBInfo()->GetName(), pPostInfo->GetNZBInfo()->CalcHealth() / 10.0);
590
pPostInfo->SetRequestParCheck(true);
595
NZBParameter* pUnpackParameter = pPostInfo->GetNZBInfo()->GetParameters()->Find("*Unpack:", false);
596
bool bUnpackParam = !(pUnpackParameter && !strcasecmp(pUnpackParameter->GetValue(), "no"));
597
bool bUnpack = bUnpackParam && pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone &&
598
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone;
600
bool bParFailed = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure ||
601
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible ||
602
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual;
604
bool bCleanup = !bUnpack &&
605
pPostInfo->GetNZBInfo()->GetCleanupStatus() == NZBInfo::csNone &&
606
((pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess &&
607
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usFailure &&
608
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usSpace &&
609
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usPassword) ||
610
(pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess &&
611
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)) &&
612
!Util::EmptyStr(g_pOptions->GetExtCleanupDisk());
614
bool bMoveInter = !bUnpack &&
615
pPostInfo->GetNZBInfo()->GetMoveStatus() == NZBInfo::msNone &&
616
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usFailure &&
617
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usSpace &&
618
pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usPassword &&
619
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure &&
620
pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psManual &&
621
pPostInfo->GetNZBInfo()->GetDeleteStatus() == NZBInfo::dsNone &&
622
!Util::EmptyStr(g_pOptions->GetInterDir()) &&
623
!strncmp(pPostInfo->GetNZBInfo()->GetDestDir(), g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir()));
625
bool bPostScript = true;
627
if (bUnpack && bParFailed)
629
warn("Skipping unpack for %s due to %s", pPostInfo->GetNZBInfo()->GetName(),
630
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psManual ? "required par-repair" : "par-failure");
631
pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
635
if (!bUnpack && !bMoveInter && !bPostScript)
637
pPostInfo->SetStage(PostInfo::ptFinished);
641
pPostInfo->SetProgressLabel(bUnpack ? "Unpacking" : bMoveInter ? "Moving" : "Executing post-process-script");
642
pPostInfo->SetWorking(true);
643
pPostInfo->SetStage(bUnpack ? PostInfo::ptUnpacking : bMoveInter ? PostInfo::ptMoving : PostInfo::ptExecutingScript);
644
pPostInfo->SetFileProgress(0);
645
pPostInfo->SetStageProgress(0);
647
pDownloadQueue->Save();
649
pPostInfo->SetStageTime(time(NULL));
653
UpdatePauseState(g_pOptions->GetUnpackPauseQueue(), "unpack");
654
UnpackController::StartJob(pPostInfo);
658
UpdatePauseState(g_pOptions->GetUnpackPauseQueue() || g_pOptions->GetScriptPauseQueue(), "cleanup");
659
CleanupController::StartJob(pPostInfo);
663
UpdatePauseState(g_pOptions->GetUnpackPauseQueue() || g_pOptions->GetScriptPauseQueue(), "move");
664
MoveController::StartJob(pPostInfo);
668
UpdatePauseState(g_pOptions->GetScriptPauseQueue(), "post-process-script");
669
PostScriptController::StartJob(pPostInfo);
673
void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
675
NZBInfo* pNZBInfo = pPostInfo->GetNZBInfo();
677
if (pPostInfo->GetStartTime() > 0)
679
pNZBInfo->SetPostTotalSec((int)(time(NULL) - pPostInfo->GetStartTime()));
680
pPostInfo->SetStartTime(0);
683
DeletePostThread(pPostInfo);
684
pNZBInfo->LeavePostProcess();
686
if (IsNZBFileCompleted(pNZBInfo, true, false))
688
// Cleaning up queue if par-check was successful or unpack was successful or
689
// health is 100% (if unpack and par-check were not performed)
690
// or health is below critical health
691
bool bCanCleanupQueue =
692
((pNZBInfo->GetParStatus() == NZBInfo::psSuccess ||
693
pNZBInfo->GetParStatus() == NZBInfo::psRepairPossible) &&
694
pNZBInfo->GetUnpackStatus() != NZBInfo::usFailure &&
695
pNZBInfo->GetUnpackStatus() != NZBInfo::usSpace &&
696
pNZBInfo->GetUnpackStatus() != NZBInfo::usPassword) ||
697
(pNZBInfo->GetUnpackStatus() == NZBInfo::usSuccess &&
698
pNZBInfo->GetParStatus() != NZBInfo::psFailure) ||
699
(pNZBInfo->GetUnpackStatus() <= NZBInfo::usSkipped &&
700
pNZBInfo->GetParStatus() != NZBInfo::psFailure &&
701
pNZBInfo->GetFailedSize() - pNZBInfo->GetParFailedSize() == 0) ||
702
(pNZBInfo->CalcHealth() < pNZBInfo->CalcCriticalHealth(false) &&
703
pNZBInfo->CalcCriticalHealth(false) < 1000);
704
if (g_pOptions->GetParCleanupQueue() && bCanCleanupQueue && !pNZBInfo->GetFileList()->empty())
706
info("Cleaning up download queue for %s", pNZBInfo->GetName());
707
pNZBInfo->SetParCleanup(true);
708
pDownloadQueue->EditEntry(pNZBInfo->GetID(), DownloadQueue::eaGroupDelete, 0, NULL);
711
if (pNZBInfo->GetUnpackCleanedUpDisk())
713
pNZBInfo->ClearCompletedFiles();
716
NZBCompleted(pDownloadQueue, pNZBInfo, false);
719
if (pNZBInfo == m_pCurJob)
725
pDownloadQueue->Save();
728
bool PrePostProcessor::IsNZBFileCompleted(NZBInfo* pNZBInfo, bool bIgnorePausedPars, bool bAllowOnlyOneDeleted)
732
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
734
FileInfo* pFileInfo = *it;
735
if (pFileInfo->GetDeleted())
739
if (((!pFileInfo->GetPaused() || !bIgnorePausedPars || !pFileInfo->GetParFile()) &&
740
!pFileInfo->GetDeleted()) ||
741
(bAllowOnlyOneDeleted && iDeleted > 1))
750
bool PrePostProcessor::IsNZBFileDownloading(NZBInfo* pNZBInfo)
752
if (pNZBInfo->GetActiveDownloads())
757
for (FileList::iterator it = pNZBInfo->GetFileList()->begin(); it != pNZBInfo->GetFileList()->end(); it++)
759
FileInfo* pFileInfo = *it;
760
if (!pFileInfo->GetPaused())
769
void PrePostProcessor::UpdatePauseState(bool bNeedPause, const char* szReason)
771
if (bNeedPause && !g_pOptions->GetTempPauseDownload())
773
info("Pausing download before %s", szReason);
775
else if (!bNeedPause && g_pOptions->GetTempPauseDownload())
777
info("Unpausing download after %s", m_szPauseReason);
779
g_pOptions->SetTempPauseDownload(bNeedPause);
780
m_szPauseReason = szReason;
783
bool PrePostProcessor::EditList(DownloadQueue* pDownloadQueue, IDList* pIDList, DownloadQueue::EEditAction eAction, int iOffset, const char* szText)
785
debug("Edit-command for post-processor received");
788
case DownloadQueue::eaPostDelete:
789
return PostQueueDelete(pDownloadQueue, pIDList);
796
bool PrePostProcessor::PostQueueDelete(DownloadQueue* pDownloadQueue, IDList* pIDList)
800
for (IDList::iterator itID = pIDList->begin(); itID != pIDList->end(); itID++)
804
for (NZBList::iterator it = pDownloadQueue->GetQueue()->begin(); it != pDownloadQueue->GetQueue()->end(); it++)
806
NZBInfo* pNZBInfo = *it;
807
PostInfo* pPostInfo = pNZBInfo->GetPostInfo();
808
if (pPostInfo && pNZBInfo->GetID() == iID)
810
if (pPostInfo->GetWorking())
812
info("Deleting active post-job %s", pPostInfo->GetNZBInfo()->GetName());
813
pPostInfo->SetDeleted(true);
814
#ifndef DISABLE_PARCHECK
815
if (PostInfo::ptLoadingPars <= pPostInfo->GetStage() && pPostInfo->GetStage() <= PostInfo::ptRenaming)
817
if (m_ParCoordinator.Cancel())
824
if (pPostInfo->GetPostThread())
826
debug("Terminating %s for %s", (pPostInfo->GetStage() == PostInfo::ptUnpacking ? "unpack" : "post-process-script"), pPostInfo->GetNZBInfo()->GetName());
827
pPostInfo->GetPostThread()->Stop();
832
error("Internal error in PrePostProcessor::QueueDelete");
837
info("Deleting queued post-job %s", pPostInfo->GetNZBInfo()->GetName());
838
JobCompleted(pDownloadQueue, pPostInfo);