From d26d04d92b3c340ef1e97a65732c8a73badd6208 Mon Sep 17 00:00:00 2001 From: Andrey Prygunkov Date: Fri, 13 Jun 2014 21:53:27 +0000 Subject: [PATCH] when changing category in web-interface the post-processing parameters are now automatically updated according to new category settings; only parameters which are different in old and new category are changed; parameters which present in both or in neither categories are not changed; that ensures that only the relevant parameters are updated and parameters which were manually changed by user remain they settings when it make sense; in the "download details dialog" the new parameters are updated on the postprocess-tab directly after changing of category and can be controlled before saving; in the "edit multiple downloads dialog" the parameters are updated individually for each download on saving; new action "CP" of remote command "--edit/-E" for groups to set category and apply parameters; new action "GroupApplyCategory of RPC-method "editqueue" for the same purpose --- daemon/main/Options.cpp | 5 +- daemon/queue/DownloadInfo.h | 1 + daemon/queue/QueueEditor.cpp | 88 +++++++++++++++++++++++++++++++++++- daemon/queue/QueueEditor.h | 2 +- daemon/remote/MessageBase.h | 2 +- daemon/remote/XmlRpc.cpp | 1 + webui/config.js | 41 +++++++++-------- webui/edit.js | 73 +++++++++++++++++++++++++++++- webui/util.js | 17 ++++++- 9 files changed, 203 insertions(+), 27 deletions(-) diff --git a/daemon/main/Options.cpp b/daemon/main/Options.cpp index d9ab7b11..c06f7453 100644 --- a/daemon/main/Options.cpp +++ b/daemon/main/Options.cpp @@ -1459,14 +1459,14 @@ void Options::InitCommandLine(int argc, char* argv[]) { m_iEditQueueAction = bGroup ? DownloadQueue::eaGroupDelete : DownloadQueue::eaFileDelete; } - else if (!strcasecmp(optarg, "C") || !strcasecmp(optarg, "K")) + else if (!strcasecmp(optarg, "C") || !strcasecmp(optarg, "K") || !strcasecmp(optarg, "CP")) { // switch "K" is provided for compatibility with v. 0.8.0 and can be removed in future versions if (!bGroup) { abort("FATAL ERROR: Category can be set only for groups\n"); } - m_iEditQueueAction = DownloadQueue::eaGroupSetCategory; + m_iEditQueueAction = !strcasecmp(optarg, "CP") ? DownloadQueue::eaGroupApplyCategory : DownloadQueue::eaGroupSetCategory; optind++; if (optind > argc) @@ -1708,6 +1708,7 @@ void Options::PrintUsage(char* com) " R Pause extra pars\n" " I Set priority (signed integer)\n" " C Set category\n" + " CP Set category and apply post-process parameters\n" " N Rename\n" " M Merge\n" " S Split - create new group from selected files\n" diff --git a/daemon/queue/DownloadInfo.h b/daemon/queue/DownloadInfo.h index a0493f17..3f1817dc 100644 --- a/daemon/queue/DownloadInfo.h +++ b/daemon/queue/DownloadInfo.h @@ -802,6 +802,7 @@ public: eaGroupPauseExtraPars, // pause only (almost all) pars in group, except main par-file (does not affect other files) eaGroupSetPriority, // set priority for groups eaGroupSetCategory, // set or change category for a group + eaGroupApplyCategory, // set or change category for a group and reassign pp-params according to category settings eaGroupMerge, // merge groups eaGroupSetParameter, // set post-process parameter for group eaGroupSetName, // set group name (rename group) diff --git a/daemon/queue/QueueEditor.cpp b/daemon/queue/QueueEditor.cpp index fff801a6..5eefee7c 100644 --- a/daemon/queue/QueueEditor.cpp +++ b/daemon/queue/QueueEditor.cpp @@ -289,7 +289,8 @@ bool QueueEditor::InternEditList(ItemList* pItemList, break; case DownloadQueue::eaGroupSetCategory: - SetNZBCategory(pItem->m_pNZBInfo, szText); + case DownloadQueue::eaGroupApplyCategory: + SetNZBCategory(pItem->m_pNZBInfo, szText, eAction == DownloadQueue::eaGroupApplyCategory); break; case DownloadQueue::eaGroupSetName: @@ -796,11 +797,94 @@ void QueueEditor::SetNZBPriority(NZBInfo* pNZBInfo, const char* szPriority) pNZBInfo->SetPriority(iPriority); } -void QueueEditor::SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory) +void QueueEditor::SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory, bool bApplyParams) { debug("QueueEditor: setting category '%s' for '%s'", szCategory, pNZBInfo->GetName()); + bool bOldUnpack = g_pOptions->GetUnpack(); + const char* szOldPostScript = g_pOptions->GetPostScript(); + if (bApplyParams && !Util::EmptyStr(pNZBInfo->GetCategory())) + { + Options::Category* pCategory = g_pOptions->FindCategory(pNZBInfo->GetCategory(), false); + if (pCategory) + { + bOldUnpack = pCategory->GetUnpack(); + if (!Util::EmptyStr(pCategory->GetPostScript())) + { + szOldPostScript = pCategory->GetPostScript(); + } + } + } + g_pQueueCoordinator->SetQueueEntryCategory(m_pDownloadQueue, pNZBInfo, szCategory); + + if (!bApplyParams) + { + return; + } + + bool bNewUnpack = g_pOptions->GetUnpack(); + const char* szNewPostScript = g_pOptions->GetPostScript(); + if (!Util::EmptyStr(pNZBInfo->GetCategory())) + { + Options::Category* pCategory = g_pOptions->FindCategory(pNZBInfo->GetCategory(), false); + if (pCategory) + { + bNewUnpack = pCategory->GetUnpack(); + if (!Util::EmptyStr(pCategory->GetPostScript())) + { + szNewPostScript = pCategory->GetPostScript(); + } + } + } + + if (bOldUnpack != bNewUnpack) + { + pNZBInfo->GetParameters()->SetParameter("*Unpack:", bNewUnpack ? "yes" : "no"); + } + + if (strcasecmp(szOldPostScript, szNewPostScript)) + { + // add new params not existed in old category + Tokenizer tokNew(szNewPostScript, ",;"); + while (const char* szNewScriptName = tokNew.Next()) + { + bool bFound = false; + const char* szOldScriptName; + Tokenizer tokOld(szOldPostScript, ",;"); + while ((szOldScriptName = tokOld.Next()) && !bFound) + { + bFound = !strcasecmp(szNewScriptName, szOldScriptName); + } + if (!bFound) + { + char szParam[1024]; + snprintf(szParam, 1024, "%s:", szNewScriptName); + szParam[1024-1] = '\0'; + pNZBInfo->GetParameters()->SetParameter(szParam, "yes"); + } + } + + // remove old params not existed in new category + Tokenizer tokOld(szOldPostScript, ",;"); + while (const char* szOldScriptName = tokOld.Next()) + { + bool bFound = false; + const char* szNewScriptName; + Tokenizer tokNew(szNewPostScript, ",;"); + while ((szNewScriptName = tokNew.Next()) && !bFound) + { + bFound = !strcasecmp(szNewScriptName, szOldScriptName); + } + if (!bFound) + { + char szParam[1024]; + snprintf(szParam, 1024, "%s:", szOldScriptName); + szParam[1024-1] = '\0'; + pNZBInfo->GetParameters()->SetParameter(szParam, "no"); + } + } + } } void QueueEditor::SetNZBName(NZBInfo* pNZBInfo, const char* szName) diff --git a/daemon/queue/QueueEditor.h b/daemon/queue/QueueEditor.h index f306f0d5..29870186 100644 --- a/daemon/queue/QueueEditor.h +++ b/daemon/queue/QueueEditor.h @@ -56,7 +56,7 @@ private: void PauseParsInGroups(ItemList* pItemList, bool bExtraParsOnly); void PausePars(FileList* pFileList, bool bExtraParsOnly); void SetNZBPriority(NZBInfo* pNZBInfo, const char* szPriority); - void SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory); + void SetNZBCategory(NZBInfo* pNZBInfo, const char* szCategory, bool bApplyParams); void SetNZBName(NZBInfo* pNZBInfo, const char* szName); bool CanCleanupDisk(NZBInfo* pNZBInfo); bool MergeGroups(ItemList* pItemList); diff --git a/daemon/remote/MessageBase.h b/daemon/remote/MessageBase.h index 3577d39b..2a0ab030 100644 --- a/daemon/remote/MessageBase.h +++ b/daemon/remote/MessageBase.h @@ -27,7 +27,7 @@ #ifndef MESSAGEBASE_H #define MESSAGEBASE_H -static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6223; // = "nzb-XX" (protocol version) +static const int32_t NZBMESSAGE_SIGNATURE = 0x6E7A6224; // = "nzb-XX" (protocol version) static const int NZBREQUESTFILENAMESIZE = 512; static const int NZBREQUESTPASSWORDSIZE = 32; diff --git a/daemon/remote/XmlRpc.cpp b/daemon/remote/XmlRpc.cpp index 98b291ab..53e1ecd9 100644 --- a/daemon/remote/XmlRpc.cpp +++ b/daemon/remote/XmlRpc.cpp @@ -2040,6 +2040,7 @@ EditCommandEntry EditCommandNameMap[] = { { DownloadQueue::eaGroupPauseExtraPars, "GroupPauseExtraPars" }, { DownloadQueue::eaGroupSetPriority, "GroupSetPriority" }, { DownloadQueue::eaGroupSetCategory, "GroupSetCategory" }, + { DownloadQueue::eaGroupApplyCategory, "GroupApplyCategory" }, { DownloadQueue::eaGroupMerge, "GroupMerge" }, { DownloadQueue::eaGroupSetParameter, "GroupSetParameter" }, { DownloadQueue::eaGroupSetName, "GroupSetName" }, diff --git a/webui/config.js b/webui/config.js index d6b601c7..df02ce51 100644 --- a/webui/config.js +++ b/webui/config.js @@ -1102,10 +1102,16 @@ var Config = (new function($) function switchGetValue(control) { - var state = $('.btn-primary', $(control).parent()).val(); + var state = $('.btn-primary', control).val(); return state; } + function switchSetValue(control, value) + { + $('.btn', control).removeClass('btn-primary'); + $('.btn@[value=' + value + ']', control).addClass('btn-primary'); + } + /*** CHANGE/ADD/REMOVE OPTIONS *************************************************************/ function navClick(event) @@ -1421,6 +1427,20 @@ var Config = (new function($) } this.getOptionValue = getOptionValue; + function setOptionValue(option, value) + { + var control = $('#' + option.formId); + if (option.type === 'switch') + { + switchSetValue(control, value); + } + else + { + control.val(value); + } + } + this.setOptionValue = setOptionValue; + // Checks if there are obsolete or invalid options function invalidOptionsExist() { @@ -1878,7 +1898,7 @@ var ScriptListDialog = (new function($) Util.show('#ScriptListDialog_OrderInfo', orderMode, 'inline-block'); buildScriptList(); - var selectedList = parseCommaList(Config.getOptionValue(option)); + var selectedList = Util.parseCommaList(Config.getOptionValue(option)); updateTable(selectedList); $ScriptListDialog.modal({backdrop: 'static'}); @@ -1910,24 +1930,9 @@ var ScriptListDialog = (new function($) $ScriptTable.fasttable('update', data); } - function parseCommaList(commaList) - { - var valueList = commaList.split(/[,;]+/); - for (var i=0; i < valueList.length; i++) - { - valueList[i] = valueList[i].trim(); - if (valueList[i] === '') - { - valueList.splice(i, 1); - i--; - } - } - return valueList; - } - function buildScriptList() { - var orderList = parseCommaList(Config.getOptionValue(Config.findOptionByName('ScriptOrder'))); + var orderList = Util.parseCommaList(Config.getOptionValue(Config.findOptionByName('ScriptOrder'))); var availableScripts = []; var availableAllScripts = []; diff --git a/webui/edit.js b/webui/edit.js index 0495b105..7ef26059 100644 --- a/webui/edit.js +++ b/webui/edit.js @@ -54,6 +54,7 @@ var DownloadsEditDialog = (new function($) var files; var refreshTimer = 0; var showing; + var oldCategory; this.init = function() { @@ -67,6 +68,7 @@ var DownloadsEditDialog = (new function($) $('#DownloadsEdit_CancelPP').click(itemCancelPP); $('#DownloadsEdit_Param, #DownloadsEdit_Log, #DownloadsEdit_File, #DownloadsEdit_Dupe').click(tabClick); $('#DownloadsEdit_Back').click(backClick); + $('#DownloadsEdit_Category').change(categoryChange); $DownloadsLogTable = $('#DownloadsEdit_LogTable'); $DownloadsLogTable.fasttable( @@ -206,7 +208,7 @@ var DownloadsEditDialog = (new function($) v.attr('disabled', 'disabled'); // Category - var v = $('#DownloadsEdit_Category'); + v = $('#DownloadsEdit_Category'); DownloadsUI.fillCategoryCombo(v); v.val(group.Category); if (v.val() != group.Category) @@ -291,6 +293,7 @@ var DownloadsEditDialog = (new function($) files = null; logFilled = false; notification = null; + oldCategory = curGroup.Category; if (area === 'backup') { @@ -506,6 +509,13 @@ var DownloadsEditDialog = (new function($) } } + function categoryChange() + { + var category = $('#DownloadsEdit_Category').val(); + ParamTab.reassignParams(postParams, oldCategory, category); + oldCategory = category; + } + /*** TAB: POST-PROCESSING PARAMETERS **************************************************/ function saveParam() @@ -1088,6 +1098,65 @@ var ParamTab = (new function($) } return request; } + + function buildCategoryScriptList(category) + { + var scriptList = []; + + for (var i=0; i < Options.categories.length; i++) + { + if (category === Options.categories[i]) + { + scriptList = Util.parseCommaList(Options.option('Category' + (i + 1) + '.PostScript')); + if (scriptList.length === 0) + { + scriptList = Util.parseCommaList(Options.option('PostScript')); + } + if (Options.option('Category' + (i + 1) + '.Unpack') === 'yes') + { + scriptList.push('*Unpack'); + } + return scriptList; + } + } + + // empty category or category not found + scriptList = Util.parseCommaList(Options.option('PostScript')); + if (Options.option('Unpack') === 'yes') + { + scriptList.push('*Unpack'); + } + return scriptList; + } + + this.reassignParams = function(postParams, oldCategory, newCategory) + { + var oldScriptList = buildCategoryScriptList(oldCategory); + var newScriptList = buildCategoryScriptList(newCategory); + + for (var i=0; i < postParams.length; i++) + { + var section = postParams[i]; + for (var j=0; j < section.options.length; j++) + { + var option = section.options[j]; + if (!option.template && !section.hidden && option.name.substr(option.name.length - 1, 1) === ':') + { + console.log(option.name); + var scriptName = option.name.substr(0, option.name.length-1); + if (oldScriptList.indexOf(scriptName) > -1 && newScriptList.indexOf(scriptName) === -1) + { + Config.setOptionValue(option, 'no'); + } + else if (oldScriptList.indexOf(scriptName) === -1 && newScriptList.indexOf(scriptName) > -1) + { + Config.setOptionValue(option, 'yes'); + } + } + } + } + } + }(jQuery)); @@ -1269,7 +1338,7 @@ var DownloadsMultiDialog = (new function($) { var category = $('#DownloadsMulti_Category').val(); (category !== oldCategory && category !== '') ? - RPC.call('editqueue', ['GroupSetCategory', 0, category, multiIDList], function() + RPC.call('editqueue', ['GroupApplyCategory', 0, category, multiIDList], function() { notification = '#Notif_Downloads_Saved'; completed(); diff --git a/webui/util.js b/webui/util.js index 459195db..d9d2d115 100644 --- a/webui/util.js +++ b/webui/util.js @@ -270,7 +270,22 @@ var Util = (new function($) $elem.css({ top: '' }); } } - + + this.parseCommaList = function(commaList) + { + var valueList = commaList.split(/[,;]+/); + for (var i=0; i < valueList.length; i++) + { + valueList[i] = valueList[i].trim(); + if (valueList[i] === '') + { + valueList.splice(i, 1); + i--; + } + } + return valueList; + } + }(jQuery));