diff --git a/DownloadInfo.cpp b/DownloadInfo.cpp index 7826f8cb..46f3e77c 100644 --- a/DownloadInfo.cpp +++ b/DownloadInfo.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -78,6 +78,42 @@ void NZBParameter::SetValue(const char* szValue) } +void NZBParameterList::SetParameter(const char* szName, const char* szValue) +{ + NZBParameter* pParameter = NULL; + bool bDelete = !szValue || !*szValue; + + for (iterator it = begin(); it != end(); it++) + { + NZBParameter* pLookupParameter = *it; + if (!strcmp(pLookupParameter->GetName(), szName)) + { + if (bDelete) + { + delete pLookupParameter; + erase(it); + return; + } + pParameter = pLookupParameter; + break; + } + } + + if (bDelete) + { + return; + } + + if (!pParameter) + { + pParameter = new NZBParameter(szName); + push_back(pParameter); + } + + pParameter->SetValue(szValue); +} + + NZBInfo::NZBInfo() { debug("Creating NZBInfo"); @@ -298,37 +334,7 @@ void NZBInfo::BuildDestDirName() void NZBInfo::SetParameter(const char* szName, const char* szValue) { - NZBParameter* pParameter = NULL; - bool bDelete = !szValue || !*szValue; - - for (NZBParameterList::iterator it = m_ppParameters.begin(); it != m_ppParameters.end(); it++) - { - NZBParameter* pLookupParameter = *it; - if (!strcmp(pLookupParameter->GetName(), szName)) - { - if (bDelete) - { - delete pLookupParameter; - m_ppParameters.erase(it); - return; - } - pParameter = pLookupParameter; - break; - } - } - - if (bDelete) - { - return; - } - - if (!pParameter) - { - pParameter = new NZBParameter(szName); - m_ppParameters.push_back(pParameter); - } - - pParameter->SetValue(szValue); + m_ppParameters.SetParameter(szName, szValue); } NZBInfo::Messages* NZBInfo::LockMessages() diff --git a/DownloadInfo.h b/DownloadInfo.h index 948d458e..5810f3f2 100644 --- a/DownloadInfo.h +++ b/DownloadInfo.h @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -174,8 +174,7 @@ private: void SetValue(const char* szValue); - friend class NZBInfo; - friend class PostInfo; + friend class NZBParameterList; public: NZBParameter(const char* szName); @@ -184,7 +183,13 @@ public: const char* GetValue() { return m_szValue; } }; -typedef std::deque NZBParameterList; +typedef std::deque NZBParameterListBase; + +class NZBParameterList : public NZBParameterListBase +{ +public: + void SetParameter(const char* szName, const char* szValue); +}; class NZBInfoList; diff --git a/QueueCoordinator.cpp b/QueueCoordinator.cpp index 36be6ac2..1f6e2cb5 100644 --- a/QueueCoordinator.cpp +++ b/QueueCoordinator.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2005 Bo Cordes Petersen - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -291,25 +291,6 @@ void QueueCoordinator::AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst) m_mutexDownloadQueue.Unlock(); } -bool QueueCoordinator::AddFileToQueue(const char* szFileName, const char* szCategory) -{ - // Parse the buffer and make it into a NZBFile - NZBFile* pNZBFile = NZBFile::CreateFromFile(szFileName, szCategory); - - // Did file parse correctly? - if (!pNZBFile) - { - return false; - } - - // Add NZBFile to Queue - AddNZBFileToQueue(pNZBFile, false); - - delete pNZBFile; - - return true; -} - /* * NOTE: see note to "AddSpeedReading" */ diff --git a/QueueCoordinator.h b/QueueCoordinator.h index 8624f62e..1852671a 100644 --- a/QueueCoordinator.h +++ b/QueueCoordinator.h @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -109,7 +109,6 @@ public: DownloadQueue* LockQueue(); void UnlockQueue() ; void AddNZBFileToQueue(NZBFile* pNZBFile, bool bAddFirst); - bool AddFileToQueue(const char* szFileName, const char* szCategory); bool HasMoreJobs() { return m_bHasMoreJobs; } bool GetStandBy() { return m_bStandBy; } bool DeleteQueueEntry(FileInfo* pFileInfo); diff --git a/Scanner.cpp b/Scanner.cpp index b6111998..b4bb58bf 100644 --- a/Scanner.cpp +++ b/Scanner.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -268,11 +268,14 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil return; } + char* szNZBCategory = strdup(szCategory); + NZBParameterList* pParameterList = new NZBParameterList; + bool bExists = true; if (m_bNZBScript && strcasecmp(szExtension, ".nzb_processed")) { - NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory); + NZBScriptController::ExecuteScript(g_pOptions->GetNZBProcess(), szFullFilename, szDirectory, &szNZBCategory, pParameterList); bExists = Util::FileExists(szFullFilename); if (bExists && strcasecmp(szExtension, ".nzb")) { @@ -289,61 +292,66 @@ void Scanner::ProcessIncomingFile(const char* szDirectory, const char* szBaseFil { char szRenamedName[1024]; bool bRenameOK = Util::RenameBak(szFullFilename, "nzb", true, szRenamedName, 1024); - if (!bRenameOK) + if (bRenameOK) + { + AddFileToQueue(szRenamedName, szNZBCategory, pParameterList); + } + else { error("Could not rename file %s to %s! Errcode: %i", szFullFilename, szRenamedName, errno); - return; } - AddFileToQueue(szRenamedName, szCategory); } else if (bExists && !strcasecmp(szExtension, ".nzb")) { - AddFileToQueue(szFullFilename, szCategory); + AddFileToQueue(szFullFilename, szNZBCategory, pParameterList); } + + for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++) + { + delete *it; + } + pParameterList->clear(); + delete pParameterList; + + free(szNZBCategory); } -void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory) +void Scanner::AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList) { const char* szBasename = Util::BaseFileName(szFilename); info("Collection %s found", szBasename); - bool bAdded = g_pQueueCoordinator->AddFileToQueue(szFilename, szCategory); - if (bAdded) - { - info("Collection %s added to queue", szBasename); - } - else + NZBFile* pNZBFile = NZBFile::CreateFromFile(szFilename, szCategory); + if (!pNZBFile) { error("Could not add collection %s to queue", szBasename); } char bakname2[1024]; - bool bRenameOK = Util::RenameBak(szFilename, bAdded ? "queued" : "error", false, bakname2, 1024); + bool bRenameOK = Util::RenameBak(szFilename, pNZBFile ? "queued" : "error", false, bakname2, 1024); if (!bRenameOK) { error("Could not rename file %s to %s! Errcode: %i", szFilename, bakname2, errno); } - if (bAdded && bRenameOK) + if (pNZBFile && bRenameOK) { - // find just added item in queue and save bakname2 into NZBInfo.QueuedFileName - DownloadQueue* pDownloadQueue = g_pQueueCoordinator->LockQueue(); - for (FileQueue::reverse_iterator it = pDownloadQueue->GetFileQueue()->rbegin(); it != pDownloadQueue->GetFileQueue()->rend(); it++) + pNZBFile->GetNZBInfo()->SetQueuedFilename(bakname2); + + for (NZBParameterList::iterator it = pParameterList->begin(); it != pParameterList->end(); it++) { - FileInfo* pFileInfo = *it; - if (!strcmp(pFileInfo->GetNZBInfo()->GetFilename(), szFilename) && - strlen(pFileInfo->GetNZBInfo()->GetQueuedFilename()) == 0) - { - pFileInfo->GetNZBInfo()->SetQueuedFilename(bakname2); - if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode()) - { - g_pDiskState->SaveDownloadQueue(pDownloadQueue); - } - break; - } + NZBParameter* pParameter = *it; + pNZBFile->GetNZBInfo()->SetParameter(pParameter->GetName(), pParameter->GetValue()); } - g_pQueueCoordinator->UnlockQueue(); + + g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, false); + info("Collection %s added to queue", szBasename); + } + + if (pNZBFile) + { + delete pNZBFile; } } diff --git a/Scanner.h b/Scanner.h index 27d504d5..6a36c879 100644 --- a/Scanner.h +++ b/Scanner.h @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -28,6 +28,7 @@ #include #include +#include "DownloadInfo.h" class Scanner { @@ -59,7 +60,7 @@ private: FileList m_FileList; void CheckIncomingNZBs(const char* szDirectory, const char* szCategory, bool bCheckStat); - void AddFileToQueue(const char* szFilename, const char* szCategory); + void AddFileToQueue(const char* szFilename, const char* szCategory, NZBParameterList* pParameterList); void ProcessIncomingFile(const char* szDirectory, const char* szBaseFilename, const char* szFullFilename, const char* szCategory); bool CanProcessFile(const char* szFullFilename, bool bCheckStat); void DropOldFiles(); diff --git a/ScriptController.cpp b/ScriptController.cpp index f979082e..a3a8ab36 100644 --- a/ScriptController.cpp +++ b/ScriptController.cpp @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -782,12 +782,15 @@ void PostScriptController::Stop() Terminate(); } -void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory) +void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBFilename, + const char* szDirectory, char** pCategory, NZBParameterList* pParameterList) { info("Executing nzb-process-script for %s", Util::BaseFileName(szNZBFilename)); NZBScriptController* pScriptController = new NZBScriptController(); pScriptController->SetScript(szScript); + pScriptController->m_pCategory = pCategory; + pScriptController->m_pParameterList = pParameterList; char szInfoName[1024]; snprintf(szInfoName, 1024, "nzb-process-script for %s", Util::BaseFileName(szNZBFilename)); @@ -822,6 +825,42 @@ void NZBScriptController::ExecuteScript(const char* szScript, const char* szNZBF delete pScriptController; } +void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText) +{ + if (!strncmp(szText, "[NZB] ", 6)) + { + debug("Command %s detected", szText + 6); + if (!strncmp(szText + 6, "CATEGORY=", 9)) + { + free(*m_pCategory); + *m_pCategory = strdup(szText + 6 + 9); + } + else if (!strncmp(szText + 6, "NZBPR_", 6)) + { + char* szParam = strdup(szText + 6 + 6); + char* szValue = strchr(szParam, '='); + if (szValue) + { + *szValue = '\0'; + m_pParameterList->SetParameter(szParam, szValue + 1); + } + else + { + error("Invalid command \"%s\" received from %s", szText, GetInfoName()); + } + free(szParam); + } + else + { + error("Invalid command \"%s\" received from %s", szText, GetInfoName()); + } + } + else + { + ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText); + } +} + void SchedulerScriptController::StartScript(const char* szCommandLine) { char** argv = NULL; diff --git a/ScriptController.h b/ScriptController.h index 1c6403e5..c8a28205 100644 --- a/ScriptController.h +++ b/ScriptController.h @@ -1,7 +1,7 @@ /* * This file is part of nzbget * - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -87,6 +87,7 @@ public: void SetWorkingDir(const char* szWorkingDir) { m_szWorkingDir = szWorkingDir; } void SetArgs(const char** szArgs, bool bFreeArgs) { m_szArgs = szArgs; m_bFreeArgs = bFreeArgs; } void SetInfoName(const char* szInfoName) { m_szInfoName = szInfoName; } + const char* GetInfoName() { return m_szInfoName; } void SetDefaultKindPrefix(const char* szDefaultKindPrefix) { m_szDefaultKindPrefix = szDefaultKindPrefix; } void SetDefaultLogKind(Options::EScriptLogKind eDefaultLogKind) { m_eDefaultLogKind = eDefaultLogKind; } void SetEnvVar(const char* szName, const char* szValue); @@ -111,8 +112,15 @@ public: class NZBScriptController : public ScriptController { +private: + char** m_pCategory; + NZBParameterList* m_pParameterList; + +protected: + virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText); + public: - static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory); + static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory, char** pCategory, NZBParameterList* pParameterList); }; class SchedulerScriptController : public Thread, ScriptController diff --git a/nzbget.conf.example b/nzbget.conf.example index 6f4ea408..9d9549e6 100644 --- a/nzbget.conf.example +++ b/nzbget.conf.example @@ -179,8 +179,9 @@ MergeNzb=no # # Example: "NzbProcess=~/nzbprocess.sh". # -# That program can unpack archives put in incoming directory, make -# filename cleanup or something else. +# That program can unpack archives which were put in incoming directory, make +# filename cleanup, assign category and post-processing parameters to nzb-file +# or do something else. # # NZBGet passes following arguments to nzbprocess-program as environment # variables: @@ -196,11 +197,23 @@ MergeNzb=no # "SERVER1_HOST". For options with predefined possible values (yes/no, etc.) # the values are passed always in lower case. # +# The nzbprocess-script can assign category or post-processing parameters +# to current nzb-file by printing special messages into standard output +# (which is processed by NZBGet). +# +# To assign category use following syntax: +# echo "[NZB] CATEGORY=my category"; +# +# To assign post-processing parameters: +# echo "[NZB] NZBPR_myvar=my value"; +# +# The prefix "NZBPR_" will be removed. In this example a post-processing +# parameter with name "myvar" and value "my value" will be associated +# with nzb-file. +# # The nzbprocess-script can delete processed file, rename it or move somewhere. # After the calling of the script the file will be either added to queue # (if it was an nzb-file) or renamed by adding the extension ".processed". -# Unpacked files will be checked on next directory scan (see option -# ). # # NOTE: Files with extensions ".processed", ".queued" and ".error" are skipped # during the directory scanning. diff --git a/nzbget.cpp b/nzbget.cpp index 93dd88d7..8ddd64cd 100644 --- a/nzbget.cpp +++ b/nzbget.cpp @@ -2,7 +2,7 @@ * This file is part of nzbget * * Copyright (C) 2004 Sven Henkel - * Copyright (C) 2007-2009 Andrei Prygounkov + * Copyright (C) 2007-2010 Andrei Prygounkov * * 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 @@ -290,10 +290,16 @@ void Run() if (!g_pOptions->GetRemoteClientMode()) { // Standalone-mode - if (!g_pOptions->GetServerMode() && !g_pQueueCoordinator->AddFileToQueue(g_pOptions->GetArgFilename(), g_pOptions->GetCategory() ? g_pOptions->GetCategory() : "")) + if (!g_pOptions->GetServerMode()) { - abort("FATAL ERROR: Parsing NZB-document %s failed\n\n", g_pOptions->GetArgFilename() ? g_pOptions->GetArgFilename() : "N/A"); - return; + NZBFile* pNZBFile = NZBFile::CreateFromFile(g_pOptions->GetArgFilename(), g_pOptions->GetCategory() ? g_pOptions->GetCategory() : ""); + if (!pNZBFile) + { + abort("FATAL ERROR: Parsing NZB-document %s failed\n\n", g_pOptions->GetArgFilename() ? g_pOptions->GetArgFilename() : "N/A"); + return; + } + g_pQueueCoordinator->AddNZBFileToQueue(pNZBFile, false); + delete pNZBFile; } if (g_pOptions->GetSaveQueue() && g_pOptions->GetServerMode())