From 6bb760375ef3a6948e5627316bbbeb2fcaf76e38 Mon Sep 17 00:00:00 2001 From: Andrey Prygunkov Date: Wed, 24 Apr 2013 20:16:04 +0000 Subject: [PATCH] added option to automatically delete unwanted files (with specified extensions) after successful par-check or unpack --- DownloadInfo.cpp | 1 + DownloadInfo.h | 10 ++++ Options.cpp | 8 +++ Options.h | 2 + PrePostProcessor.cpp | 16 ++++++ Unpack.cpp | 117 +++++++++++++++++++++++++++++++++++++++++++ Unpack.h | 15 ++++++ nzbget.conf | 8 +++ 8 files changed, 177 insertions(+) diff --git a/DownloadInfo.cpp b/DownloadInfo.cpp index 46a32c52..521174bc 100644 --- a/DownloadInfo.cpp +++ b/DownloadInfo.cpp @@ -186,6 +186,7 @@ NZBInfo::NZBInfo() m_eRenameStatus = rsNone; m_eParStatus = psNone; m_eUnpackStatus = usNone; + m_eCleanupStatus = csNone; m_eMoveStatus = msNone; m_bDeleted = false; m_bParCleanup = false; diff --git a/DownloadInfo.h b/DownloadInfo.h index ecfb24d8..320692ad 100644 --- a/DownloadInfo.h +++ b/DownloadInfo.h @@ -274,6 +274,13 @@ public: usSuccess }; + enum ECleanupStatus + { + csNone, + csFailure, + csSuccess + }; + enum EMoveStatus { msNone, @@ -299,6 +306,7 @@ private: ERenameStatus m_eRenameStatus; EParStatus m_eParStatus; EUnpackStatus m_eUnpackStatus; + ECleanupStatus m_eCleanupStatus; EMoveStatus m_eMoveStatus; char* m_szQueuedFilename; bool m_bDeleted; @@ -349,6 +357,8 @@ public: void SetParStatus(EParStatus eParStatus) { m_eParStatus = eParStatus; } EUnpackStatus GetUnpackStatus() { return m_eUnpackStatus; } void SetUnpackStatus(EUnpackStatus eUnpackStatus) { m_eUnpackStatus = eUnpackStatus; } + ECleanupStatus GetCleanupStatus() { return m_eCleanupStatus; } + void SetCleanupStatus(ECleanupStatus eCleanupStatus) { m_eCleanupStatus = eCleanupStatus; } EMoveStatus GetMoveStatus() { return m_eMoveStatus; } void SetMoveStatus(EMoveStatus eMoveStatus) { m_eMoveStatus = eMoveStatus; } const char* GetQueuedFilename() { return m_szQueuedFilename; } diff --git a/Options.cpp b/Options.cpp index e0947dea..2d831911 100644 --- a/Options.cpp +++ b/Options.cpp @@ -177,6 +177,7 @@ static const char* OPTION_SEVENZIPCMD = "SevenZipCmd"; static const char* OPTION_UNPACKPAUSEQUEUE = "UnpackPauseQueue"; static const char* OPTION_SCRIPTORDER = "ScriptOrder"; static const char* OPTION_DEFSCRIPT = "DefScript"; +static const char* OPTION_EXTCLEANUPDISK = "ExtCleanupDisk"; // obsolete options static const char* OPTION_POSTLOGKIND = "PostLogKind"; @@ -521,6 +522,7 @@ Options::Options(int argc, char* argv[]) m_szUnrarCmd = NULL; m_szSevenZipCmd = NULL; m_bUnpackPauseQueue = false; + m_szExtCleanupDisk = NULL; // Option "ConfigFile" will be initialized later, but we want // to see it at the top of option list, so we add it first @@ -713,6 +715,10 @@ Options::~Options() { free(m_szSevenZipCmd); } + if (m_szExtCleanupDisk) + { + free(m_szExtCleanupDisk); + } for (NameList::iterator it = m_EditQueueNameList.begin(); it != m_EditQueueNameList.end(); it++) { @@ -866,6 +872,7 @@ void Options::InitDefault() SetOption(OPTION_SEVENZIPCMD, "7z"); #endif SetOption(OPTION_UNPACKPAUSEQUEUE, "no"); + SetOption(OPTION_EXTCLEANUPDISK, ""); } void Options::InitOptFile() @@ -999,6 +1006,7 @@ void Options::InitOptions() m_szLogFile = strdup(GetOption(OPTION_LOGFILE)); m_szUnrarCmd = strdup(GetOption(OPTION_UNRARCMD)); m_szSevenZipCmd = strdup(GetOption(OPTION_SEVENZIPCMD)); + m_szExtCleanupDisk = strdup(GetOption(OPTION_EXTCLEANUPDISK)); m_iDownloadRate = (int)(ParseFloatValue(OPTION_DOWNLOADRATE) * 1024); m_iConnectionTimeout = ParseIntValue(OPTION_CONNECTIONTIMEOUT, 10); diff --git a/Options.h b/Options.h index 86fe3f28..94068950 100644 --- a/Options.h +++ b/Options.h @@ -305,6 +305,7 @@ private: char* m_szUnrarCmd; char* m_szSevenZipCmd; bool m_bUnpackPauseQueue; + char* m_szExtCleanupDisk; // Parsed command-line parameters bool m_bServerMode; @@ -465,6 +466,7 @@ public: const char* GetUnrarCmd() { return m_szUnrarCmd; } const char* GetSevenZipCmd() { return m_szSevenZipCmd; } bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; } + const char* GetExtCleanupDisk() { return m_szExtCleanupDisk; } Category* FindCategory(const char* szName) { return m_Categories.FindCategory(szName); } diff --git a/PrePostProcessor.cpp b/PrePostProcessor.cpp index faf18646..ca9ab88f 100644 --- a/PrePostProcessor.cpp +++ b/PrePostProcessor.cpp @@ -600,14 +600,24 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn #endif bool bUnpack = g_pOptions->GetUnpack() && (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usNone); + bool bParFailed = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure || pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible; + + bool bCleanup = !bUnpack && + pPostInfo->GetNZBInfo()->GetCleanupStatus() == NZBInfo::csNone && + (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess || + (pPostInfo->GetNZBInfo()->GetUnpackStatus() == NZBInfo::usSuccess && + pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)) && + strlen(g_pOptions->GetExtCleanupDisk()) > 0; + bool bMoveInter = !bUnpack && pPostInfo->GetNZBInfo()->GetMoveStatus() == NZBInfo::msNone && pPostInfo->GetNZBInfo()->GetUnpackStatus() != NZBInfo::usFailure && pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure && strlen(g_pOptions->GetInterDir()) > 0 && !strncmp(pPostInfo->GetNZBInfo()->GetDestDir(), g_pOptions->GetInterDir(), strlen(g_pOptions->GetInterDir())); + // TODO: check if download has pp-scripts defined bool bPostScript = true; @@ -642,6 +652,11 @@ void PrePostProcessor::StartJob(DownloadQueue* pDownloadQueue, PostInfo* pPostIn UpdatePauseState(g_pOptions->GetUnpackPauseQueue(), "unpack"); UnpackController::StartJob(pPostInfo); } + else if (bCleanup) + { + UpdatePauseState(g_pOptions->GetUnpackPauseQueue() || g_pOptions->GetScriptPauseQueue(), "cleanup"); + CleanupController::StartJob(pPostInfo); + } else if (bMoveInter) { UpdatePauseState(g_pOptions->GetUnpackPauseQueue() || g_pOptions->GetScriptPauseQueue(), "move"); @@ -1115,6 +1130,7 @@ bool PrePostProcessor::HistoryReturn(IDList* pIDList, bool bReprocess) pNZBInfo->SetParStatus(NZBInfo::psNone); pNZBInfo->SetRenameStatus(NZBInfo::rsNone); pNZBInfo->SetUnpackStatus(NZBInfo::usNone); + pNZBInfo->SetCleanupStatus(NZBInfo::csNone); } pNZBInfo->GetScriptStatuses()->Clear(); pNZBInfo->SetParkedFileCount(0); diff --git a/Unpack.cpp b/Unpack.cpp index 8f8927e6..09906eb2 100644 --- a/Unpack.cpp +++ b/Unpack.cpp @@ -715,3 +715,120 @@ bool MoveController::MoveFiles() return bOK; } + + +void CleanupController::StartJob(PostInfo* pPostInfo) +{ + CleanupController* pCleanupController = new CleanupController(); + pCleanupController->m_pPostInfo = pPostInfo; + pCleanupController->SetAutoDestroy(false); + + pPostInfo->SetPostThread(pCleanupController); + + pCleanupController->Start(); +} + +void CleanupController::Run() +{ + // the locking is needed for accessing the members of NZBInfo + g_pDownloadQueueHolder->LockQueue(); + + char szNZBName[1024]; + strncpy(szNZBName, m_pPostInfo->GetNZBInfo()->GetName(), 1024); + szNZBName[1024-1] = '\0'; + + char szInfoName[1024]; + snprintf(szInfoName, 1024, "cleanup for %s", m_pPostInfo->GetNZBInfo()->GetName()); + szInfoName[1024-1] = '\0'; + SetInfoName(szInfoName); + + SetDefaultLogKind(g_pOptions->GetProcessLogKind()); + + strncpy(m_szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024); + m_szDestDir[1024-1] = '\0'; + + g_pDownloadQueueHolder->UnlockQueue(); + + info("Cleaning up %s", szNZBName); + + bool bDeleted = false; + bool bOK = Cleanup(&bDeleted); + + szInfoName[0] = 'C'; // uppercase + + if (bOK && bDeleted) + { + info("%s successful", szInfoName); + m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess); + } + else if (bOK) + { + info("Nothing to cleanup for %s", szNZBName); + m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csSuccess); + } + else + { + error("%s failed", szInfoName); + m_pPostInfo->GetNZBInfo()->SetCleanupStatus(NZBInfo::csFailure); + } + + m_pPostInfo->SetStage(PostInfo::ptQueued); + m_pPostInfo->SetWorking(false); +} + +bool CleanupController::Cleanup(bool *bDeleted) +{ + *bDeleted = false; + bool bOK = true; + + ExtList extList; + + // split ExtCleanupDisk into tokens and create a list + char* szExtCleanupDisk = strdup(g_pOptions->GetExtCleanupDisk()); + + char* saveptr; + char* szExt = strtok_r(szExtCleanupDisk, ",; ", &saveptr); + while (szExt) + { + extList.push_back(szExt); + szExt = strtok_r(NULL, ",;", &saveptr); + } + + DirBrowser dir(m_szDestDir); + while (const char* filename = dir.Next()) + { + // check file extension + + bool bDeleteIt = false; + const char *szExt = strrchr(filename, '.'); + for (ExtList::iterator it = extList.begin(); it != extList.end(); it++) + { + const char* szExt2 = *it; + if (szExt && !strcasecmp(szExt+1, szExt2)) + { + bDeleteIt = true; + break; + } + } + + if (bDeleteIt) + { + char szFullFilename[1024]; + snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename); + szFullFilename[1024-1] = '\0'; + + PrintMessage(Message::mkInfo, "Deleting file %s", filename); + if (remove(szFullFilename) != 0) + { + PrintMessage(Message::mkError, "Could not delete file %s! Errcode: %i", szFullFilename, errno); + bOK = false; + } + + *bDeleted = true; + } + } + + free(szExtCleanupDisk); + + return bOK; +} diff --git a/Unpack.h b/Unpack.h index b63bd3d7..8e25f3bf 100644 --- a/Unpack.h +++ b/Unpack.h @@ -107,4 +107,19 @@ public: static void StartJob(PostInfo* pPostInfo); }; +class CleanupController : public Thread, public ScriptController +{ +private: + PostInfo* m_pPostInfo; + char m_szDestDir[1024]; + + bool Cleanup(bool *bDeleted); + + typedef std::deque ExtList; + +public: + virtual void Run(); + static void StartJob(PostInfo* pPostInfo); +}; + #endif diff --git a/nzbget.conf b/nzbget.conf index f45a48ea..c35d5a9a 100644 --- a/nzbget.conf +++ b/nzbget.conf @@ -976,6 +976,14 @@ ParCleanupQueue=yes # after successful check/repair. NzbCleanupDisk=no +# File extensions to delete after successful check/repair. +# +# List of file extensions to delete after successful check/repair. Extensions +# must be written without starting dots and separated with commas. +# +# Example: par2,sfv +ExtCleanupDisk=par2,1,sfv + ############################################################################## ### UNPACK ###