mirror of
https://github.com/nzbget/nzbget.git
synced 2026-04-26 15:56:53 -04:00
added built-in unpack: 1) rar and 7-zip formats are supported (via external Unrar and 7-Zip executables); 2) new options <Unpack>, <UnpackPauseQueue>, <UnpackCleanupDisk>, <UnrarCmd>, <SevenZipCmd>; 3) web-interface now shows progress and estimated time during unpack (rar only; for 7-Zip progress is not available due to limitations of 7-Zip) 4) when built-in unpack is enabled, the post-processing script is called after unpack and possibly par-check/repair (if needed); 5) for nzb-files containing multiple collections (par-sets) the post-processing script is called only once, after the last par-set; 6) new parameter <NZBPP_UNPACKSTATUS> passed to post-processing script; 7) if the option <AllowReProcess> is enabled the post-processing-script is called after each par-set (as in previous versions); 8) example post-processing script updated: removed unrar-code, added check for unpack status; 9) new field <UnpackStatus> in result of RPC-method <history>; 10) history-dialog in web-interface shows three status: par-status, unpack-status, script-status; 11) with two built-in special post-processing parameters <*Unpack:> and <*Unpack:Password> the unpack can be disabled for individual nzb-file or the password can be set; 12) built-in special post-processing parameters can be set via web-interface on page <PP-Parameters> (when built-in unpack is enabled).
This commit is contained in:
@@ -82,7 +82,7 @@ bool DiskState::SaveDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
return false;
|
||||
}
|
||||
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 17);
|
||||
fprintf(outfile, "%s%i\n", FORMATVERSION_SIGNATURE, 18);
|
||||
|
||||
// save nzb-infos
|
||||
SaveNZBList(pDownloadQueue, outfile);
|
||||
@@ -136,7 +136,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
int iFormatVersion = ParseFormatVersion(FileSignatur);
|
||||
if (iFormatVersion < 3 || iFormatVersion > 17)
|
||||
if (iFormatVersion < 3 || iFormatVersion > 18)
|
||||
{
|
||||
error("Could not load diskstate due to file version mismatch");
|
||||
fclose(infile);
|
||||
@@ -152,7 +152,7 @@ bool DiskState::LoadDownloadQueue(DownloadQueue* pDownloadQueue)
|
||||
if (iFormatVersion >= 7)
|
||||
{
|
||||
// load post-queue
|
||||
if (!LoadPostQueue(pDownloadQueue, infile)) goto error;
|
||||
if (!LoadPostQueue(pDownloadQueue, infile, iFormatVersion)) goto error;
|
||||
}
|
||||
else if (iFormatVersion < 7 && g_pOptions->GetReloadPostQueue())
|
||||
{
|
||||
@@ -204,8 +204,7 @@ void DiskState::SaveNZBList(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetName());
|
||||
fprintf(outfile, "%s\n", pNZBInfo->GetCategory());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetPostProcess() ? 1 : 0);
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetParStatus());
|
||||
fprintf(outfile, "%i\n", (int)pNZBInfo->GetScriptStatus());
|
||||
fprintf(outfile, "%i,%i,%i\n", (int)pNZBInfo->GetParStatus(), (int)pNZBInfo->GetUnpackStatus(), (int)pNZBInfo->GetScriptStatus());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetFileCount());
|
||||
fprintf(outfile, "%i\n", pNZBInfo->GetParkedFileCount());
|
||||
|
||||
@@ -301,20 +300,29 @@ bool DiskState::LoadNZBList(DownloadQueue* pDownloadQueue, FILE* infile, int iFo
|
||||
pNZBInfo->SetPostProcess(iPostProcess == 1);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 8)
|
||||
if (iFormatVersion >= 8 && iFormatVersion < 18)
|
||||
{
|
||||
int iParStatus;
|
||||
if (fscanf(infile, "%i\n", &iParStatus) != 1) goto error;
|
||||
pNZBInfo->SetParStatus((NZBInfo::EParStatus)iParStatus);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 9)
|
||||
if (iFormatVersion >= 9 && iFormatVersion < 18)
|
||||
{
|
||||
int iScriptStatus;
|
||||
if (fscanf(infile, "%i\n", &iScriptStatus) != 1) goto error;
|
||||
pNZBInfo->SetScriptStatus((NZBInfo::EScriptStatus)iScriptStatus);
|
||||
}
|
||||
|
||||
if (iFormatVersion >= 18)
|
||||
{
|
||||
int iParStatus, iUnpackStatus, iScriptStatus;
|
||||
if (fscanf(infile, "%i,%i,%i\n", &iParStatus, &iUnpackStatus, &iScriptStatus) != 3) goto error;
|
||||
pNZBInfo->SetParStatus((NZBInfo::EParStatus)iParStatus);
|
||||
pNZBInfo->SetUnpackStatus((NZBInfo::EUnpackStatus)iUnpackStatus);
|
||||
pNZBInfo->SetScriptStatus((NZBInfo::EScriptStatus)iScriptStatus);
|
||||
}
|
||||
|
||||
int iFileCount;
|
||||
if (fscanf(infile, "%i\n", &iFileCount) != 1) goto error;
|
||||
pNZBInfo->SetFileCount(iFileCount);
|
||||
@@ -610,7 +618,7 @@ void DiskState::SavePostQueue(DownloadQueue* pDownloadQueue, FILE* outfile)
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion)
|
||||
{
|
||||
debug("Loading post-queue from disk");
|
||||
|
||||
@@ -625,6 +633,7 @@ bool DiskState::LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile)
|
||||
PostInfo* pPostInfo = NULL;
|
||||
unsigned int iNZBIndex, iParCheck, iParStatus, iStage;
|
||||
if (fscanf(infile, "%i,%i,%i,%i\n", &iNZBIndex, &iParCheck, &iParStatus, &iStage) != 4) goto error;
|
||||
if (iFormatVersion < 18 && iStage > (int)PostInfo::ptVerifyingRepaired) iStage++;
|
||||
|
||||
if (!bSkipPostQueue)
|
||||
{
|
||||
@@ -1023,7 +1032,7 @@ bool DiskState::DiscardDownloadQueue()
|
||||
char FileSignatur[128];
|
||||
fgets(FileSignatur, sizeof(FileSignatur), infile);
|
||||
int iFormatVersion = ParseFormatVersion(FileSignatur);
|
||||
if (3 <= iFormatVersion && iFormatVersion <= 17)
|
||||
if (3 <= iFormatVersion && iFormatVersion <= 18)
|
||||
{
|
||||
// skip nzb-infos
|
||||
int size = 0;
|
||||
@@ -1046,14 +1055,18 @@ bool DiskState::DiscardDownloadQueue()
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // category
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // postprocess
|
||||
}
|
||||
if (iFormatVersion >= 8)
|
||||
if (iFormatVersion >= 8 && iFormatVersion < 18)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ParStatus
|
||||
}
|
||||
if (iFormatVersion >= 9)
|
||||
if (iFormatVersion >= 9 && iFormatVersion < 18)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ScriptStatus
|
||||
}
|
||||
if (iFormatVersion >= 18)
|
||||
{
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // ParStatus, UnpackStatus, ScriptStatus
|
||||
}
|
||||
if (!fgets(buf, sizeof(buf), infile)) break; // file count
|
||||
if (iFormatVersion >= 10)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2009 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
void SaveFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQueue, FILE* outfile);
|
||||
bool LoadFileQueue(DownloadQueue* pDownloadQueue, FileQueue* pFileQueue, FILE* infile, int iFormatVersion);
|
||||
void SavePostQueue(DownloadQueue* pDownloadQueue, FILE* outfile);
|
||||
bool LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile);
|
||||
bool LoadPostQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
|
||||
bool LoadOldPostQueue(DownloadQueue* pDownloadQueue);
|
||||
void SaveUrlQueue(DownloadQueue* pDownloadQueue, FILE* outfile);
|
||||
bool LoadUrlQueue(DownloadQueue* pDownloadQueue, FILE* infile, int iFormatVersion);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2004 Sven Henkel <sidddy@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -130,7 +130,8 @@ NZBInfo::NZBInfo()
|
||||
m_lSize = 0;
|
||||
m_iRefCount = 0;
|
||||
m_bPostProcess = false;
|
||||
m_eParStatus = prNone;
|
||||
m_eParStatus = psNone;
|
||||
m_eUnpackStatus = usNone;
|
||||
m_eScriptStatus = srNone;
|
||||
m_bDeleted = false;
|
||||
m_bParCleanup = false;
|
||||
@@ -350,9 +351,8 @@ void NZBInfo::AppendMessage(Message::EKind eKind, time_t tTime, const char * szT
|
||||
tTime = time(NULL);
|
||||
}
|
||||
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, tTime, szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
m_mutexLog.Unlock();
|
||||
}
|
||||
@@ -610,6 +610,7 @@ PostInfo::PostInfo()
|
||||
m_bDeleted = false;
|
||||
m_bParCheck = false;
|
||||
m_eParStatus = psNone;
|
||||
m_eUnpackStatus = usNone;
|
||||
m_eRequestParCheck = rpNone;
|
||||
m_eScriptStatus = srNone;
|
||||
m_szProgressLabel = strdup("");
|
||||
@@ -696,9 +697,8 @@ void PostInfo::UnlockMessages()
|
||||
|
||||
void PostInfo::AppendMessage(Message::EKind eKind, const char * szText)
|
||||
{
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
|
||||
m_mutexLog.Lock();
|
||||
Message* pMessage = new Message(++m_iIDMessageGen, eKind, time(NULL), szText);
|
||||
m_Messages.push_back(pMessage);
|
||||
|
||||
while (m_Messages.size() > (unsigned int)g_pOptions->GetLogBufferSize())
|
||||
|
||||
@@ -216,10 +216,18 @@ class NZBInfo
|
||||
public:
|
||||
enum EParStatus
|
||||
{
|
||||
prNone,
|
||||
prFailure,
|
||||
prRepairPossible,
|
||||
prSuccess
|
||||
psNone,
|
||||
psFailure,
|
||||
psRepairPossible,
|
||||
psSuccess
|
||||
};
|
||||
|
||||
enum EUnpackStatus
|
||||
{
|
||||
usNone,
|
||||
usSkipped,
|
||||
usFailure,
|
||||
usSuccess
|
||||
};
|
||||
|
||||
enum EScriptStatus
|
||||
@@ -246,6 +254,7 @@ private:
|
||||
Files m_completedFiles;
|
||||
bool m_bPostProcess;
|
||||
EParStatus m_eParStatus;
|
||||
EUnpackStatus m_eUnpackStatus;
|
||||
EScriptStatus m_eScriptStatus;
|
||||
char* m_szQueuedFilename;
|
||||
bool m_bDeleted;
|
||||
@@ -289,6 +298,8 @@ public:
|
||||
void SetPostProcess(bool bPostProcess) { m_bPostProcess = bPostProcess; }
|
||||
EParStatus GetParStatus() { return m_eParStatus; }
|
||||
void SetParStatus(EParStatus eParStatus) { m_eParStatus = eParStatus; }
|
||||
EUnpackStatus GetUnpackStatus() { return m_eUnpackStatus; }
|
||||
void SetUnpackStatus(EUnpackStatus eUnpackStatus) { m_eUnpackStatus = eUnpackStatus; }
|
||||
EScriptStatus GetScriptStatus() { return m_eScriptStatus; }
|
||||
void SetScriptStatus(EScriptStatus eScriptStatus) { m_eScriptStatus = eScriptStatus; }
|
||||
const char* GetQueuedFilename() { return m_szQueuedFilename; }
|
||||
@@ -326,6 +337,7 @@ public:
|
||||
ptVerifyingSources,
|
||||
ptRepairing,
|
||||
ptVerifyingRepaired,
|
||||
ptUnpacking,
|
||||
ptExecutingScript,
|
||||
ptFinished
|
||||
};
|
||||
@@ -345,6 +357,14 @@ public:
|
||||
rpAll
|
||||
};
|
||||
|
||||
enum EUnpackStatus
|
||||
{
|
||||
usNone,
|
||||
usSkipped,
|
||||
usFailure,
|
||||
usSuccess
|
||||
};
|
||||
|
||||
enum EScriptStatus
|
||||
{
|
||||
srNone,
|
||||
@@ -364,6 +384,7 @@ private:
|
||||
bool m_bDeleted;
|
||||
bool m_bParCheck;
|
||||
EParStatus m_eParStatus;
|
||||
EUnpackStatus m_eUnpackStatus;
|
||||
EScriptStatus m_eScriptStatus;
|
||||
ERequestParCheck m_eRequestParCheck;
|
||||
EStage m_eStage;
|
||||
@@ -410,6 +431,8 @@ public:
|
||||
void SetParCheck(bool bParCheck) { m_bParCheck = bParCheck; }
|
||||
EParStatus GetParStatus() { return m_eParStatus; }
|
||||
void SetParStatus(EParStatus eParStatus) { m_eParStatus = eParStatus; }
|
||||
EUnpackStatus GetUnpackStatus() { return m_eUnpackStatus; }
|
||||
void SetUnpackStatus(EUnpackStatus eUnpackStatus) { m_eUnpackStatus = eUnpackStatus; }
|
||||
ERequestParCheck GetRequestParCheck() { return m_eRequestParCheck; }
|
||||
void SetRequestParCheck(ERequestParCheck eRequestParCheck) { m_eRequestParCheck = eRequestParCheck; }
|
||||
EScriptStatus GetScriptStatus() { return m_eScriptStatus; }
|
||||
|
||||
@@ -34,7 +34,7 @@ nzbget_SOURCES = \
|
||||
RemoteServer.cpp RemoteServer.h Scanner.cpp Scanner.h Scheduler.cpp Scheduler.h ScriptController.cpp \
|
||||
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h \
|
||||
Util.cpp Util.h XmlRpc.cpp XmlRpc.h WebDownloader.cpp WebDownloader.h WebServer.cpp WebServer.h \
|
||||
UrlCoordinator.cpp UrlCoordinator.h nzbget.cpp nzbget.h
|
||||
UrlCoordinator.cpp UrlCoordinator.h Unpack.cpp Unpack.h nzbget.cpp nzbget.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd nzbget-postprocess.sh \
|
||||
|
||||
@@ -97,7 +97,8 @@ am_nzbget_OBJECTS = ArticleDownloader.$(OBJEXT) BinRpc.$(OBJEXT) \
|
||||
ScriptController.$(OBJEXT) ServerPool.$(OBJEXT) \
|
||||
svn_version.$(OBJEXT) TLS.$(OBJEXT) Thread.$(OBJEXT) \
|
||||
Util.$(OBJEXT) XmlRpc.$(OBJEXT) WebDownloader.$(OBJEXT) \
|
||||
WebServer.$(OBJEXT) UrlCoordinator.$(OBJEXT) nzbget.$(OBJEXT)
|
||||
WebServer.$(OBJEXT) UrlCoordinator.$(OBJEXT) Unpack.$(OBJEXT) \
|
||||
nzbget.$(OBJEXT)
|
||||
nzbget_OBJECTS = $(am_nzbget_OBJECTS)
|
||||
nzbget_LDADD = $(LDADD)
|
||||
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
|
||||
@@ -254,7 +255,7 @@ nzbget_SOURCES = \
|
||||
RemoteServer.cpp RemoteServer.h Scanner.cpp Scanner.h Scheduler.cpp Scheduler.h ScriptController.cpp \
|
||||
ScriptController.h ServerPool.cpp ServerPool.h svn_version.cpp TLS.cpp TLS.h Thread.cpp Thread.h \
|
||||
Util.cpp Util.h XmlRpc.cpp XmlRpc.h WebDownloader.cpp WebDownloader.h WebServer.cpp WebServer.h \
|
||||
UrlCoordinator.cpp UrlCoordinator.h nzbget.cpp nzbget.h
|
||||
UrlCoordinator.cpp UrlCoordinator.h Unpack.cpp Unpack.h nzbget.cpp nzbget.h
|
||||
|
||||
EXTRA_DIST = \
|
||||
Makefile.cvs nzbgetd nzbget-postprocess.sh \
|
||||
@@ -456,6 +457,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerPool.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TLS.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Unpack.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UrlCoordinator.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/WebDownloader.Po@am__quote@
|
||||
|
||||
40
Options.cpp
40
Options.cpp
@@ -171,6 +171,11 @@ static const char* OPTION_MERGENZB = "MergeNzb";
|
||||
static const char* OPTION_PARTIMELIMIT = "ParTimeLimit";
|
||||
static const char* OPTION_KEEPHISTORY = "KeepHistory";
|
||||
static const char* OPTION_ACCURATERATE = "AccurateRate";
|
||||
static const char* OPTION_UNPACK = "Unpack";
|
||||
static const char* OPTION_UNPACKCLEANUPDISK = "UnpackCleanupDisk";
|
||||
static const char* OPTION_UNRARCMD = "UnrarCmd";
|
||||
static const char* OPTION_SEVENZIPCMD = "SevenZipCmd";
|
||||
static const char* OPTION_UNPACKPAUSEQUEUE = "UnpackPauseQueue";
|
||||
|
||||
// obsolete options
|
||||
static const char* OPTION_POSTLOGKIND = "PostLogKind";
|
||||
@@ -431,6 +436,11 @@ Options::Options(int argc, char* argv[])
|
||||
m_bAccurateRate = false;
|
||||
m_EMatchMode = mmID;
|
||||
m_tResumeTime = 0;
|
||||
m_bUnpack = false;
|
||||
m_bUnpackCleanupDisk = false;
|
||||
m_szUnrarCmd = NULL;
|
||||
m_szSevenZipCmd = NULL;
|
||||
m_bUnpackPauseQueue = false;
|
||||
|
||||
// Option "ConfigFile" will be initialized later, but we want
|
||||
// to see it at the top of option list, so we add it first
|
||||
@@ -603,6 +613,14 @@ Options::~Options()
|
||||
{
|
||||
free(m_szAddNZBFilename);
|
||||
}
|
||||
if (m_szUnrarCmd)
|
||||
{
|
||||
free(m_szUnrarCmd);
|
||||
}
|
||||
if (m_szSevenZipCmd)
|
||||
{
|
||||
free(m_szSevenZipCmd);
|
||||
}
|
||||
|
||||
for (NameList::iterator it = m_EditQueueNameList.begin(); it != m_EditQueueNameList.end(); it++)
|
||||
{
|
||||
@@ -731,6 +749,16 @@ void Options::InitDefault()
|
||||
SetOption(OPTION_PARTIMELIMIT, "0");
|
||||
SetOption(OPTION_KEEPHISTORY, "7");
|
||||
SetOption(OPTION_ACCURATERATE, "no");
|
||||
SetOption(OPTION_UNPACK, "no");
|
||||
SetOption(OPTION_UNPACKCLEANUPDISK, "no");
|
||||
#ifdef WIN32
|
||||
SetOption(OPTION_UNRARCMD, "unrar.exe");
|
||||
SetOption(OPTION_SEVENZIPCMD, "7z.exe");
|
||||
#else
|
||||
SetOption(OPTION_UNRARCMD, "unrar");
|
||||
SetOption(OPTION_SEVENZIPCMD, "7z");
|
||||
#endif
|
||||
SetOption(OPTION_UNPACKPAUSEQUEUE, "no");
|
||||
}
|
||||
|
||||
void Options::InitOptFile()
|
||||
@@ -858,6 +886,8 @@ void Options::InitOptions()
|
||||
m_szLockFile = strdup(GetOption(OPTION_LOCKFILE));
|
||||
m_szDaemonUserName = strdup(GetOption(OPTION_DAEMONUSERNAME));
|
||||
m_szLogFile = strdup(GetOption(OPTION_LOGFILE));
|
||||
m_szUnrarCmd = strdup(GetOption(OPTION_UNRARCMD));
|
||||
m_szSevenZipCmd = strdup(GetOption(OPTION_SEVENZIPCMD));
|
||||
|
||||
m_iDownloadRate = (int)(ParseFloatValue(OPTION_DOWNLOADRATE) * 1024);
|
||||
m_iConnectionTimeout = ParseIntValue(OPTION_CONNECTIONTIMEOUT, 10);
|
||||
@@ -912,6 +942,9 @@ void Options::InitOptions()
|
||||
m_bMergeNzb = (bool)ParseEnumValue(OPTION_MERGENZB, BoolCount, BoolNames, BoolValues);
|
||||
m_bAccurateRate = (bool)ParseEnumValue(OPTION_ACCURATERATE, BoolCount, BoolNames, BoolValues);
|
||||
m_bSecureControl = (bool)ParseEnumValue(OPTION_SECURECONTROL, BoolCount, BoolNames, BoolValues);
|
||||
m_bUnpack = (bool)ParseEnumValue(OPTION_UNPACK, BoolCount, BoolNames, BoolValues);
|
||||
m_bUnpackCleanupDisk = (bool)ParseEnumValue(OPTION_UNPACKCLEANUPDISK, BoolCount, BoolNames, BoolValues);
|
||||
m_bUnpackPauseQueue = (bool)ParseEnumValue(OPTION_UNPACKPAUSEQUEUE, BoolCount, BoolNames, BoolValues);
|
||||
|
||||
const char* OutputModeNames[] = { "loggable", "logable", "log", "colored", "color", "ncurses", "curses" };
|
||||
const int OutputModeValues[] = { omLoggable, omLoggable, omLoggable, omColored, omColored, omNCurses, omNCurses };
|
||||
@@ -2350,6 +2383,13 @@ void Options::CheckOptions()
|
||||
{
|
||||
m_bDirectWrite = false;
|
||||
}
|
||||
|
||||
if (m_bUnpack && m_bAllowReProcess)
|
||||
{
|
||||
LocateOptionSrcPos(OPTION_ALLOWREPROCESS);
|
||||
ConfigError("Options \"%s\" and \"%s\" cannot be both active at the same time", OPTION_UNPACK, OPTION_ALLOWREPROCESS);
|
||||
m_bAllowReProcess = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Options::ParseFileIDList(int argc, char* argv[], int optind)
|
||||
|
||||
11
Options.h
11
Options.h
@@ -255,6 +255,11 @@ private:
|
||||
int m_iParTimeLimit;
|
||||
int m_iKeepHistory;
|
||||
bool m_bAccurateRate;
|
||||
bool m_bUnpack;
|
||||
bool m_bUnpackCleanupDisk;
|
||||
char* m_szUnrarCmd;
|
||||
char* m_szSevenZipCmd;
|
||||
bool m_bUnpackPauseQueue;
|
||||
|
||||
// Parsed command-line parameters
|
||||
bool m_bServerMode;
|
||||
@@ -405,6 +410,12 @@ public:
|
||||
int GetParTimeLimit() { return m_iParTimeLimit; }
|
||||
int GetKeepHistory() { return m_iKeepHistory; }
|
||||
bool GetAccurateRate() { return m_bAccurateRate; }
|
||||
bool GetUnpack() { return m_bUnpack; }
|
||||
bool GetUnpackCleanupDisk() { return m_bUnpackCleanupDisk; }
|
||||
const char* GetUnrarCmd() { return m_szUnrarCmd; }
|
||||
const char* GetSevenZipCmd() { return m_szSevenZipCmd; }
|
||||
bool GetUnpackPauseQueue() { return m_bUnpackPauseQueue; }
|
||||
|
||||
Category* FindCategory(const char* szName) { return m_Categories.FindCategory(szName); }
|
||||
|
||||
// Parsed command-line parameters
|
||||
|
||||
@@ -130,13 +130,22 @@ void ParCoordinator::PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo)
|
||||
|
||||
bool ParCoordinator::FindMainPars(const char* szPath, FileList* pFileList)
|
||||
{
|
||||
pFileList->clear();
|
||||
if (pFileList)
|
||||
{
|
||||
pFileList->clear();
|
||||
}
|
||||
|
||||
DirBrowser dir(szPath);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
int iBaseLen = 0;
|
||||
if (ParseParFilename(filename, &iBaseLen, NULL))
|
||||
{
|
||||
if (!pFileList)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if the base file already added to list
|
||||
bool exists = false;
|
||||
for (FileList::iterator it = pFileList->begin(); it != pFileList->end(); it++)
|
||||
@@ -154,7 +163,7 @@ bool ParCoordinator::FindMainPars(const char* szPath, FileList* pFileList)
|
||||
}
|
||||
}
|
||||
}
|
||||
return !pFileList->empty();
|
||||
return pFileList && !pFileList->empty();
|
||||
}
|
||||
|
||||
bool ParCoordinator::SameParCollection(const char* szFilename1, const char* szFilename2)
|
||||
@@ -226,14 +235,6 @@ bool ParCoordinator::ParseParFilename(const char* szParFilename, int* iBaseNameL
|
||||
*/
|
||||
void ParCoordinator::StartParJob(PostInfo* pPostInfo)
|
||||
{
|
||||
if (g_pOptions->GetParPauseQueue())
|
||||
{
|
||||
if (PauseDownload())
|
||||
{
|
||||
info("Pausing queue before par-check");
|
||||
}
|
||||
}
|
||||
|
||||
info("Checking pars for %s", pPostInfo->GetInfoName());
|
||||
m_ParChecker.SetPostInfo(pPostInfo);
|
||||
m_ParChecker.SetParFilename(pPostInfo->GetParFilename());
|
||||
@@ -357,23 +358,23 @@ void ParCoordinator::ParCheckerUpdate(Subject* Caller, void* Aspect)
|
||||
if (m_ParChecker.GetStatus() == ParChecker::psFailed && !m_ParChecker.GetCancelled())
|
||||
{
|
||||
pPostInfo->SetParStatus(PostInfo::psFailure);
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::prFailure);
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psFailure);
|
||||
}
|
||||
else if (m_ParChecker.GetStatus() == ParChecker::psFinished &&
|
||||
(g_pOptions->GetParRepair() || m_ParChecker.GetRepairNotNeeded()))
|
||||
{
|
||||
pPostInfo->SetParStatus(PostInfo::psSuccess);
|
||||
if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::prNone)
|
||||
if (pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psNone)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::prSuccess);
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psSuccess);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pPostInfo->SetParStatus(PostInfo::psRepairPossible);
|
||||
if (pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::prFailure)
|
||||
if (pPostInfo->GetNZBInfo()->GetParStatus() != NZBInfo::psFailure)
|
||||
{
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::prRepairPossible);
|
||||
pPostInfo->GetNZBInfo()->SetParStatus(NZBInfo::psRepairPossible);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,14 +384,6 @@ void ParCoordinator::ParCheckerUpdate(Subject* Caller, void* Aspect)
|
||||
}
|
||||
|
||||
g_pQueueCoordinator->UnlockQueue();
|
||||
|
||||
if (g_pOptions->GetParPauseQueue() && !(g_pOptions->GetPostPauseQueue() && m_bPostScript))
|
||||
{
|
||||
if (UnpauseDownload())
|
||||
{
|
||||
info("Unpausing queue after par-check");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -87,9 +87,9 @@ public:
|
||||
public:
|
||||
ParCoordinator();
|
||||
virtual ~ParCoordinator();
|
||||
bool FindMainPars(const char* szPath, FileList* pFileList);
|
||||
bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
|
||||
bool SameParCollection(const char* szFilename1, const char* szFilename2);
|
||||
static bool FindMainPars(const char* szPath, FileList* pFileList);
|
||||
static bool ParseParFilename(const char* szParFilename, int* iBaseNameLen, int* iBlocks);
|
||||
static bool SameParCollection(const char* szFilename1, const char* szFilename2);
|
||||
void PausePars(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "DiskState.h"
|
||||
#include "Util.h"
|
||||
#include "Scheduler.h"
|
||||
#include "Unpack.h"
|
||||
|
||||
extern QueueCoordinator* g_pQueueCoordinator;
|
||||
extern Options* g_pOptions;
|
||||
@@ -182,7 +183,9 @@ void PrePostProcessor::Stop()
|
||||
if (!pDownloadQueue->GetPostQueue()->empty())
|
||||
{
|
||||
PostInfo* pPostInfo = pDownloadQueue->GetPostQueue()->front();
|
||||
if (pPostInfo->GetStage() == PostInfo::ptExecutingScript && pPostInfo->GetScriptThread())
|
||||
if ((pPostInfo->GetStage() == PostInfo::ptUnpacking ||
|
||||
pPostInfo->GetStage() == PostInfo::ptExecutingScript) &&
|
||||
pPostInfo->GetScriptThread())
|
||||
{
|
||||
Thread* pScriptThread = pPostInfo->GetScriptThread();
|
||||
pPostInfo->SetScriptThread(NULL);
|
||||
@@ -261,7 +264,7 @@ void PrePostProcessor::NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZ
|
||||
#else
|
||||
bool bParCheck = g_pOptions->GetParCheck() && g_pOptions->GetDecode();
|
||||
#endif
|
||||
if ((bParCheck || m_bPostScript) &&
|
||||
if ((bParCheck || m_bPostScript || g_pOptions->GetUnpack()) &&
|
||||
CreatePostJobs(pDownloadQueue, pNZBInfo, bParCheck, true, false))
|
||||
{
|
||||
pNZBInfo->SetPostProcess(true);
|
||||
@@ -505,24 +508,18 @@ void PrePostProcessor::CheckPostQueue()
|
||||
|
||||
if (pPostInfo->GetParCheck() && pPostInfo->GetParStatus() == PostInfo::psNone && !g_pOptions->GetPausePostProcess())
|
||||
{
|
||||
UpdatePauseState(g_pOptions->GetParPauseQueue(), "par-check");
|
||||
m_ParCoordinator.StartParJob(pPostInfo);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (pPostInfo->GetStage() == PostInfo::ptQueued && !g_pOptions->GetPausePostProcess())
|
||||
{
|
||||
StartScriptJob(pDownloadQueue, pPostInfo);
|
||||
StartProcessJob(pDownloadQueue, pPostInfo);
|
||||
}
|
||||
else if (pPostInfo->GetStage() == PostInfo::ptFinished)
|
||||
{
|
||||
if (m_bPostScript && g_pOptions->GetPostPauseQueue())
|
||||
{
|
||||
if (UnpauseDownload())
|
||||
{
|
||||
info("Unpausing queue after post-process-script");
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePauseState(false, NULL);
|
||||
JobCompleted(pDownloadQueue, pPostInfo);
|
||||
}
|
||||
else if (!g_pOptions->GetPausePostProcess())
|
||||
@@ -565,17 +562,31 @@ void PrePostProcessor::SanitisePostQueue(PostQueue* pPostQueue)
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::StartScriptJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
|
||||
void PrePostProcessor::StartProcessJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
|
||||
{
|
||||
if (!m_bPostScript)
|
||||
bool bUnpack = g_pOptions->GetUnpack() && (pPostInfo->GetUnpackStatus() == PostInfo::usNone);
|
||||
bool bNZBFileCompleted = IsNZBFileCompleted(pDownloadQueue, pPostInfo->GetNZBInfo(), true, true, false);
|
||||
bool bHasFailedParJobs = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psFailure ||
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible;
|
||||
|
||||
if (bUnpack && bHasFailedParJobs)
|
||||
{
|
||||
warn("Skipping unpack due to par-failure for %s", pPostInfo->GetInfoName());
|
||||
pPostInfo->SetUnpackStatus(PostInfo::usSkipped);
|
||||
pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
|
||||
bUnpack = false;
|
||||
}
|
||||
|
||||
if ((!bNZBFileCompleted && !(m_bPostScript && g_pOptions->GetAllowReProcess())) ||
|
||||
(!bUnpack && !m_bPostScript))
|
||||
{
|
||||
pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
return;
|
||||
}
|
||||
|
||||
pPostInfo->SetProgressLabel("Executing post-process-script");
|
||||
pPostInfo->SetProgressLabel(bUnpack ? "Unpacking" : "Executing post-process-script");
|
||||
pPostInfo->SetWorking(true);
|
||||
pPostInfo->SetStage(PostInfo::ptExecutingScript);
|
||||
pPostInfo->SetStage(bUnpack ? PostInfo::ptUnpacking : PostInfo::ptExecutingScript);
|
||||
pPostInfo->SetFileProgress(0);
|
||||
pPostInfo->SetStageProgress(0);
|
||||
SaveQueue(pDownloadQueue);
|
||||
@@ -586,19 +597,16 @@ void PrePostProcessor::StartScriptJob(DownloadQueue* pDownloadQueue, PostInfo* p
|
||||
}
|
||||
pPostInfo->SetStageTime(time(NULL));
|
||||
|
||||
bool bNZBFileCompleted = IsNZBFileCompleted(pDownloadQueue, pPostInfo->GetNZBInfo(), true, true, false);
|
||||
bool bHasFailedParJobs = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::prFailure ||
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::prRepairPossible;
|
||||
|
||||
if (g_pOptions->GetPostPauseQueue())
|
||||
if (bUnpack)
|
||||
{
|
||||
if (PauseDownload())
|
||||
{
|
||||
info("Pausing queue before post-process-script");
|
||||
}
|
||||
UpdatePauseState(g_pOptions->GetUnpackPauseQueue(), "unpack");
|
||||
UnpackController::StartUnpackJob(pPostInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatePauseState(g_pOptions->GetPostPauseQueue(), "post-process-script");
|
||||
PostScriptController::StartScriptJob(pPostInfo, bNZBFileCompleted, bHasFailedParJobs);
|
||||
}
|
||||
|
||||
PostScriptController::StartScriptJob(pPostInfo, g_pOptions->GetPostProcess(), bNZBFileCompleted, bHasFailedParJobs);
|
||||
}
|
||||
|
||||
void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo)
|
||||
@@ -632,8 +640,8 @@ void PrePostProcessor::JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPo
|
||||
if (IsNZBFileCompleted(pDownloadQueue, pPostInfo->GetNZBInfo(), true, true, false))
|
||||
{
|
||||
// Cleaning up queue if all par-checks were successful or all scripts were successful
|
||||
bool bCanCleanupQueue = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::prSuccess ||
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::prRepairPossible ||
|
||||
bool bCanCleanupQueue = pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psSuccess ||
|
||||
pPostInfo->GetNZBInfo()->GetParStatus() == NZBInfo::psRepairPossible ||
|
||||
pPostInfo->GetNZBInfo()->GetScriptStatus() == NZBInfo::srSuccess;
|
||||
if ((g_pOptions->GetParCleanupQueue() || g_pOptions->GetNzbCleanupDisk()) && bCanCleanupQueue)
|
||||
{
|
||||
@@ -719,7 +727,7 @@ bool PrePostProcessor::IsNZBFileCompleted(DownloadQueue* pDownloadQueue, NZBInfo
|
||||
}
|
||||
|
||||
bool PrePostProcessor::CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
|
||||
bool bParCheck, bool bPostScript, bool bAddTop)
|
||||
bool bParCheck, bool bUnpackOrScript, bool bAddTop)
|
||||
{
|
||||
debug("Queueing post-process-jobs");
|
||||
|
||||
@@ -750,8 +758,12 @@ bool PrePostProcessor::CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pN
|
||||
char szParInfoName[1024];
|
||||
snprintf(szParInfoName, 1024, "%s%c%s", pNZBInfo->GetName(), (int)PATH_SEPARATOR, szInfoName);
|
||||
szParInfoName[1024-1] = '\0';
|
||||
|
||||
info("Queueing %s%c%s for par-check", pNZBInfo->GetName(), (int)PATH_SEPARATOR, szInfoName);
|
||||
|
||||
if (cPostQueue.empty())
|
||||
{
|
||||
info("Queueing %s for post-processing", pNZBInfo->GetName());
|
||||
}
|
||||
|
||||
PostInfo* pPostInfo = new PostInfo();
|
||||
pPostInfo->SetNZBInfo(pNZBInfo);
|
||||
pPostInfo->SetParFilename(szFullParFilename);
|
||||
@@ -771,9 +783,9 @@ bool PrePostProcessor::CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pN
|
||||
}
|
||||
}
|
||||
|
||||
if (cPostQueue.empty() && bPostScript && m_bPostScript)
|
||||
if (cPostQueue.empty() && bUnpackOrScript && (m_bPostScript || g_pOptions->GetUnpack()))
|
||||
{
|
||||
info("Queueing %s for post-process-script", pNZBInfo->GetName());
|
||||
info("Queueing %s for post-processing", pNZBInfo->GetName());
|
||||
PostInfo* pPostInfo = new PostInfo();
|
||||
pPostInfo->SetNZBInfo(pNZBInfo);
|
||||
pPostInfo->SetParFilename("");
|
||||
@@ -846,6 +858,26 @@ void PrePostProcessor::ApplySchedulerState()
|
||||
}
|
||||
}
|
||||
|
||||
void PrePostProcessor::UpdatePauseState(bool bNeedPause, const char* szReason)
|
||||
{
|
||||
if (bNeedPause)
|
||||
{
|
||||
if (PauseDownload())
|
||||
{
|
||||
info("Pausing queue before %s", szReason);
|
||||
}
|
||||
}
|
||||
else if (m_bPostPause)
|
||||
{
|
||||
if (UnpauseDownload())
|
||||
{
|
||||
info("Unpausing queue after %s", m_szPauseReason);
|
||||
}
|
||||
}
|
||||
|
||||
m_szPauseReason = szReason;
|
||||
}
|
||||
|
||||
bool PrePostProcessor::PauseDownload()
|
||||
{
|
||||
debug("PrePostProcessor::PauseDownload()");
|
||||
@@ -944,7 +976,7 @@ bool PrePostProcessor::PostQueueDelete(IDList* pIDList)
|
||||
#endif
|
||||
if (pPostInfo->GetScriptThread())
|
||||
{
|
||||
debug("Terminating post-process-script for %s", pPostInfo->GetInfoName());
|
||||
debug("Terminating %s for %s", (pPostInfo->GetStage() == PostInfo::ptUnpacking ? "unpack" : "post-process-script"), pPostInfo->GetInfoName());
|
||||
pPostInfo->GetScriptThread()->Stop();
|
||||
bOK = true;
|
||||
}
|
||||
@@ -1155,8 +1187,9 @@ bool PrePostProcessor::HistoryReturn(IDList* pIDList, bool bReprocess)
|
||||
|
||||
// reset postprocessing status variables
|
||||
pNZBInfo->SetPostProcess(false);
|
||||
pNZBInfo->SetParStatus(NZBInfo::prNone);
|
||||
pNZBInfo->SetParStatus(NZBInfo::psNone);
|
||||
pNZBInfo->SetParCleanup(false);
|
||||
pNZBInfo->SetUnpackStatus(NZBInfo::usNone);
|
||||
pNZBInfo->SetScriptStatus(NZBInfo::srNone);
|
||||
pNZBInfo->SetParkedFileCount(0);
|
||||
}
|
||||
|
||||
@@ -76,24 +76,26 @@ private:
|
||||
bool m_bSchedulerPause;
|
||||
bool m_bPostPause;
|
||||
Scanner m_Scanner;
|
||||
const char* m_szPauseReason;
|
||||
|
||||
bool IsNZBFileCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo,
|
||||
bool bIgnorePausedPars, bool bCheckPostQueue, bool bAllowOnlyOneDeleted);
|
||||
void CheckPostQueue();
|
||||
void JobCompleted(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartScriptJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void StartProcessJob(DownloadQueue* pDownloadQueue, PostInfo* pPostInfo);
|
||||
void SaveQueue(DownloadQueue* pDownloadQueue);
|
||||
void SanitisePostQueue(PostQueue* pPostQueue);
|
||||
void CheckDiskSpace();
|
||||
void ApplySchedulerState();
|
||||
void CheckScheduledResume();
|
||||
void UpdatePauseState(bool bNeedPause, const char* szReason);
|
||||
bool PauseDownload();
|
||||
bool UnpauseDownload();
|
||||
void NZBAdded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBDownloaded(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBDeleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
void NZBCompleted(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bSaveQueue);
|
||||
bool CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bParCheck, bool bPostScript, bool bAddTop);
|
||||
bool CreatePostJobs(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo, bool bParCheck, bool bUnpackOrScript, bool bAddTop);
|
||||
void DeleteQueuedFile(const char* szQueuedFile);
|
||||
NZBInfo* MergeGroups(DownloadQueue* pDownloadQueue, NZBInfo* pNZBInfo);
|
||||
bool PostQueueMove(IDList* pIDList, EEditAction eAction, int iOffset);
|
||||
|
||||
@@ -446,6 +446,9 @@ bool QueueCoordinator::GetNextArticle(FileInfo* &pFileInfo, ArticleInfo* &pArtic
|
||||
// if the file doesn't have any articles left for download, we store that fact and search again,
|
||||
// ignoring all files which were previously marked as not having any articles.
|
||||
|
||||
// special case: if the file has ExtraPriority-flag set, it has the highest priority and the
|
||||
// Paused-flag is ignored.
|
||||
|
||||
//debug("QueueCoordinator::GetNextArticle()");
|
||||
|
||||
bool bOK = false;
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "RemoteClient.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "Options.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
@@ -1026,15 +1027,14 @@ bool RemoteClient::RequestPostQueue()
|
||||
|
||||
int iStageProgress = ntohl(pPostQueueAnswer->m_iStageProgress);
|
||||
|
||||
static const int EXECUTING_SCRIPT = 5;
|
||||
char szCompleted[100];
|
||||
szCompleted[0] = '\0';
|
||||
if (iStageProgress > 0 && (int)ntohl(pPostQueueAnswer->m_iStage) != EXECUTING_SCRIPT)
|
||||
if (iStageProgress > 0 && (int)ntohl(pPostQueueAnswer->m_iStage) != (int)PostInfo::ptExecutingScript)
|
||||
{
|
||||
sprintf(szCompleted, ", %i%s", (int)(iStageProgress / 10), "%");
|
||||
}
|
||||
|
||||
const char* szPostStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Executing postprocess-script", "" };
|
||||
const char* szPostStageName[] = { "", ", Loading Pars", ", Verifying source files", ", Repairing", ", Verifying repaired files", ", Unpacking", ", Executing postprocess-script", "" };
|
||||
char* szInfoName = pBufPtr + sizeof(SNZBPostQueueResponseEntry) + ntohl(pPostQueueAnswer->m_iNZBFilenameLen) + ntohl(pPostQueueAnswer->m_iParFilename);
|
||||
|
||||
printf("[%i] %s%s%s\n", ntohl(pPostQueueAnswer->m_iID), szInfoName, szPostStageName[ntohl(pPostQueueAnswer->m_iStage)], szCompleted);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "ScriptController.h"
|
||||
@@ -243,12 +244,6 @@ void ScriptController::PrepareEnvironmentStrings()
|
||||
|
||||
int ScriptController::Execute()
|
||||
{
|
||||
if (!Util::FileExists(m_szScript))
|
||||
{
|
||||
error("Could not start %s: could not find file %s", m_szInfoName, m_szScript);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PrepareEnvironmentStrings();
|
||||
|
||||
int iExitCode = 0;
|
||||
@@ -299,8 +294,7 @@ int ScriptController::Execute()
|
||||
DWORD dwErrCode = GetLastError();
|
||||
char szErrMsg[255];
|
||||
szErrMsg[255-1] = '\0';
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM || FORMAT_MESSAGE_IGNORE_INSERTS || FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||
NULL, dwErrCode, 0, szErrMsg, 255, NULL))
|
||||
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrCode, 0, szErrMsg, 255, NULL))
|
||||
{
|
||||
error("Could not start %s: %s", m_szInfoName, szErrMsg);
|
||||
}
|
||||
@@ -308,6 +302,10 @@ int ScriptController::Execute()
|
||||
{
|
||||
error("Could not start %s: error %i", m_szInfoName, dwErrCode);
|
||||
}
|
||||
if (!Util::FileExists(m_szScript))
|
||||
{
|
||||
error("Could not find file %s", m_szScript);
|
||||
}
|
||||
free(szEnvironmentStrings);
|
||||
return -1;
|
||||
}
|
||||
@@ -370,6 +368,7 @@ int ScriptController::Execute()
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
chdir(m_szWorkingDir);
|
||||
execve(m_szScript, (char* const*)m_szArgs, (char* const*)pEnvironmentStrings);
|
||||
fprintf(stdout, "[ERROR] Could not start script: %s", strerror(errno));
|
||||
fflush(stdout);
|
||||
@@ -409,7 +408,7 @@ int ScriptController::Execute()
|
||||
debug("Entering pipe-loop");
|
||||
while (!feof(readpipe) && !m_bTerminated)
|
||||
{
|
||||
if (fgets(buf, 10240, readpipe))
|
||||
if (ReadLine(buf, 10240, readpipe))
|
||||
{
|
||||
#ifdef CHILD_WATCHDOG
|
||||
if (!bChildConfirmed)
|
||||
@@ -503,6 +502,11 @@ void ScriptController::Terminate()
|
||||
debug("Stopped %s", m_szInfoName);
|
||||
}
|
||||
|
||||
bool ScriptController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
|
||||
{
|
||||
return fgets(szBuf, iBufSize, pStream);
|
||||
}
|
||||
|
||||
void ScriptController::ProcessOutput(char* szText)
|
||||
{
|
||||
debug("Processing output received from script");
|
||||
@@ -517,23 +521,23 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
|
||||
if (!strncmp(szText, "[INFO] ", 7))
|
||||
{
|
||||
AddMessage(Message::mkInfo, false, g_pOptions->GetInfoTarget(), szText + 7);
|
||||
AddMessage(Message::mkInfo, false, szText + 7);
|
||||
}
|
||||
else if (!strncmp(szText, "[WARNING] ", 10))
|
||||
{
|
||||
AddMessage(Message::mkWarning, false, g_pOptions->GetWarningTarget(), szText + 10);
|
||||
AddMessage(Message::mkWarning, false, szText + 10);
|
||||
}
|
||||
else if (!strncmp(szText, "[ERROR] ", 8))
|
||||
{
|
||||
AddMessage(Message::mkError, false, g_pOptions->GetErrorTarget(), szText + 8);
|
||||
AddMessage(Message::mkError, false, szText + 8);
|
||||
}
|
||||
else if (!strncmp(szText, "[DETAIL] ", 9))
|
||||
{
|
||||
AddMessage(Message::mkDetail, false, g_pOptions->GetDetailTarget(), szText + 9);
|
||||
AddMessage(Message::mkDetail, false, szText + 9);
|
||||
}
|
||||
else if (!strncmp(szText, "[DEBUG] ", 8))
|
||||
{
|
||||
AddMessage(Message::mkDebug, false, g_pOptions->GetDebugTarget(), szText + 8);
|
||||
AddMessage(Message::mkDebug, false, szText + 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -543,23 +547,23 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
break;
|
||||
|
||||
case Options::slDetail:
|
||||
AddMessage(Message::mkDetail, true, g_pOptions->GetDetailTarget(), szText);
|
||||
AddMessage(Message::mkDetail, true, szText);
|
||||
break;
|
||||
|
||||
case Options::slInfo:
|
||||
AddMessage(Message::mkInfo, true, g_pOptions->GetInfoTarget(), szText);
|
||||
AddMessage(Message::mkInfo, true, szText);
|
||||
break;
|
||||
|
||||
case Options::slWarning:
|
||||
AddMessage(Message::mkWarning, true, g_pOptions->GetWarningTarget(), szText);
|
||||
AddMessage(Message::mkWarning, true, szText);
|
||||
break;
|
||||
|
||||
case Options::slError:
|
||||
AddMessage(Message::mkError, true, g_pOptions->GetErrorTarget(), szText);
|
||||
AddMessage(Message::mkError, true, szText);
|
||||
break;
|
||||
|
||||
case Options::slDebug:
|
||||
AddMessage(Message::mkDebug, true, g_pOptions->GetDebugTarget(), szText);
|
||||
AddMessage(Message::mkDebug, true, szText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -567,7 +571,7 @@ void ScriptController::ProcessOutput(char* szText)
|
||||
debug("Processing output received from script - completed");
|
||||
}
|
||||
|
||||
void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
|
||||
void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
{
|
||||
switch (eKind)
|
||||
{
|
||||
@@ -593,13 +597,26 @@ void ScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Optio
|
||||
}
|
||||
}
|
||||
|
||||
void PostScriptController::StartScriptJob(PostInfo* pPostInfo, const char* szScript, bool bNZBFileCompleted, bool bHasFailedParJobs)
|
||||
void ScriptController::PrintMessage(Message::EKind eKind, const char* szFormat, ...)
|
||||
{
|
||||
char tmp2[1024];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
vsnprintf(tmp2, 1024, szFormat, ap);
|
||||
tmp2[1024-1] = '\0';
|
||||
va_end(ap);
|
||||
|
||||
AddMessage(eKind, false, tmp2);
|
||||
}
|
||||
|
||||
void PostScriptController::StartScriptJob(PostInfo* pPostInfo, bool bNZBFileCompleted, bool bHasFailedParJobs)
|
||||
{
|
||||
info("Executing post-process-script for %s", pPostInfo->GetInfoName());
|
||||
|
||||
PostScriptController* pScriptController = new PostScriptController();
|
||||
pScriptController->m_pPostInfo = pPostInfo;
|
||||
pScriptController->SetScript(szScript);
|
||||
pScriptController->SetScript(g_pOptions->GetPostProcess());
|
||||
pScriptController->SetWorkingDir(g_pOptions->GetDestDir());
|
||||
pScriptController->m_bNZBFileCompleted = bNZBFileCompleted;
|
||||
pScriptController->m_bHasFailedParJobs = bHasFailedParJobs;
|
||||
@@ -620,9 +637,14 @@ void PostScriptController::Run()
|
||||
szNZBName[1024-1] = '\0';
|
||||
|
||||
char szParStatus[10];
|
||||
snprintf(szParStatus, 10, "%i", m_pPostInfo->GetParStatus());
|
||||
snprintf(szParStatus, 10, "%i", g_pOptions->GetAllowReProcess() ? (int)m_pPostInfo->GetParStatus() : (int)m_pPostInfo->GetNZBInfo()->GetParStatus());
|
||||
szParStatus[10-1] = '\0';
|
||||
|
||||
int iUnpackStatus[] = { 0, 0, 1, 2 };
|
||||
char szUnpackStatus[10];
|
||||
snprintf(szUnpackStatus, 10, "%i", g_pOptions->GetAllowReProcess() ? 0 : iUnpackStatus[m_pPostInfo->GetNZBInfo()->GetUnpackStatus()]);
|
||||
szUnpackStatus[10-1] = '\0';
|
||||
|
||||
char szCollectionCompleted[10];
|
||||
snprintf(szCollectionCompleted, 10, "%i", (int)m_bNZBFileCompleted);
|
||||
szCollectionCompleted[10-1] = '\0';
|
||||
@@ -648,7 +670,7 @@ void PostScriptController::Run()
|
||||
szCategory[1024-1] = '\0';
|
||||
|
||||
char szInfoName[1024];
|
||||
snprintf(szInfoName, 1024, "post-process-script for %s", m_pPostInfo->GetInfoName());
|
||||
snprintf(szInfoName, 1024, "post-process-script for %s", g_pOptions->GetAllowReProcess() ? m_pPostInfo->GetInfoName() : m_pPostInfo->GetNZBInfo()->GetName());
|
||||
szInfoName[1024-1] = '\0';
|
||||
SetInfoName(szInfoName);
|
||||
|
||||
@@ -672,6 +694,7 @@ void PostScriptController::Run()
|
||||
SetEnvVar("NZBPP_NZBFILENAME", szNZBFilename);
|
||||
SetEnvVar("NZBPP_PARFILENAME", szParFilename);
|
||||
SetEnvVar("NZBPP_PARSTATUS", szParStatus);
|
||||
SetEnvVar("NZBPP_UNPACKSTATUS", szUnpackStatus);
|
||||
SetEnvVar("NZBPP_NZBCOMPLETED", szCollectionCompleted);
|
||||
SetEnvVar("NZBPP_PARFAILED", szHasFailedParJobs);
|
||||
SetEnvVar("NZBPP_CATEGORY", szCategory);
|
||||
@@ -689,14 +712,17 @@ void PostScriptController::Run()
|
||||
|
||||
int iResult = Execute();
|
||||
|
||||
szInfoName[0] = 'P'; // uppercase
|
||||
|
||||
switch (iResult)
|
||||
{
|
||||
case POSTPROCESS_SUCCESS:
|
||||
info("%s sucessful", szInfoName);
|
||||
info("%s successful", szInfoName);
|
||||
m_pPostInfo->SetScriptStatus(PostInfo::srSuccess);
|
||||
break;
|
||||
|
||||
case POSTPROCESS_ERROR:
|
||||
case -1: // Execute() returns -1 if the process could not be started (file not found or other problem)
|
||||
info("%s failed", szInfoName);
|
||||
m_pPostInfo->SetScriptStatus(PostInfo::srFailure);
|
||||
break;
|
||||
@@ -755,26 +781,18 @@ void PostScriptController::Run()
|
||||
m_pPostInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
void PostScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText)
|
||||
void PostScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
{
|
||||
if (!strncmp(szText, "[HISTORY] ", 10))
|
||||
{
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText + 10);
|
||||
}
|
||||
m_pPostInfo->GetNZBInfo()->AppendMessage(eKind, 0, szText + 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
|
||||
|
||||
if (eMessageTarget == Options::mtScreen || eMessageTarget == Options::mtBoth)
|
||||
{
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
}
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, szText);
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
}
|
||||
|
||||
|
||||
if (g_pOptions->GetPausePostProcess())
|
||||
{
|
||||
time_t tStageTime = m_pPostInfo->GetStageTime();
|
||||
@@ -854,7 +872,7 @@ 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)
|
||||
void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
{
|
||||
if (!strncmp(szText, "[NZB] ", 6))
|
||||
{
|
||||
@@ -890,7 +908,7 @@ void NZBScriptController::AddMessage(Message::EKind eKind, bool bDefaultKind, Op
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, eMessageTarget, szText);
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, szText);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -70,11 +70,14 @@ private:
|
||||
pid_t m_hProcess;
|
||||
#endif
|
||||
|
||||
void ProcessOutput(char* szText);
|
||||
void PrepareEnvironmentStrings();
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
void ProcessOutput(char* szText);
|
||||
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
|
||||
void PrintMessage(Message::EKind eKind, const char* szFormat, ...);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText);
|
||||
bool GetTerminated() { return m_bTerminated; }
|
||||
|
||||
public:
|
||||
ScriptController();
|
||||
@@ -93,7 +96,7 @@ public:
|
||||
void SetEnvVar(const char* szName, const char* szValue);
|
||||
};
|
||||
|
||||
class PostScriptController : public Thread, ScriptController
|
||||
class PostScriptController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
@@ -101,13 +104,12 @@ private:
|
||||
bool m_bHasFailedParJobs;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText);
|
||||
|
||||
public:
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartScriptJob(PostInfo* pPostInfo, const char* szScript,
|
||||
bool bNZBFileCompleted, bool bHasFailedParJobs);
|
||||
static void StartScriptJob(PostInfo* pPostInfo, bool bNZBFileCompleted, bool bHasFailedParJobs);
|
||||
};
|
||||
|
||||
class NZBScriptController : public ScriptController
|
||||
@@ -118,13 +120,13 @@ private:
|
||||
NZBParameterList* m_pParameterList;
|
||||
|
||||
protected:
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, Options::EMessageTarget eMessageTarget, const char* szText);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText);
|
||||
|
||||
public:
|
||||
static void ExecuteScript(const char* szScript, const char* szNZBFilename, const char* szDirectory, char** pCategory, int* iPriority, NZBParameterList* pParameterList);
|
||||
};
|
||||
|
||||
class NZBAddedScriptController : public Thread, ScriptController
|
||||
class NZBAddedScriptController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
char* m_szNZBName;
|
||||
@@ -134,7 +136,7 @@ public:
|
||||
static void StartScript(DownloadQueue* pDownloadQueue, NZBInfo *pNZBInfo, const char* szScript);
|
||||
};
|
||||
|
||||
class SchedulerScriptController : public Thread, ScriptController
|
||||
class SchedulerScriptController : public Thread, public ScriptController
|
||||
{
|
||||
public:
|
||||
virtual void Run();
|
||||
|
||||
539
Unpack.cpp
Normal file
539
Unpack.cpp
Normal file
@@ -0,0 +1,539 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include "win32.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <fstream>
|
||||
#ifndef WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "nzbget.h"
|
||||
#include "Unpack.h"
|
||||
#include "Log.h"
|
||||
#include "Util.h"
|
||||
#include "ParCoordinator.h"
|
||||
|
||||
extern Options* g_pOptions;
|
||||
extern DownloadQueueHolder* g_pDownloadQueueHolder;
|
||||
|
||||
UnpackController::~UnpackController()
|
||||
{
|
||||
for (FileList::iterator it = m_archiveFiles.begin(); it != m_archiveFiles.end(); it++)
|
||||
{
|
||||
free(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::StartUnpackJob(PostInfo* pPostInfo)
|
||||
{
|
||||
UnpackController* pUnpackController = new UnpackController();
|
||||
pUnpackController->m_pPostInfo = pPostInfo;
|
||||
pUnpackController->SetAutoDestroy(false);
|
||||
|
||||
pPostInfo->SetScriptThread(pUnpackController);
|
||||
|
||||
pUnpackController->Start();
|
||||
}
|
||||
|
||||
void UnpackController::Run()
|
||||
{
|
||||
// the locking is needed for accessing the members of NZBInfo
|
||||
g_pDownloadQueueHolder->LockQueue();
|
||||
|
||||
strncpy(m_szDestDir, m_pPostInfo->GetNZBInfo()->GetDestDir(), 1024);
|
||||
m_szDestDir[1024-1] = '\0';
|
||||
|
||||
char szName[1024];
|
||||
strncpy(szName, m_pPostInfo->GetNZBInfo()->GetName(), 1024);
|
||||
szName[1024-1] = '\0';
|
||||
|
||||
bool bUnpack = true;
|
||||
m_szPassword[0] = '\0';
|
||||
|
||||
for (NZBParameterList::iterator it = m_pPostInfo->GetNZBInfo()->GetParameters()->begin(); it != m_pPostInfo->GetNZBInfo()->GetParameters()->end(); it++)
|
||||
{
|
||||
NZBParameter* pParameter = *it;
|
||||
if (!strcasecmp(pParameter->GetName(), "*Unpack:") && !strcasecmp(pParameter->GetValue(), "no"))
|
||||
{
|
||||
bUnpack = false;
|
||||
}
|
||||
if (!strcasecmp(pParameter->GetName(), "*Unpack:Password"))
|
||||
{
|
||||
strncpy(m_szPassword, pParameter->GetValue(), 1024-1);
|
||||
m_szPassword[1024-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
g_pDownloadQueueHolder->UnlockQueue();
|
||||
|
||||
snprintf(m_szInfoName, 1024, "unpack for %s", szName);
|
||||
m_szInfoName[1024-1] = '\0';
|
||||
|
||||
snprintf(m_szInfoNameUp, 1024, "Unpack for %s", szName); // first letter in upper case
|
||||
m_szInfoNameUp[1024-1] = '\0';
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && HasBrokenFiles() && !m_pPostInfo->GetParCheck() && HasParFiles())
|
||||
{
|
||||
info("%s has broken files", szName);
|
||||
RequestParCheck();
|
||||
m_pPostInfo->SetWorking(false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bUnpack)
|
||||
{
|
||||
CheckArchiveFiles();
|
||||
}
|
||||
|
||||
if (bUnpack && (m_bHasRarFiles || m_bHasSevenZipFiles || m_bHasSevenZipMultiFiles))
|
||||
{
|
||||
SetInfoName(m_szInfoName);
|
||||
SetDefaultLogKind(g_pOptions->GetProcessLogKind());
|
||||
SetWorkingDir(m_szDestDir);
|
||||
|
||||
PrintMessage(Message::mkInfo, "Unpacking %s", szName);
|
||||
|
||||
CreateUnpackDir();
|
||||
|
||||
m_bUnpackOK = true;
|
||||
m_bUnpackStartError = false;
|
||||
|
||||
if (m_bHasRarFiles)
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel("");
|
||||
ExecuteUnrar();
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipFiles && m_bUnpackOK)
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel("");
|
||||
ExecuteSevenZip(false);
|
||||
}
|
||||
|
||||
if (m_bHasSevenZipMultiFiles && m_bUnpackOK)
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel("");
|
||||
ExecuteSevenZip(true);
|
||||
}
|
||||
|
||||
Completed();
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintMessage(Message::mkInfo, (bUnpack ? "Nothing to unpack for %s" : "Unpack for %s skipped"), szName);
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (bUnpack && !m_pPostInfo->GetParCheck() && HasParFiles())
|
||||
{
|
||||
RequestParCheck();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_pPostInfo->SetUnpackStatus(PostInfo::usSkipped);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSkipped);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
|
||||
m_pPostInfo->SetWorking(false);
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteUnrar()
|
||||
{
|
||||
// Format:
|
||||
// unrar x -y -p- -o+ *.rar ./_unpack
|
||||
|
||||
char szPasswordParam[1024];
|
||||
const char* szArgs[8];
|
||||
szArgs[0] = g_pOptions->GetUnrarCmd();
|
||||
szArgs[1] = "x";
|
||||
szArgs[2] = "-y";
|
||||
szArgs[3] = "-p-";
|
||||
if (strlen(m_szPassword) > 0)
|
||||
{
|
||||
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
|
||||
szArgs[3] = szPasswordParam;
|
||||
}
|
||||
szArgs[4] = "-o+";
|
||||
szArgs[5] = "*.rar";
|
||||
szArgs[6] = "./_unpack";
|
||||
szArgs[7] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
|
||||
SetScript(g_pOptions->GetUnrarCmd());
|
||||
SetDefaultKindPrefix("Unrar: ");
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upUnrar;
|
||||
|
||||
int iExitCode = Execute();
|
||||
|
||||
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
|
||||
m_bUnpackStartError = iExitCode == -1;
|
||||
|
||||
if (!m_bUnpackOK && iExitCode > 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Unrar error code: %i", iExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::ExecuteSevenZip(bool bMultiVolumes)
|
||||
{
|
||||
// Format:
|
||||
// 7z x -y -p- -o./_unpack *.7z
|
||||
// OR
|
||||
// 7z x -y -p- -o./_unpack *.7z.001
|
||||
|
||||
char szPasswordParam[1024];
|
||||
const char* szArgs[7];
|
||||
szArgs[0] = g_pOptions->GetSevenZipCmd();
|
||||
szArgs[1] = "x";
|
||||
szArgs[2] = "-y";
|
||||
szArgs[3] = "-p-";
|
||||
if (strlen(m_szPassword) > 0)
|
||||
{
|
||||
snprintf(szPasswordParam, 1024, "-p%s", m_szPassword);
|
||||
szArgs[3] = szPasswordParam;
|
||||
}
|
||||
szArgs[4] = "-o./_unpack";
|
||||
szArgs[5] = bMultiVolumes ? "*.7z.001" : "*.7z";
|
||||
szArgs[6] = NULL;
|
||||
SetArgs(szArgs, false);
|
||||
|
||||
SetScript(g_pOptions->GetSevenZipCmd());
|
||||
SetDefaultKindPrefix("7-Zip: ");
|
||||
|
||||
m_bAllOKMessageReceived = false;
|
||||
m_eUnpacker = upSevenZip;
|
||||
|
||||
PrintMessage(Message::mkInfo, "Executing 7-Zip");
|
||||
int iExitCode = Execute();
|
||||
|
||||
m_bUnpackOK = iExitCode == 0 && m_bAllOKMessageReceived && !GetTerminated();
|
||||
m_bUnpackStartError = iExitCode == -1;
|
||||
|
||||
if (!m_bUnpackOK && iExitCode > 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "7-Zip error code: %i", iExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::Completed()
|
||||
{
|
||||
bool bCleanupSuccess = Cleanup();
|
||||
|
||||
if (m_bUnpackOK && bCleanupSuccess)
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s %s", m_szInfoNameUp, "successful");
|
||||
m_pPostInfo->SetUnpackStatus(PostInfo::usSuccess);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usSuccess);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef DISABLE_PARCHECK
|
||||
if (!m_bUnpackOK && !m_pPostInfo->GetParCheck() && !m_bUnpackStartError && !GetTerminated() && HasParFiles())
|
||||
{
|
||||
RequestParCheck();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
PrintMessage(Message::mkError, "%s failed", m_szInfoNameUp);
|
||||
m_pPostInfo->SetUnpackStatus(PostInfo::usFailure);
|
||||
m_pPostInfo->GetNZBInfo()->SetUnpackStatus(NZBInfo::usFailure);
|
||||
m_pPostInfo->SetStage(PostInfo::ptQueued);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void UnpackController::RequestParCheck()
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "%s requested par-check/repair", m_szInfoNameUp);
|
||||
m_pPostInfo->SetRequestParCheck(PostInfo::rpAll);
|
||||
m_pPostInfo->SetStage(PostInfo::ptFinished);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool UnpackController::HasParFiles()
|
||||
{
|
||||
return ParCoordinator::FindMainPars(m_szDestDir, NULL);
|
||||
}
|
||||
|
||||
bool UnpackController::HasBrokenFiles()
|
||||
{
|
||||
char szBrokenLog[1024];
|
||||
snprintf(szBrokenLog, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, "_brokenlog.txt");
|
||||
szBrokenLog[1024-1] = '\0';
|
||||
return Util::FileExists(szBrokenLog);
|
||||
}
|
||||
|
||||
void UnpackController::CreateUnpackDir()
|
||||
{
|
||||
snprintf(m_szUnpackDir, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, "_unpack");
|
||||
m_szUnpackDir[1024-1] = '\0';
|
||||
Util::ForceDirectories(m_szUnpackDir);
|
||||
}
|
||||
|
||||
|
||||
void UnpackController::CheckArchiveFiles()
|
||||
{
|
||||
m_bHasRarFiles = false;
|
||||
m_bHasSevenZipFiles = false;
|
||||
m_bHasSevenZipMultiFiles = false;
|
||||
|
||||
RegEx regExRar(".*\\.rar$");
|
||||
RegEx regExSevenZip(".*\\.7z$");
|
||||
RegEx regExSevenZipMulti(".*\\.7z\\.[0-9]*$");
|
||||
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
if (regExRar.Match(filename))
|
||||
{
|
||||
m_bHasRarFiles = true;
|
||||
}
|
||||
if (regExSevenZip.Match(filename))
|
||||
{
|
||||
m_bHasSevenZipFiles = true;
|
||||
}
|
||||
if (regExSevenZipMulti.Match(filename))
|
||||
{
|
||||
m_bHasSevenZipMultiFiles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UnpackController::Cleanup()
|
||||
{
|
||||
// By success:
|
||||
// - move unpacked files to destination dir;
|
||||
// - remove _unpack-dir;
|
||||
// - delete archive-files.
|
||||
// By failure:
|
||||
// - remove _unpack-dir.
|
||||
|
||||
bool bOK = true;
|
||||
|
||||
if (m_bUnpackOK)
|
||||
{
|
||||
// moving files back
|
||||
DirBrowser dir(m_szUnpackDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
char szSrcFile[1024];
|
||||
snprintf(szSrcFile, 1024, "%s%c%s", m_szUnpackDir, PATH_SEPARATOR, filename);
|
||||
szSrcFile[1024-1] = '\0';
|
||||
|
||||
char szDstFile[1024];
|
||||
snprintf(szDstFile, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szDstFile[1024-1] = '\0';
|
||||
|
||||
// silently overwrite existing files
|
||||
remove(szDstFile);
|
||||
|
||||
if (!Util::MoveFile(szSrcFile, szDstFile))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not move file %s to %s", szSrcFile, szDstFile);
|
||||
bOK = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bOK && !Util::DeleteDirectoryWithContent(m_szUnpackDir))
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not remove temporary directory %s", m_szUnpackDir);
|
||||
}
|
||||
|
||||
if (m_bUnpackOK && bOK && g_pOptions->GetUnpackCleanupDisk())
|
||||
{
|
||||
PrintMessage(Message::mkInfo, "Deleting archive files");
|
||||
|
||||
// Delete rar-files (only files which were used by unrar)
|
||||
for (FileList::iterator it = m_archiveFiles.begin(); it != m_archiveFiles.end(); it++)
|
||||
{
|
||||
char* szFilename = *it;
|
||||
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, szFilename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
PrintMessage(Message::mkDetail, "Deleting file %s", szFilename);
|
||||
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete file %s", szFullFilename);
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately 7-Zip doesn't print the processed archive-files to the output.
|
||||
// Therefore we don't know for sure which files were extracted.
|
||||
// We just delete all 7z-files in the directory.
|
||||
|
||||
RegEx regExSevenZip(".*\\.7z$|.*\\.7z\\.[0-9]*$");
|
||||
|
||||
DirBrowser dir(m_szDestDir);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", m_szDestDir, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, "..") && !Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
if (regExSevenZip.Match(filename))
|
||||
{
|
||||
PrintMessage(Message::mkDetail, "Deleting file %s", filename);
|
||||
|
||||
if (remove(szFullFilename) != 0)
|
||||
{
|
||||
PrintMessage(Message::mkError, "Could not delete file %s", szFullFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unrar prints progress information into the same line using backspace control character.
|
||||
* In order to print progress continuously we analyze the output after every char
|
||||
* and update post-job progress information.
|
||||
*/
|
||||
bool UnpackController::ReadLine(char* szBuf, int iBufSize, FILE* pStream)
|
||||
{
|
||||
bool bPrinted = false;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (; i < iBufSize - 1; i++)
|
||||
{
|
||||
int ch = fgetc(pStream);
|
||||
szBuf[i] = ch;
|
||||
szBuf[i+1] = '\0';
|
||||
if (ch == EOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ch == '\n')
|
||||
{
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
|
||||
char* szBackspace = strrchr(szBuf, '\b');
|
||||
if (szBackspace)
|
||||
{
|
||||
if (!bPrinted)
|
||||
{
|
||||
char tmp[1024];
|
||||
strncpy(tmp, szBuf, 1024);
|
||||
tmp[1024-1] = '\0';
|
||||
char* szTmpPercent = strrchr(tmp, '\b');
|
||||
if (szTmpPercent)
|
||||
{
|
||||
*szTmpPercent = '\0';
|
||||
}
|
||||
if (strncmp(szBuf, "...", 3))
|
||||
{
|
||||
ProcessOutput(tmp);
|
||||
}
|
||||
bPrinted = true;
|
||||
}
|
||||
if (strchr(szBackspace, '%'))
|
||||
{
|
||||
int iPercent = atoi(szBackspace + 1);
|
||||
m_pPostInfo->SetStageProgress(iPercent * 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
szBuf[i] = '\0';
|
||||
|
||||
if (bPrinted)
|
||||
{
|
||||
szBuf[0] = '\0';
|
||||
}
|
||||
|
||||
return i > 0;
|
||||
}
|
||||
|
||||
void UnpackController::AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText)
|
||||
{
|
||||
ScriptController::AddMessage(eKind, bDefaultKind, szText);
|
||||
m_pPostInfo->AppendMessage(eKind, szText);
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szText, "Extracting from ", 16))
|
||||
{
|
||||
const char *szFilename = szText + 16;
|
||||
debug("Filename: %s", szFilename);
|
||||
m_archiveFiles.push_back(strdup(szFilename));
|
||||
m_pPostInfo->SetProgressLabel(szText);
|
||||
}
|
||||
|
||||
if (m_eUnpacker == upUnrar && !strncmp(szText, "Extracting ", 11))
|
||||
{
|
||||
m_pPostInfo->SetProgressLabel(szText);
|
||||
}
|
||||
|
||||
if ((m_eUnpacker == upUnrar && !strncmp(szText, "All OK", 6)) ||
|
||||
(m_eUnpacker == upSevenZip && !strncmp(szText, "Everything is Ok", 16)))
|
||||
{
|
||||
m_bAllOKMessageReceived = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UnpackController::Stop()
|
||||
{
|
||||
debug("Stopping unpack");
|
||||
Thread::Stop();
|
||||
Terminate();
|
||||
}
|
||||
87
Unpack.h
Normal file
87
Unpack.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2013 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UNPACK_H
|
||||
#define UNPACK_H
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "Log.h"
|
||||
#include "Thread.h"
|
||||
#include "DownloadInfo.h"
|
||||
#include "ScriptController.h"
|
||||
|
||||
class UnpackController : public Thread, public ScriptController
|
||||
{
|
||||
private:
|
||||
enum EUnpacker
|
||||
{
|
||||
upUnrar,
|
||||
upSevenZip
|
||||
};
|
||||
|
||||
private:
|
||||
PostInfo* m_pPostInfo;
|
||||
char m_szInfoName[1024];
|
||||
char m_szInfoNameUp[1024];
|
||||
char m_szDestDir[1024];
|
||||
char m_szUnpackDir[1024];
|
||||
char m_szPassword[1024];
|
||||
bool m_bAllOKMessageReceived;
|
||||
bool m_bNoFilesMessageReceived;
|
||||
bool m_bHasRarFiles;
|
||||
bool m_bHasSevenZipFiles;
|
||||
bool m_bHasSevenZipMultiFiles;
|
||||
bool m_bUnpackOK;
|
||||
bool m_bUnpackStartError;
|
||||
EUnpacker m_eUnpacker;
|
||||
|
||||
typedef std::deque<char*> FileList;
|
||||
|
||||
FileList m_archiveFiles;
|
||||
|
||||
protected:
|
||||
virtual bool ReadLine(char* szBuf, int iBufSize, FILE* pStream);
|
||||
virtual void AddMessage(Message::EKind eKind, bool bDefaultKind, const char* szText);
|
||||
void ExecuteUnrar();
|
||||
void ExecuteSevenZip(bool bMultiVolumes);
|
||||
void Completed();
|
||||
void CreateUnpackDir();
|
||||
bool Cleanup();
|
||||
bool HasParFiles();
|
||||
bool HasBrokenFiles();
|
||||
void CheckArchiveFiles();
|
||||
#ifndef DISABLE_PARCHECK
|
||||
void RequestParCheck();
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual ~UnpackController();
|
||||
virtual void Run();
|
||||
virtual void Stop();
|
||||
static void StartUnpackJob(PostInfo* pPostInfo);
|
||||
};
|
||||
|
||||
#endif
|
||||
36
Util.cpp
36
Util.cpp
@@ -599,6 +599,42 @@ bool Util::CreateDirectory(const char* szDirFilename)
|
||||
return DirectoryExists(szDirFilename);
|
||||
}
|
||||
|
||||
bool Util::RemoveDirectory(const char* szDirFilename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
return ::RemoveDirectory(szDirFilename);
|
||||
#else
|
||||
return remove(szDirFilename) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Util::DeleteDirectoryWithContent(const char* szDirFilename)
|
||||
{
|
||||
bool bOK = true;
|
||||
|
||||
DirBrowser dir(szDirFilename);
|
||||
while (const char* filename = dir.Next())
|
||||
{
|
||||
char szFullFilename[1024];
|
||||
snprintf(szFullFilename, 1024, "%s%c%s", szDirFilename, PATH_SEPARATOR, filename);
|
||||
szFullFilename[1024-1] = '\0';
|
||||
|
||||
if (strcmp(filename, ".") && strcmp(filename, ".."))
|
||||
{
|
||||
if (Util::DirectoryExists(szFullFilename))
|
||||
{
|
||||
bOK &= DeleteDirectoryWithContent(szFullFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
bOK &= remove(szFullFilename) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bOK && RemoveDirectory(szDirFilename);
|
||||
}
|
||||
|
||||
long long Util::FileSize(const char* szFilename)
|
||||
{
|
||||
#ifdef WIN32
|
||||
|
||||
2
Util.h
2
Util.h
@@ -71,6 +71,8 @@ public:
|
||||
static bool FileExists(const char* szFilename);
|
||||
static bool DirectoryExists(const char* szDirFilename);
|
||||
static bool CreateDirectory(const char* szDirFilename);
|
||||
static bool RemoveDirectory(const char* szDirFilename);
|
||||
static bool DeleteDirectoryWithContent(const char* szDirFilename);
|
||||
static bool ForceDirectories(const char* szPath);
|
||||
static bool GetCurrentDirectory(char* szBuffer, int iBufSize);
|
||||
static bool SetCurrentDirectory(const char* szDirFilename);
|
||||
|
||||
14
XmlRpc.cpp
14
XmlRpc.cpp
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2007-2011 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2007-2013 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
|
||||
@@ -1629,7 +1629,7 @@ void PostQueueXmlCommand::Execute()
|
||||
{
|
||||
PostInfo* pPostInfo = *it;
|
||||
|
||||
const char* szPostStageName[] = { "QUEUED", "LOADING_PARS", "VERIFYING_SOURCES", "REPAIRING", "VERIFYING_REPAIRED", "EXECUTING_SCRIPT", "FINISHED" };
|
||||
const char* szPostStageName[] = { "QUEUED", "LOADING_PARS", "VERIFYING_SOURCES", "REPAIRING", "VERIFYING_REPAIRED", "UNPACKING", "EXECUTING_SCRIPT", "FINISHED" };
|
||||
|
||||
char* xmlNZBNicename = EncodeStr(pPostInfo->GetNZBInfo()->GetName());
|
||||
char* xmlNZBFilename = EncodeStr(pPostInfo->GetNZBInfo()->GetFilename());
|
||||
@@ -1786,6 +1786,7 @@ void HistoryXmlCommand::Execute()
|
||||
"<member><name>DestDir</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>Category</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ParStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>UnpackStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>ScriptStatus</name><value><string>%s</string></value></member>\n"
|
||||
"<member><name>FileSizeLo</name><value><i4>%u</i4></value></member>\n"
|
||||
"<member><name>FileSizeHi</name><value><i4>%u</i4></value></member>\n"
|
||||
@@ -1816,6 +1817,7 @@ void HistoryXmlCommand::Execute()
|
||||
"\"DestDir\" : \"%s\",\n"
|
||||
"\"Category\" : \"%s\",\n"
|
||||
"\"ParStatus\" : \"%s\",\n"
|
||||
"\"UnpackStatus\" : \"%s\",\n"
|
||||
"\"ScriptStatus\" : \"%s\",\n"
|
||||
"\"FileSizeLo\" : %u,\n"
|
||||
"\"FileSizeHi\" : %u,\n"
|
||||
@@ -1864,6 +1866,7 @@ void HistoryXmlCommand::Execute()
|
||||
"}";
|
||||
|
||||
const char* szParStatusName[] = { "NONE", "FAILURE", "REPAIR_POSSIBLE", "SUCCESS" };
|
||||
const char* szUnpackStatusName[] = { "NONE", "NONE", "FAILURE", "SUCCESS" };
|
||||
const char* szScriptStatusName[] = { "NONE", "UNKNOWN", "FAILURE", "SUCCESS" };
|
||||
const char* szUrlStatusName[] = { "UNKNOWN", "UNKNOWN", "SUCCESS", "FAILURE", "UNKNOWN" };
|
||||
const char* szMessageType[] = { "INFO", "WARNING", "ERROR", "DEBUG", "DETAIL"};
|
||||
@@ -1899,9 +1902,10 @@ void HistoryXmlCommand::Execute()
|
||||
|
||||
snprintf(szItemBuf, szItemBufSize, IsJson() ? JSON_HISTORY_ITEM_START : XML_HISTORY_ITEM_START,
|
||||
pHistoryInfo->GetID(), pHistoryInfo->GetID(), "NZB", xmlNicename, xmlNicename, xmlNZBFilename,
|
||||
xmlDestDir, xmlCategory, szParStatusName[pNZBInfo->GetParStatus()],
|
||||
szScriptStatusName[pNZBInfo->GetScriptStatus()], iFileSizeLo, iFileSizeHi, iFileSizeMB,
|
||||
pNZBInfo->GetFileCount(), pNZBInfo->GetParkedFileCount(), pHistoryInfo->GetTime(), "", "");
|
||||
xmlDestDir, xmlCategory, szParStatusName[pNZBInfo->GetParStatus()],
|
||||
szUnpackStatusName[pNZBInfo->GetUnpackStatus()], szScriptStatusName[pNZBInfo->GetScriptStatus()],
|
||||
iFileSizeLo, iFileSizeHi, iFileSizeMB, pNZBInfo->GetFileCount(),
|
||||
pNZBInfo->GetParkedFileCount(), pHistoryInfo->GetTime(), "", "");
|
||||
|
||||
free(xmlDestDir);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#
|
||||
# This file if part of nzbget
|
||||
#
|
||||
# Template configuration file for postprocessing script "nzbget-postprocess.sh".
|
||||
# Template configuration file for post-processing script "nzbget-postprocess.sh".
|
||||
# Please refer to "nzbget-postprocess.sh" for usage instructions.
|
||||
#
|
||||
# Copyright (C) 2008-2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-2013 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
|
||||
@@ -22,45 +22,29 @@
|
||||
#
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
### PATHS ###
|
||||
|
||||
# Set the full path to unrar if it is not in your PATH.
|
||||
UnrarCmd=unrar
|
||||
|
||||
|
||||
##############################################################################
|
||||
### OPTIONS ###
|
||||
|
||||
# Delete rar-files after unpacking (yes, no).
|
||||
DeleteRarFiles=yes
|
||||
|
||||
# Rename img-files to iso (yes, no).
|
||||
RenameIMG=yes
|
||||
|
||||
# Joint TS-files (yes, no).
|
||||
JoinTS=no
|
||||
JoinTS=yes
|
||||
|
||||
##############################################################################
|
||||
### POSTPROCESSING-PARAMETERS ###
|
||||
|
||||
# This section defines parameters, which can be set for each nzb-file
|
||||
# individually using either web-interface or command line.
|
||||
# Example command line for setting parameter "password" to value "123" for
|
||||
# Example command line for setting parameter "PostProcess" to value "no" for
|
||||
# nzb-file with id=2:
|
||||
# nzbget -E G O Password=123 2
|
||||
# nzbget -E G O PostProcess=no 2
|
||||
|
||||
# Perform postprocessing (yes, no).
|
||||
#
|
||||
# Set to "no" to skip postprocessing for this nzb-file.
|
||||
PostProcess=yes
|
||||
|
||||
# Password for encrypted posts.
|
||||
#
|
||||
# If the post requires a password for unpacking.
|
||||
Password=
|
||||
|
||||
# Destination directory.
|
||||
#
|
||||
# NOTE: NZBGet must have write-access-rights for that directory.
|
||||
DestDir=
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Copyright (C) 2008 Peter Roubos <peterroubos@hotmail.com>
|
||||
# Copyright (C) 2008 Otmar Werner
|
||||
# Copyright (C) 2008-2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
# Copyright (C) 2008-2013 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
|
||||
@@ -25,8 +25,7 @@
|
||||
#
|
||||
|
||||
####################### Usage instructions #######################
|
||||
# o Script will unrar downloaded rar files, join ts-files and rename img-files
|
||||
# to iso.
|
||||
# o Script will cleanup, join ts-files and rename img-files to iso.
|
||||
#
|
||||
# o To use this script with nzbget set the option "PostProcess" in
|
||||
# nzbget configuration file to point to this script file. E.g.:
|
||||
@@ -41,41 +40,29 @@
|
||||
#
|
||||
# o There are few options, which can be ajdusted for each nzb-file individually.
|
||||
#
|
||||
# o The script supports the feature called "delayed par-check".
|
||||
# That means it can try to unpack downloaded files without par-checking
|
||||
# them fisrt. Only if unpack fails, the script schedules par-check,
|
||||
# then unpacks again.
|
||||
# To use delayed par-check set following options in nzbget configuration file:
|
||||
# ParCheck=no
|
||||
# ParRepair=yes
|
||||
# LoadPars=one (or) LoadPars=all
|
||||
#
|
||||
# o If you want to par-check/repair all files before trying to unpack them,
|
||||
# set option "ParCheck=yes".
|
||||
#
|
||||
####################### End of Usage instructions #######################
|
||||
|
||||
|
||||
# NZBGet passes following arguments to postprocess-programm as environment
|
||||
# variables:
|
||||
# NZBPP_DIRECTORY - path to destination dir for downloaded files;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file;
|
||||
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
|
||||
# found);
|
||||
# NZBPP_NZBNAME - user-friendly name of processed nzb-file as it is displayed
|
||||
# by the program. The file path and extension are removed.
|
||||
# If download was renamed, this parameter reflects the new name;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file. It includes file extension and also
|
||||
# may include full path;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string);
|
||||
# NZBPP_PARSTATUS - result of par-check:
|
||||
# 0 = not checked: par-check disabled or nzb-file does
|
||||
# 0 = not checked: par-check is disabled or nzb-file does
|
||||
# not contain any par-files;
|
||||
# 1 = checked and failed to repair;
|
||||
# 2 = checked and successfully repaired;
|
||||
# 3 = checked and can be repaired but repair is disabled;
|
||||
# NZBPP_NZBCOMPLETED - state of nzb-job:
|
||||
# 0 = there are more collections in this nzb-file queued;
|
||||
# 1 = this was the last collection in nzb-file;
|
||||
# NZBPP_PARFAILED - indication of failed par-jobs for current nzb-file:
|
||||
# 0 = no failed par-jobs;
|
||||
# 1 = current par-job or any of the previous par-jobs for
|
||||
# the same nzb-files failed;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string).
|
||||
# 3 = checked and can be repaired but repair is disabled.
|
||||
# NZBPP_UNPACKSTATUS - result of unpack:
|
||||
# 0 = unpack is disabled or was skipped due to nzb-file
|
||||
# properties or due to errors during par-check;
|
||||
# 1 = unpack failed;
|
||||
# 2 = unpack successful.
|
||||
|
||||
|
||||
# Name of script's configuration file
|
||||
@@ -99,7 +86,7 @@ fi
|
||||
# (for current nzb-file) via web-interface or via command line with
|
||||
# "nzbget -E G O PostProcess=no <ID>"
|
||||
if [ "$NZBPR_PostProcess" = "no" ]; then
|
||||
echo "[WARNING] Post-Process: Postprocessing disabled for this nzb-file, exiting"
|
||||
echo "[WARNING] Post-Process: Post-processing disabled for this nzb-file, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
@@ -129,27 +116,11 @@ if [ "$NZBOP_ALLOWREPROCESS" = "yes" ]; then
|
||||
BadConfig=1
|
||||
fi
|
||||
|
||||
if [ "$NZBOP_LOADPARS" = "none" ]; then
|
||||
echo "[ERROR] Post-Process: Please set option \"LoadPars\" to \"One\" or \"All\" in nzbget configuration file"
|
||||
BadConfig=1
|
||||
fi
|
||||
|
||||
if [ "$NZBOP_PARREPAIR" = "no" ]; then
|
||||
echo "[ERROR] Post-Process: Please set option \"ParRepair\" to \"Yes\" in nzbget configuration file"
|
||||
BadConfig=1
|
||||
fi
|
||||
|
||||
if [ "$BadConfig" -eq 1 ]; then
|
||||
echo "[ERROR] Post-Process: Exiting because of not compatible nzbget configuration"
|
||||
echo "[ERROR] Post-Process: Exiting due to incompatible nzbget configuration"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Check if all collections in nzb-file were downloaded
|
||||
if [ ! "$NZBPP_NZBCOMPLETED" -eq 1 ]; then
|
||||
echo "[INFO] Post-Process: Not the last collection in nzb-file, exiting"
|
||||
exit $POSTPROCESS_SUCCESS
|
||||
fi
|
||||
|
||||
# Check par status
|
||||
if [ "$NZBPP_PARSTATUS" -eq 1 -o "$NZBPP_PARSTATUS" -eq 3 -o "$NZBPP_PARFAILED" -eq 1 ]; then
|
||||
if [ "$NZBPP_PARSTATUS" -eq 3 ]; then
|
||||
@@ -157,7 +128,13 @@ if [ "$NZBPP_PARSTATUS" -eq 1 -o "$NZBPP_PARSTATUS" -eq 3 -o "$NZBPP_PARFAILED"
|
||||
else
|
||||
echo "[WARNING] Post-Process: Par-check failed, exiting"
|
||||
fi
|
||||
exit $POSTPROCESS_ERROR
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
# Check unpack status
|
||||
if [ "$NZBPP_UNPACKSTATUS" -ne 2 ]; then
|
||||
echo "[WARNING] Post-Process: Unpack failed or disabled, exiting"
|
||||
exit $POSTPROCESS_NONE
|
||||
fi
|
||||
|
||||
# Check if destination directory exists (important for reprocessing of history items)
|
||||
@@ -168,109 +145,8 @@ fi
|
||||
|
||||
cd "$NZBPP_DIRECTORY"
|
||||
|
||||
# If not just repaired and file "_brokenlog.txt" exists, the collection is damaged
|
||||
# exiting with returning code $POSTPROCESS_PARCHECK_ALL to request par-repair
|
||||
if [ ! "$NZBPP_PARSTATUS" -eq 2 ]; then
|
||||
if [ -f "_brokenlog.txt" ]; then
|
||||
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Brokenlog found, requesting par-repair"
|
||||
exit $POSTPROCESS_PARCHECK_ALL
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# All checks done, now processing the files
|
||||
|
||||
# Flag indicates that something was unrared
|
||||
Unrared=0
|
||||
|
||||
# Unrar the files (if any) to the temporary directory, if there are no rar files this will do nothing
|
||||
if (ls *.rar >/dev/null 2>&1); then
|
||||
|
||||
# Check if unrar exists
|
||||
$UnrarCmd >/dev/null 2>&1
|
||||
if [ "$?" -eq 127 ]; then
|
||||
echo "[ERROR] Post-Process: Unrar not found. Set the path to unrar in script's configuration"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Make a temporary directory to store the unrarred files
|
||||
ExtractedDirExists=0
|
||||
if [ -d extracted ]; then
|
||||
ExtractedDirExists=1
|
||||
else
|
||||
mkdir extracted
|
||||
fi
|
||||
|
||||
echo "[INFO] Post-Process: Unraring"
|
||||
rarpasswordparam=""
|
||||
if [ "$NZBPR_Password" != "" ]; then
|
||||
rarpasswordparam="-p$NZBPR_Password"
|
||||
fi
|
||||
|
||||
$UnrarCmd x -y -p- "$rarpasswordparam" -o+ "*.rar" ./extracted/
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo "[ERROR] Post-Process: Unrar failed"
|
||||
if [ "$ExtractedDirExists" -eq 0 ]; then
|
||||
rm -R extracted
|
||||
fi
|
||||
# for delayed par-check/-repair at least one par-file must be already downloaded
|
||||
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Requesting par-repair"
|
||||
exit $POSTPROCESS_PARCHECK_ALL
|
||||
fi
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
Unrared=1
|
||||
|
||||
# Remove the rar files
|
||||
if [ "$DeleteRarFiles" = "yes" ]; then
|
||||
echo "[INFO] Post-Process: Deleting rar-files"
|
||||
rm *.r[0-9][0-9] >/dev/null 2>&1
|
||||
rm *.rar >/dev/null 2>&1
|
||||
rm *.s[0-9][0-9] >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Go to the temp directory and try to unrar again.
|
||||
# If there are any rars inside the extracted rars then these will no also be unrarred
|
||||
cd extracted
|
||||
if (ls *.rar >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: Unraring (second pass)"
|
||||
$UnrarCmd x -y -p- -o+ "*.rar"
|
||||
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo "[INFO] Post-Process: Unrar (second pass) failed"
|
||||
exit $POSTPROCESS_ERROR
|
||||
fi
|
||||
|
||||
# Delete the Rar files
|
||||
if [ "$DeleteRarFiles" = "yes" ]; then
|
||||
echo "[INFO] Post-Process: Deleting rar-files (second pass)"
|
||||
rm *.r[0-9][0-9] >/dev/null 2>&1
|
||||
rm *.rar >/dev/null 2>&1
|
||||
rm *.s[0-9][0-9] >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Move everything back to the Download folder
|
||||
mv * ..
|
||||
cd ..
|
||||
rmdir extracted
|
||||
fi
|
||||
|
||||
|
||||
# If there were nothing to unrar and the download was not par-checked,
|
||||
# we don't know if it's OK. To be sure we force par-check.
|
||||
# In particular that helps with downloads containing renamed rar-files.
|
||||
# The par-repair will rename files to correct names, then we can unpack.
|
||||
if [ "$Unrared" -eq 0 -a "$NZBPP_PARSTATUS" -eq 0 ]; then
|
||||
if (ls *.[pP][aA][rR]2 >/dev/null 2>&1); then
|
||||
echo "[INFO] Post-Process: No rar-files found, requesting par-check"
|
||||
exit $POSTPROCESS_PARCHECK_ALL
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# If download contains only nzb-files move them into nzb-directory
|
||||
# for further download
|
||||
# Check if command "wc" exists
|
||||
@@ -291,10 +167,7 @@ rm *.nzb >/dev/null 2>&1
|
||||
rm *.sfv >/dev/null 2>&1
|
||||
rm *.1 >/dev/null 2>&1
|
||||
rm _brokenlog.txt >/dev/null 2>&1
|
||||
if [ "$Unrared" -eq 1 ]; then
|
||||
# Delete par2-file only if there were files for unpacking.
|
||||
rm *.[pP][aA][rR]2 >/dev/null 2>&1
|
||||
fi
|
||||
rm *.[pP][aA][rR]2 >/dev/null 2>&1
|
||||
|
||||
if [ "$JoinTS" = "yes" ]; then
|
||||
# Join any split .ts files if they are named xxxx.0000.ts xxxx.0001.ts
|
||||
|
||||
182
nzbget.conf
182
nzbget.conf
@@ -66,7 +66,6 @@ LogFile=${DestDir}/nzbget.log
|
||||
# it is also used to serve JSON-/XML-RPC requests.
|
||||
WebDir=
|
||||
|
||||
|
||||
##############################################################################
|
||||
### NEWS-SERVERS ###
|
||||
|
||||
@@ -738,7 +737,11 @@ UpdateInterval=200
|
||||
# Paused files remain in queue and can be unpaused by parchecker when needed.
|
||||
LoadPars=one
|
||||
|
||||
# Automatic par-verification (yes, no).
|
||||
# Force par-verification (yes, no).
|
||||
#
|
||||
# Force par-check for every download. When set to "no" the par-check is
|
||||
# performed only if the unpacker or the post-processing script detect a
|
||||
# damaged download.
|
||||
#
|
||||
# To download only needed par2-files (smart par-files loading) set also
|
||||
# the option <LoadPars> to "one". If option <LoadPars> is set to "all",
|
||||
@@ -751,7 +754,7 @@ ParCheck=no
|
||||
#
|
||||
# If option <ParCheck> is enabled and <ParRepair> is not, the program
|
||||
# only verifies downloaded files and downloads needed par2-files, but does
|
||||
# not start repair-process. This is useful if the server does not have
|
||||
# not start repair-process. This is useful if computer does not have
|
||||
# enough CPU power, since repairing of large files may take too much
|
||||
# resources and time on a slow computers.
|
||||
ParRepair=yes
|
||||
@@ -823,7 +826,7 @@ ParTimeLimit=0
|
||||
# NOTE: If parchecker needs additional par-files it temporarily unpauses
|
||||
# the queue.
|
||||
#
|
||||
# NOTE: See also option <PostPauseQueue>.
|
||||
# NOTE: See also options <PostPauseQueue> and <UnpackPauseQueue>.
|
||||
ParPauseQueue=no
|
||||
|
||||
# Cleanup download queue after successful check/repair (yes, no).
|
||||
@@ -839,38 +842,110 @@ ParCleanupQueue=yes
|
||||
NzbCleanupDisk=no
|
||||
|
||||
|
||||
##############################################################################
|
||||
### UNPACK ###
|
||||
|
||||
# Unpack downloaded nzb-files (yes, no).
|
||||
#
|
||||
# If the download is damaged and could not be repaired using par-files
|
||||
# the unpacking is not performed.
|
||||
#
|
||||
# If the option <ParCheck> is disabled the program will try to unpack
|
||||
# downloaded files first. If the unpacking fails the par-check/repair
|
||||
# is performed and the unpack will be executed again.
|
||||
Unpack=yes
|
||||
|
||||
# Pause download queue during unpack (yes, no).
|
||||
#
|
||||
# Enable the option to give CPU more time for unpacking. That helps
|
||||
# to speed up unpacking on slow CPUs.
|
||||
#
|
||||
# NOTE: See also options <ParPauseQueue> and <PostPauseQueue>.
|
||||
UnpackPauseQueue=no
|
||||
|
||||
# Delete archive files after successful unpacking (yes, no).
|
||||
UnpackCleanupDisk=yes
|
||||
|
||||
# Full path to unrar executable.
|
||||
#
|
||||
# Example: "/usr/bin/unrar".
|
||||
#
|
||||
# If unrar is in your PATH you may leave the path part and set only
|
||||
# the executable name ("unrar" on POSIX or "unrar.exe" on Windows).
|
||||
UnrarCmd=unrar
|
||||
|
||||
# Full path to 7-Zip executable.
|
||||
#
|
||||
# Example: "/usr/bin/7z".
|
||||
#
|
||||
# If 7-Zip binary is in your PATH you may leave the path part and set only
|
||||
# the executable name ("7z" or "7za" on POSIX or "7z.exe" on Windows).
|
||||
SevenZipCmd=7z
|
||||
|
||||
|
||||
##############################################################################
|
||||
### POST-PROCESSING ###
|
||||
|
||||
# Set path to program, that must be executed after the download of nzb-file
|
||||
# or one collection in nzb-file is completed and possibly par-checked/repaired.
|
||||
# is completed and possibly par-checked/repaired and unpacked, depending
|
||||
# on other options.
|
||||
#
|
||||
# Example: "PostProcess=~/nzbget-postprocess.sh".
|
||||
#
|
||||
# NOTE: An example script for unrarring is provided within distribution
|
||||
# in file "nzbget-postprocess.sh".
|
||||
# NOTE: An example script is provided within distribution in file
|
||||
# "nzbget-postprocess.sh".
|
||||
#
|
||||
# NOTE: Since version 10.0 NZBGet has a built-in support for unpack
|
||||
# (option <Unpack>). In the previous versions unpack was performed by
|
||||
# post-processing scripts. If you use a script created for older NZBGet
|
||||
# version you need to disable the built-in unpack for script to operate
|
||||
# properly.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# NZBGet passes following arguments to postprocess-program as environment
|
||||
# If the option <AllowReProcess> is disabled (that's the default setting)
|
||||
# the post-processing script is executed once per nzb-file after
|
||||
# par-check/repair (if needed) and unpacking (if enabled).
|
||||
#
|
||||
# If the option <AllowReProcess> is active the post-processing script is
|
||||
# executed for each collection within nzb-file (for nzb-files having multiple
|
||||
# collections but at least once). Depending on option <ParCheck> the collection
|
||||
# could be already par-checked/repaired or the script could be called without
|
||||
# par-check taken place. In the latest case if the script detects errors
|
||||
# (such as unpack failed) it has an ability to request par-check from
|
||||
# NZBGet. After par-check/repair NZBGet calls the script once again.
|
||||
#
|
||||
# NZBGet passes following arguments to post-processing script as environment
|
||||
# variables:
|
||||
# NZBPP_DIRECTORY - path to destination dir for downloaded files;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file;
|
||||
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
|
||||
# found);
|
||||
# NZBPP_NZBNAME - user-friendly name of processed nzb-file as it is displayed
|
||||
# by the program. The file path and extension are removed.
|
||||
# If download was renamed, this parameter reflects the new name;
|
||||
# NZBPP_NZBFILENAME - name of processed nzb-file. It includes file extension and also
|
||||
# may include full path;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string);
|
||||
# NZBPP_PARSTATUS - result of par-check:
|
||||
# 0 = not checked: par-check disabled or nzb-file does
|
||||
# 0 = not checked: par-check is disabled or nzb-file does
|
||||
# not contain any par-files;
|
||||
# 1 = checked and failed to repair;
|
||||
# 2 = checked and successfully repaired;
|
||||
# 3 = checked and can be repaired but repair is disabled;
|
||||
# NZBPP_NZBCOMPLETED - state of nzb-job:
|
||||
# 0 = there are more collections in this nzb-file queued;
|
||||
# 1 = this was the last collection in nzb-file;
|
||||
# 3 = checked and can be repaired but repair is disabled.
|
||||
# NZBPP_UNPACKSTATUS - result of unpack:
|
||||
# 0 = unpack is disabled or was skipped due to nzb-file
|
||||
# properties or due to errors during par-check;
|
||||
# 1 = unpack failed;
|
||||
# 2 = unpack successful.
|
||||
#
|
||||
# In addition the following arguments are passed if the option <AllowReProcess>
|
||||
# is active:
|
||||
# NZBPP_PARFILENAME - name of par-file or empty string (if no collections were
|
||||
# found);
|
||||
# NZBPP_PARFAILED - indication of failed par-jobs for current nzb-file:
|
||||
# 0 = no failed par-jobs;
|
||||
# 1 = current par-job or any of the previous par-jobs for
|
||||
# the same nzb-files failed;
|
||||
# NZBPP_CATEGORY - category assigned to nzb-file (can be empty string).
|
||||
# NZBPP_NZBCOMPLETED - state of nzb-job:
|
||||
# 0 = there are more collections in this nzb-file queued;
|
||||
# 1 = this was the last collection in nzb-file.
|
||||
#
|
||||
# If nzb-file has associated postprocess-parameters (which can be set using
|
||||
# subcommand <O> of command <-E>, for example: NZBGet -E G O "myvar=hello !" 10)
|
||||
@@ -888,13 +963,14 @@ NzbCleanupDisk=no
|
||||
# the values are passed always in lower case.
|
||||
#
|
||||
# Return value: NZBGet processes the exit code returned by the script:
|
||||
# 91 - request NZBGet to do par-check/repair for current collection in the
|
||||
# current nzb-file;
|
||||
# 92 - request NZBGet to do par-check/repair for all collections in the
|
||||
# current nzb-file;
|
||||
# 93 - post-process successful (status = SUCCESS);
|
||||
# 94 - post-process failed (status = FAILURE);
|
||||
# 95 - post-process skipped (status = NONE);
|
||||
# 91 - request NZBGet to do par-check/repair for current collection in the
|
||||
# current nzb-file. This return code is accepted only if the
|
||||
# option <AllowReProcess> is active;
|
||||
# 92 - request NZBGet to do par-check/repair for all collections (par-sets)
|
||||
# in the current nzb-file.
|
||||
# All other return codes are interpreted as "status unknown".
|
||||
#
|
||||
# The return value is used to display the status of post-processing in
|
||||
@@ -903,62 +979,42 @@ NzbCleanupDisk=no
|
||||
# to standard output. For example:
|
||||
# echo "[ERROR] [HISTORY] Unpack failed, not enough disk space";
|
||||
#
|
||||
# NOTE: The parameter NZBPP_NZBCOMPLETED is very important and MUST be checked
|
||||
# even in the simplest scripts.
|
||||
# If par-check is enabled and nzb-file contains more than one collection
|
||||
# of files the postprocess-program is called after each collection is completed
|
||||
# and par-checked. If you want to unpack files or clean up the directory
|
||||
# (delete par-files, etc.) there are two possibilities, when you can do this:
|
||||
# 1) you parse NZBPP_PARFILENAME to find out the base name of collection and
|
||||
# clean up only files from this collection (not reliable, because par-files
|
||||
# sometimes have different names than rar-files);
|
||||
# 2) or you just check the parameters NZBPP_NZBCOMPLETED and NZBPP_PARFAILED
|
||||
# and do the processing, only if NZBPP_NZBCOMPLETED is set to "1" (which
|
||||
# means, that this was the last collection in nzb-file and all files
|
||||
# are now completed) and NZBPP_PARFAILED is set to "0" (no failed par-jobs);
|
||||
#
|
||||
# NOTE: The term "collection" in the above description actually means
|
||||
# NOTE: If the option <AllowReProcess> is active NZBGet calls the script
|
||||
# for each collection within nzb-file. The term "collection" actually means
|
||||
# "par-set". To determine what "collections" are present in nzb-file NZBGet
|
||||
# looks for par-sets. If any collection of files within nzb-file does
|
||||
# not have any par-files, this collection will not be detected.
|
||||
# For example, for nzb-file containing three collections but only two par-sets,
|
||||
# the postprocess will be called two times - after processing of each par-set.
|
||||
#
|
||||
# NOTE: If NZBGet doesn't find any collections it calls PostProcess once
|
||||
# with empty string for parameter NZBPP_PARFILENAME;
|
||||
#
|
||||
# NOTE: The using of special return values (91 and 92) for requesting of
|
||||
# par-check/repair allows to organize the delayed parcheck. To do that:
|
||||
# 1) set options: LoadPars=one, ParCheck=no, ParRepair=yes;
|
||||
# 2) in post-process-script check the parameter NZBPP_PARSTATUS. If it is "0",
|
||||
# that means, the script is called for the first time. Try to unpack files.
|
||||
# If unpack fails, exit the script with exit code for par-check/repair;
|
||||
# 3) NZBGet will start par-check/repair. After that it calls the script again;
|
||||
# 4) on second pass the parameter NZBPP_PARSTATUS will have value
|
||||
# greater than "0". If it is "2" ("checked and successfully repaired")
|
||||
# you can try unpack again.
|
||||
# If NZBGet doesn't find any collections it calls PostProcess once
|
||||
# with empty string for parameter NZBPP_PARFILENAME.
|
||||
PostProcess=
|
||||
|
||||
# Allow multiple post-processing for the same nzb-file (yes, no).
|
||||
#
|
||||
# NOTE: Enable this option only if you were advised to do that by the author
|
||||
# of the post-process-script.
|
||||
# of the post-processing script.
|
||||
#
|
||||
# NOTE: By enabling <AllowReProcess> you should disable the option <ParCheck>
|
||||
# to prevent multiple par-checking.
|
||||
#
|
||||
# INFO FOR DEVELOPERS:
|
||||
# After the post-processing (par-check and call of a postprocess-script) is
|
||||
# completed, NZBGet adds the nzb-file to a list of completed-jobs. The nzb-file
|
||||
# stays in the list until the last file from that nzb-file is deleted from
|
||||
# the download queue (it occurs straight away if the par-check was successful
|
||||
# and the option <ParCleanupQueue> is enabled).
|
||||
# That means, if a paused file from a nzb-collection becomes unpaused
|
||||
# (manually or from a post-process-script) after the collection was already
|
||||
# postprocessed NZBGet will not post-process nzb-file again.
|
||||
# This prevents the unwanted multiple post-processings of the same nzb-file.
|
||||
# But it might be needed if the par-check/-repair are performed not directly
|
||||
# by NZBGet but from a post-process-script.
|
||||
# This option affects the post-processing in several ways:
|
||||
# 1) If the option is active the post-processing script (option <PostProcess>)
|
||||
# is called for each collection (par-set) within nzb-file;
|
||||
# 2) The post-processing script may be called multiple times when nzb-file
|
||||
# reaches the state "completely downloaded". This can be needed if
|
||||
# the par-check/-repair is performed by the post-processing script
|
||||
# (instead of relying on NZBGet's built-in par-check-feature).
|
||||
#
|
||||
# NOTE: If the built-in unpacking is active (option <Unpack>) this option
|
||||
# is ignored (as if it were set to "no").
|
||||
#
|
||||
# NOTE: If you develop a script depending on this option you should check
|
||||
# if the option is active when your script is started and generate an
|
||||
# error message if the option is not set correctly. You should also check
|
||||
# the option <Unpack> because if it's active the option <AllowReProcess>
|
||||
# doesn't work too.
|
||||
AllowReProcess=no
|
||||
|
||||
# Pause download queue during executing of postprocess-script (yes, no).
|
||||
@@ -966,7 +1022,7 @@ AllowReProcess=no
|
||||
# Enable the option to give CPU more time for postprocess-script. That helps
|
||||
# to speed up postprocess on slow CPUs with fast connection (e.g. NAS-devices).
|
||||
#
|
||||
# NOTE: See also option <ParPauseQueue>.
|
||||
# NOTE: See also options <ParPauseQueue> and <UnpackPauseQueue>.
|
||||
PostPauseQueue=no
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2013 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
|
||||
@@ -336,6 +336,7 @@ var Options = (new function($)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
this.findOption = findOption;
|
||||
|
||||
function mergeValues(config, values)
|
||||
{
|
||||
@@ -662,9 +663,9 @@ var Config = (new function($)
|
||||
value = option.defvalue;
|
||||
}
|
||||
|
||||
option.formId = section.category + '-' + option.name.replace(/[\.|$]/g, '_');
|
||||
option.formId = section.category + '-' + option.name.replace(/[\.|$|\:|\*]/g, '_');
|
||||
|
||||
var caption = option.name;
|
||||
var caption = option.caption ? option.caption : option.name;
|
||||
if (section.multi)
|
||||
{
|
||||
caption = '<span class="config-multicaption">' + caption.substring(0, caption.indexOf('.') + 1) + '</span>' + caption.substring(caption.indexOf('.') + 1);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2013 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
|
||||
@@ -273,7 +273,8 @@ var Downloads = (new function($)
|
||||
case 'VERIFYING_SOURCES': group.status = 'checking'; break;
|
||||
case 'REPAIRING': group.status = 'repairing'; break;
|
||||
case 'VERIFYING_REPAIRED': group.status = 'verifying'; break;
|
||||
case 'EXECUTING_SCRIPT': group.status = 'unpacking'; break;
|
||||
case 'UNPACKING': group.status = 'unpacking'; break;
|
||||
case 'EXECUTING_SCRIPT': group.status = 'processing'; break;
|
||||
case 'FINISHED': group.status = 'finished'; break;
|
||||
default: group.status = 'error: ' + group.post.Stage; break;
|
||||
}
|
||||
@@ -633,15 +634,28 @@ var DownloadsUI = (new function($)
|
||||
this.buildProgressLabel = function(group)
|
||||
{
|
||||
var text = '';
|
||||
if (group.postprocess && !Status.status.PostPaused && group.post.Stage !== 'REPAIRING')
|
||||
if (group.postprocess && !Status.status.PostPaused)
|
||||
{
|
||||
if (group.post.Log && group.post.Log.length > 0)
|
||||
switch (group.post.Stage)
|
||||
{
|
||||
text = group.post.Log[group.post.Log.length-1].Text;
|
||||
}
|
||||
else if (group.post.ProgressLabel !== '')
|
||||
{
|
||||
text = group.post.ProgressLabel;
|
||||
case "REPAIRING":
|
||||
break;
|
||||
case "LOADING_PARS":
|
||||
case "VERIFYING_SOURCES":
|
||||
case "VERIFYING_REPAIRED":
|
||||
case "UNPACKING":
|
||||
text = group.post.ProgressLabel;
|
||||
break;
|
||||
case "EXECUTING_SCRIPT":
|
||||
if (group.post.Log && group.post.Log.length > 0)
|
||||
{
|
||||
text = group.post.Log[group.post.Log.length-1].Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
text = group.post.ProgressLabel;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2013 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
|
||||
@@ -149,6 +149,7 @@ var DownloadsEditDialog = (new function($)
|
||||
table += '<tr><td>Total</td><td class="text-right">' + size + '</td></tr>';
|
||||
table += '<tr><td>Paused</td><td class="text-right">' + unpausedSize + '</td></tr>';
|
||||
table += '<tr><td>Unpaused</td><td class="text-right">' + remaining + '</td></tr>';
|
||||
//table += '<tr><td>Active downloads</td><td class="text-right">' + group.ActiveDownloads + '</td></tr>';
|
||||
table += '<tr><td>Estimated time</td><td class="text-right">' + estimated + '</td></tr>';
|
||||
table += '<tr><td>Files (total/remaining/pars)</td><td class="text-center">' + group.FileCount + ' / ' +
|
||||
group.RemainingFileCount + ' / ' + group.RemainingParCount + '</td></tr>';
|
||||
@@ -182,13 +183,16 @@ var DownloadsEditDialog = (new function($)
|
||||
$DownloadsLogTable.fasttable('update', []);
|
||||
$DownloadsFileTable.fasttable('update', []);
|
||||
|
||||
var postParamConfig = Options.postParamConfig;
|
||||
defineBuiltinParams(postParamConfig);
|
||||
|
||||
Util.show('#DownloadsEdit_NZBNameReadonly', group.postprocess);
|
||||
Util.show('#DownloadsEdit_CancelPPGroup', group.postprocess);
|
||||
Util.show('#DownloadsEdit_DeleteGroup', !group.postprocess);
|
||||
Util.show('#DownloadsEdit_PauseGroup', !group.postprocess);
|
||||
Util.show('#DownloadsEdit_ResumeGroup', false);
|
||||
Util.show('#DownloadsEdit_Save', !group.postprocess);
|
||||
var postParam = Options.postParamConfig && Options.postParamConfig.length > 0;
|
||||
var postParam = postParamConfig && postParamConfig.length > 0;
|
||||
var postLog = group.postprocess && group.post.Log.length > 0;
|
||||
Util.show('#DownloadsEdit_Param', postParam);
|
||||
Util.show('#DownloadsEdit_Log', postLog);
|
||||
@@ -216,7 +220,7 @@ var DownloadsEditDialog = (new function($)
|
||||
|
||||
if (postParam)
|
||||
{
|
||||
postParams = $.extend(true, [], Options.postParamConfig);
|
||||
postParams = $.extend(true, [], postParamConfig);
|
||||
Options.mergeValues(postParams, group.Parameters);
|
||||
var content = Config.buildOptionsContent(postParams[0]);
|
||||
var configData = $('#DownloadsEdit_ParamData');
|
||||
@@ -427,6 +431,25 @@ var DownloadsEditDialog = (new function($)
|
||||
|
||||
/*** TAB: POST-PROCESSING PARAMETERS **************************************************/
|
||||
|
||||
function defineBuiltinParams(postParamConfig)
|
||||
{
|
||||
if (Options.option('Unpack') !== 'yes')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (postParamConfig.length == 0)
|
||||
{
|
||||
postParamConfig.push({category: 'P', postparam: true, options: []});
|
||||
}
|
||||
|
||||
if (!Options.findOption(postParamConfig[0].options, '*Unpack:'))
|
||||
{
|
||||
postParamConfig[0].options.unshift({name: '*Unpack:Password', value: '', defvalue: '', select: [], caption: 'Password', description: 'Unpack-password for encrypted posts.'});
|
||||
postParamConfig[0].options.unshift({name: '*Unpack:', value: '', defvalue: 'yes', select: ['yes', 'no'], caption: 'Unpack', description: 'Set to "no" to disable unpack for this nzb-file.'});
|
||||
}
|
||||
}
|
||||
|
||||
function prepareParamRequest()
|
||||
{
|
||||
var request = [];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of nzbget
|
||||
*
|
||||
* Copyright (C) 2012 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
||||
* Copyright (C) 2012-2013 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
|
||||
@@ -113,19 +113,29 @@ var History = (new function($)
|
||||
{
|
||||
if (hist.Kind === 'NZB')
|
||||
{
|
||||
switch (hist.ScriptStatus)
|
||||
if (hist.ParStatus == 'FAILURE' || hist.UnpackStatus == 'FAILURE' || hist.ScriptStatus == 'FAILURE')
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'FAILURE': hist.status = 'failure'; break;
|
||||
case 'UNKNOWN': hist.status = 'unknown'; break;
|
||||
case 'NONE':
|
||||
switch (hist.ParStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'REPAIR_POSSIBLE': hist.status = 'repairable'; break;
|
||||
case 'FAILURE': hist.status = 'failure'; break;
|
||||
case 'NONE': hist.status = 'none'; break;
|
||||
}
|
||||
hist.status = 'failure';
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (hist.ScriptStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'UNKNOWN': hist.status = 'unknown'; break;
|
||||
case 'NONE':
|
||||
switch (hist.UnpackStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'NONE':
|
||||
switch (hist.ParStatus)
|
||||
{
|
||||
case 'SUCCESS': hist.status = 'success'; break;
|
||||
case 'REPAIR_POSSIBLE': hist.status = 'repairable'; break;
|
||||
case 'NONE': hist.status = 'unknown'; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hist.Kind === 'URL')
|
||||
@@ -180,7 +190,7 @@ var History = (new function($)
|
||||
{
|
||||
var hist = item.hist;
|
||||
|
||||
var status = buildStatus(hist);
|
||||
var status = buildStatus(hist.status, '');
|
||||
|
||||
var name = '<a href="#" histid="' + hist.ID + '">' + Util.textToHtml(Util.formatNZBName(hist.Name)) + '</a>';
|
||||
var category = Util.textToHtml(hist.Category);
|
||||
@@ -222,16 +232,27 @@ var History = (new function($)
|
||||
}
|
||||
}
|
||||
|
||||
function buildStatus(hist)
|
||||
function buildStatus(status, prefix)
|
||||
{
|
||||
switch (hist.status)
|
||||
switch (status)
|
||||
{
|
||||
case 'success': return '<span class="label label-status label-success">success</span>';
|
||||
case 'failure': return '<span class="label label-status label-important">failure</span>';
|
||||
case 'unknown': return '<span class="label label-status label-info">unknown</span>';
|
||||
case 'repairable': return '<span class="label label-status label-success">repairable</span>';
|
||||
case 'none': return '<span class="label label-status">unknown</span>';
|
||||
default: return '<span class="label label-status label-important">internal error(' + hist.status + ')</span>';
|
||||
case 'success':
|
||||
case 'SUCCESS':
|
||||
return '<span class="label label-status label-success">' + prefix + 'success</span>';
|
||||
case 'failure':
|
||||
case 'FAILURE':
|
||||
return '<span class="label label-status label-important">' + prefix + 'failure</span>';
|
||||
case 'unknown':
|
||||
case 'UNKNOWN':
|
||||
return '<span class="label label-status label-info">' + prefix + 'unknown</span>';
|
||||
case 'repairable':
|
||||
case 'REPAIR_POSSIBLE':
|
||||
return '<span class="label label-status label-success">' + prefix + 'repairable</span>';
|
||||
case 'none':
|
||||
case 'NONE':
|
||||
return '<span class="label label-status">' + prefix + 'none</span>';
|
||||
default:
|
||||
return '<span class="label label-status">' + prefix + status + '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,7 +379,17 @@ var History = (new function($)
|
||||
|
||||
curHist = hist;
|
||||
|
||||
var status = buildStatus(hist);
|
||||
var status;
|
||||
if (hist.Kind === 'URL')
|
||||
{
|
||||
status = buildStatus(hist.status, '');
|
||||
}
|
||||
else
|
||||
{
|
||||
status = buildStatus(hist.ParStatus, 'Par: ') + ' ' +
|
||||
(Options.option('Unpack') == 'yes' || hist.UnpackStatus != 'NONE' ? buildStatus(hist.UnpackStatus, 'Unpack: ') + ' ' : '') +
|
||||
buildStatus(hist.ScriptStatus, 'Script: ');
|
||||
}
|
||||
|
||||
$('#HistoryEdit_Title').text(Util.formatNZBName(hist.Name));
|
||||
if (hist.Kind === 'URL')
|
||||
|
||||
@@ -732,13 +732,13 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<div class="modal-bottom-toolbar">
|
||||
<button class="btn" data-tab="DownloadsEdit_FileTab" data-fullscreen="true" id="DownloadsEdit_File">Files <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_ParamTab" id="DownloadsEdit_Param" title="Post-processing parameters">PP Parameters <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_LogTab" data-fullscreen="true" id="DownloadsEdit_Log" title="Post-processing messages">PP Messages <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_FileTab" data-fullscreen="true" id="DownloadsEdit_File" title="File list">Files <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_ParamTab" id="DownloadsEdit_Param" title="Post-processing parameters">PP-Parameters <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
<button class="btn" data-tab="DownloadsEdit_LogTab" data-fullscreen="true" id="DownloadsEdit_Log" title="Post-processing messages">PP-Messages <i class="icon-forward" style="opacity:0.6;"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user