From a5245694c3a3d7291c6c799541d37d9a878d0b62 Mon Sep 17 00:00:00 2001 From: John Andrews Date: Thu, 1 Aug 2024 12:20:09 +1200 Subject: [PATCH] FF-1646: Added support for sh/bat/ps1 scripts --- BasicNodes/Scripting/BatScript.cs | 126 ++ .../{Functions => Scripting}/Function.cs | 12 +- BasicNodes/Scripting/PowerShellScript.cs | 127 ++ BasicNodes/Scripting/ShScript.cs | 127 ++ BasicNodes/i18n/en.json | 1183 +++++++++-------- FileFlows.Plugin.dll | Bin 147968 -> 147968 bytes FileFlows.Plugin.pdb | Bin 36780 -> 36808 bytes 7 files changed, 997 insertions(+), 578 deletions(-) create mode 100644 BasicNodes/Scripting/BatScript.cs rename BasicNodes/{Functions => Scripting}/Function.cs (83%) create mode 100644 BasicNodes/Scripting/PowerShellScript.cs create mode 100644 BasicNodes/Scripting/ShScript.cs diff --git a/BasicNodes/Scripting/BatScript.cs b/BasicNodes/Scripting/BatScript.cs new file mode 100644 index 00000000..7a5de4fe --- /dev/null +++ b/BasicNodes/Scripting/BatScript.cs @@ -0,0 +1,126 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using FileFlows.Plugin; +using FileFlows.Plugin.Attributes; + +namespace FileFlows.BasicNodes.Scripting; + +/// +/// Flow element that executes a bat script +/// +public class BatScript : Node +{ + /// + public override int Inputs => 1; + /// + public override int Outputs => 2; + /// + public override FlowElementType Type => FlowElementType.Process; + /// + public override string Icon => "svg:bat"; + /// + public override bool FailureNode => true; + /// + public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/bat-script"; + + /// + /// Gets or sets the code to execute + /// + [Required] + [DefaultValue(@"REM This is a template batch file + +REM Replace {file.FullName} and {file.Orig.FullName} with actual values +SET WorkingFile={file.FullName} +SET OriginalFile={file.Orig.FullName} + +REM Example commands using the variables +echo Working on file: %WorkingFile% +echo Original file location: %OriginalFile% + +REM Add your actual batch commands below +REM Example: Copy the working file to a backup location +REM copy ""%WorkingFile%"" ""C:\Backup\%~nxWorkingFile%"" + +REM Set the exit code to 0 +EXIT /B 0 +")] + [Code(1, "bat")] + public string Code { get; set; } + + /// + public override int Execute(NodeParameters args) + { + if (string.IsNullOrEmpty(Code)) + { + args.FailureReason = "No code specified in .bat script"; + args.Logger?.ELog(args.FailureReason); + return -1; // no code, flow cannot continue doesn't know what to do + } + + if (OperatingSystem.IsWindows() == false) + { + args.FailureReason = "Cannot run a .bat file on a non Windows system"; + args.Logger?.ELog(args.FailureReason); + return -1; + } + + var batFile = System.IO.Path.Combine(args.TempPath, Guid.NewGuid() + ".bat"); + + try + { + var code = "@echo off" + Environment.NewLine + args.ReplaceVariables(Code); + args.Logger?.ILog("Executing code: \n" + code); + System.IO.File.WriteAllText(batFile, code); + args.Logger?.ILog($"Temporary bat file created: {batFile}"); + + var processStartInfo = new ProcessStartInfo + { + FileName = batFile, + WorkingDirectory = args.TempPath, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using var process = new Process { StartInfo = processStartInfo }; + process.Start(); + + string standardOutput = process.StandardOutput.ReadToEnd(); + string standardError = process.StandardError.ReadToEnd(); + + process.WaitForExit(); + int exitCode = process.ExitCode; + + if(string.IsNullOrWhiteSpace(standardOutput) == false) + args.Logger?.ILog($"Standard Output:\n{standardOutput}"); + if(string.IsNullOrWhiteSpace(standardError) == false) + args.Logger?.WLog($"Standard Error:\n{standardError}"); + args.Logger?.ILog($"Exit Code: {exitCode}"); + + return exitCode == 0 ? 1 : 2; + } + catch (Exception ex) + { + args.FailureReason = "Failed executing bat script: " + ex.Message; + args.Logger?.ELog(args.FailureReason); + return -1; + } + finally + { + try + { + if (System.IO.File.Exists(batFile)) + { + System.IO.File.Delete(batFile); + args.Logger?.ILog($"Temporary bat file deleted: {batFile}"); + } + } + catch (Exception ex) + { + args.Logger?.WLog($"Failed to delete temporary bat file: {batFile}. Error: {ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/BasicNodes/Functions/Function.cs b/BasicNodes/Scripting/Function.cs similarity index 83% rename from BasicNodes/Functions/Function.cs rename to BasicNodes/Scripting/Function.cs index d0d1921c..06af7475 100644 --- a/BasicNodes/Functions/Function.cs +++ b/BasicNodes/Scripting/Function.cs @@ -19,7 +19,9 @@ public class Function : Node /// public override bool FailureNode => true; /// - public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/function"; + public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/function"; + /// + public override string Group => "Scripting"; /// /// Gets or sets the number of outputs @@ -40,11 +42,14 @@ public class Function : Node public override int Execute(NodeParameters args) { if (string.IsNullOrEmpty(Code)) - return -1; // no code, flow cannot continue doesnt know what to do + { + args.FailureReason = "No code specified in Function script"; + args.Logger?.ELog(args.FailureReason); + return -1; // no code, flow cannot continue doesn't know what to do + } try { - return args.ScriptExecutor.Execute(new FileFlows.Plugin.Models.ScriptExecutionArgs { Args = args, @@ -53,6 +58,7 @@ public class Function : Node } catch (Exception ex) { + args.FailureReason = "Failed executing function: " + ex.Message; args.Logger?.ELog("Failed executing function: " + ex.Message + Environment.NewLine + ex.StackTrace); return -1; } diff --git a/BasicNodes/Scripting/PowerShellScript.cs b/BasicNodes/Scripting/PowerShellScript.cs new file mode 100644 index 00000000..4de6724e --- /dev/null +++ b/BasicNodes/Scripting/PowerShellScript.cs @@ -0,0 +1,127 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using FileFlows.Plugin; +using FileFlows.Plugin.Attributes; + +namespace FileFlows.BasicNodes.Scripting; + +/// +/// Flow element that executes a PowerShell script +/// +public class PowerShellScript : Node +{ + /// + public override int Inputs => 1; + /// + public override int Outputs => 2; + /// + public override FlowElementType Type => FlowElementType.Process; + /// + public override string Icon => "svg:ps1"; + /// + public override bool FailureNode => true; + /// + public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/powershell-script"; + + /// + /// Gets or sets the code to execute + /// + [Required] + [DefaultValue(@"# This is a template PowerShell script + +# Replace {file.FullName} and {file.Orig.FullName} with actual values +$WorkingFile = '{file.FullName}' +$OriginalFile = '{file.Orig.FullName}' + +# Example commands using the variables +Write-Output ""Working on file: $WorkingFile"" +Write-Output ""Original file location: $OriginalFile"" + +# Add your actual PowerShell commands below +# Example: Copy the working file to a backup location +# Copy-Item -Path $WorkingFile -Destination ""C:\Backup\$([System.IO.Path]::GetFileName($WorkingFile))"" + +# Set the exit code to 0 +exit 0 +")] + [Code(1, "powershell")] + public string Code { get; set; } + + /// + public override int Execute(NodeParameters args) + { + if (string.IsNullOrEmpty(Code)) + { + args.FailureReason = "No code specified in PowerShell script"; + args.Logger?.ELog(args.FailureReason); + return -1; // no code, flow cannot continue doesn't know what to do + } + + if (OperatingSystem.IsWindows() == false) + { + args.FailureReason = "Cannot run a PowerShell file on a non Windows system"; + args.Logger?.ELog(args.FailureReason); + return -1; + } + + var ps1File = System.IO.Path.Combine(args.TempPath, Guid.NewGuid() + ".ps1"); + + try + { + var code = args.ReplaceVariables(Code); + args.Logger?.ILog("Executing code: \n" + code); + System.IO.File.WriteAllText(ps1File, code); + args.Logger?.ILog($"Temporary PowerShell file created: {ps1File}"); + + var processStartInfo = new ProcessStartInfo + { + FileName = "powershell.exe", + Arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{ps1File}\"", + WorkingDirectory = args.TempPath, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using var process = new Process { StartInfo = processStartInfo }; + process.Start(); + + string standardOutput = process.StandardOutput.ReadToEnd(); + string standardError = process.StandardError.ReadToEnd(); + + process.WaitForExit(); + int exitCode = process.ExitCode; + + if(string.IsNullOrWhiteSpace(standardOutput) == false) + args.Logger?.ILog($"Standard Output:\n{standardOutput}"); + if(string.IsNullOrWhiteSpace(standardError) == false) + args.Logger?.WLog($"Standard Error:\n{standardError}"); + args.Logger?.ILog($"Exit Code: {exitCode}"); + + return exitCode == 0 ? 1 : 2; + } + catch (Exception ex) + { + args.FailureReason = "Failed executing PowerShell script: " + ex.Message; + args.Logger?.ELog(args.FailureReason); + return -1; + } + finally + { + try + { + if (System.IO.File.Exists(ps1File)) + { + System.IO.File.Delete(ps1File); + args.Logger?.ILog($"Temporary ps1 file deleted: {ps1File}"); + } + } + catch (Exception ex) + { + args.Logger?.WLog($"Failed to delete temporary ps1 file: {ps1File}. Error: {ex.Message}"); + } + } + } +} \ No newline at end of file diff --git a/BasicNodes/Scripting/ShScript.cs b/BasicNodes/Scripting/ShScript.cs new file mode 100644 index 00000000..8d67f786 --- /dev/null +++ b/BasicNodes/Scripting/ShScript.cs @@ -0,0 +1,127 @@ +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Diagnostics; +using FileFlows.Plugin; +using FileFlows.Plugin.Attributes; + +namespace FileFlows.BasicNodes.Scripting; + +/// +/// Flow element that executes a SH script +/// +public class ShScript : Node +{ + /// + public override int Inputs => 1; + /// + public override int Outputs => 2; + /// + public override FlowElementType Type => FlowElementType.Process; + /// + public override string Icon => "svg:sh"; + /// + public override bool FailureNode => true; + /// + public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/sh-script"; + + /// + /// Gets or sets the code to execute + /// + [Required] + [DefaultValue(@"# This is a template shell script + +# Replace {file.FullName} and {file.Orig.FullName} with actual values +WorkingFile=""{file.FullName}"" +OriginalFile=""{file.Orig.FullName}"" + +# Example commands using the variables +echo ""Working on file: $WorkingFile"" +echo ""Original file location: $OriginalFile"" + +# Add your actual shell commands below +# Example: Copy the working file to a backup location +# cp ""$WorkingFile"" ""/path/to/backup/$(basename \""$WorkingFile\"")"" + +# Set the exit code to 0 +exit 0 +")] + [Code(1, "sh")] + public string Code { get; set; } + + /// + public override int Execute(NodeParameters args) + { + if (string.IsNullOrEmpty(Code)) + { + args.FailureReason = "No code specified in SH script"; + args.Logger?.ELog(args.FailureReason); + return -1; // no code, flow cannot continue doesn't know what to do + } + + if (OperatingSystem.IsWindows()) + { + args.FailureReason = "Cannot run a SH script on a Windows system"; + args.Logger?.ELog(args.FailureReason); + return -1; + } + + var shFile = System.IO.Path.Combine(args.TempPath, Guid.NewGuid() + ".sh"); + + try + { + var code = args.ReplaceVariables(Code); + args.Logger?.ILog("Executing code: \n" + code); + System.IO.File.WriteAllText(shFile, code); + args.Logger?.ILog($"Temporary SH file created: {shFile}"); + + var processStartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"\"{shFile}\"", + WorkingDirectory = args.TempPath, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + using var process = new Process { StartInfo = processStartInfo }; + process.Start(); + + string standardOutput = process.StandardOutput.ReadToEnd(); + string standardError = process.StandardError.ReadToEnd(); + + process.WaitForExit(); + int exitCode = process.ExitCode; + + if (!string.IsNullOrWhiteSpace(standardOutput)) + args.Logger?.ILog($"Standard Output:\n{standardOutput}"); + if (!string.IsNullOrWhiteSpace(standardError)) + args.Logger?.WLog($"Standard Error:\n{standardError}"); + args.Logger?.ILog($"Exit Code: {exitCode}"); + + return exitCode == 0 ? 1 : 2; + } + catch (Exception ex) + { + args.FailureReason = "Failed executing SH script: " + ex.Message; + args.Logger?.ELog(args.FailureReason); + return -1; + } + finally + { + try + { + if (System.IO.File.Exists(shFile)) + { + System.IO.File.Delete(shFile); + args.Logger?.ILog($"Temporary SH file deleted: {shFile}"); + } + } + catch (Exception ex) + { + args.Logger?.WLog($"Failed to delete temporary SH file: {shFile}. Error: {ex.Message}"); + } + } + } +} diff --git a/BasicNodes/i18n/en.json b/BasicNodes/i18n/en.json index 8a55a3b3..7c4241f4 100644 --- a/BasicNodes/i18n/en.json +++ b/BasicNodes/i18n/en.json @@ -1,584 +1,617 @@ { - "Enums":{ - "LogType":{ - "Info":"Information", - "Debug":"Debug", - "Warning":"Warning", - "Error":"Error" + "Enums": { + "LogType": { + "Info": "Information", + "Debug": "Debug", + "Warning": "Warning", + "Error": "Error" + } + }, + "Flow": { + "Parts": { + "InputFile": { + "Description": "An input flow element for a file. This is required and is the starting point of a flow. Any input flow element can be used, just one is required.", + "Outputs": { + "1": "Library File" } - }, - "Flow":{ - "Parts": { - "InputFile": { - "Description": "An input flow element for a file. This is required and is the starting point of a flow. Any input flow element can be used, just one is required.", - "Outputs": { - "1": "Library File" - } + }, + "InputFolder": { + "Description": "An input flow element for a folder. This will only work if the library using this flow is configured for folders.", + "Outputs": { + "1": "Library Folder" + } + }, + "BatScript": { + "Label": "BAT Script", + "Description": "Allows you to execute a batch (.bat) script in a Windows environment.", + "Outputs": { + "1": "Success - The batch script executed successfully with an exit code of 0.", + "2": "Failure - The batch script execution failed or returned a non-zero exit code." }, - "InputFolder": { - "Description": "An input flow element for a folder. This will only work if the library using this flow is configured for folders.", - "Outputs": { - "1": "Library Folder" - } + "Fields": { + "Code": "Code" + } + }, + "ShScript": { + "Label": "SH Script", + "Description": "Allows you to execute a shell (.sh) script in a Unix-like environment.", + "Outputs": { + "1": "Success - The shell script executed successfully with an exit code of 0.", + "2": "Failure - The shell script execution failed or returned a non-zero exit code." }, - "CopyFile": { - "Description": "Copies a file to the destination folder", - "Outputs": { - "1": "File copied" - }, - "Fields": { - "InputFile": "File To Copy", - "InputFile-Help": "The file to copy, if left empty then the working file will be copied", - "InputFile-Placeholder": "Working File", - "DestinationPath": "Destination Folder", - "DestinationPath-Help": "The folder where the file will be copied to", - "DestinationFile": "Destination File", - "DestinationFile-Help": "The filename to copy the file to. If empty, the original filename will be used", - "CopyFolder": "Copy Folder", - "CopyFolder-Help": "If the relative library folder structure should be copied too", - "AdditionalFiles": "Additional Files", - "AdditionalFiles-Help": "Additional files to copy from the directory to the new directory.\nEach value can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn''t support regular expressions.", - "AdditionalFilesFromOriginal": "Original Directory", - "AdditionalFilesFromOriginal-Help": "If the additional files should be copied from the working directory or from the original directory. Turn on for original directory.", - "PreserverOriginalDates": "Preserve Dates", - "PreserverOriginalDates-Help": "If the original creation time and last write time of the original input file should be preserved." - } + "Fields": { + "Code": "Code" + } + }, + "PowerShellScript": { + "Label": "PowerShell Script", + "Description": "Allows you to execute a PowerShell (.ps1) script in a Windows environment.", + "Outputs": { + "1": "Success - The PowerShell script executed successfully with an exit code of 0.", + "2": "Failure - The PowerShell script execution failed or returned a non-zero exit code." }, - "DeleteSourceDirectory": { - "Label": "Delete Source Folder", - "Outputs": { - "1": "Source directory deleted", - "2": "Directory was NOT deleted" - }, - "Description": "Deletes the source folder of the original library file", - "Fields": { - "IfEmpty": "If Empty", - "IfEmpty-Help": "Only delete the source folder if the it is empty", - "IncludePatterns": "Include Patterns", - "IncludePatterns-Help": "Optional, if set only files matching these patterns will be counted to see if the folder is empty. Any of these patterns can match." - } - }, - "Executor": { - "Description": "Execute the following process against the file.\nOutput 1: The process returned the success exit code\nOutput 2: The process return a non-successful exit code.", - "Outputs": { - "1": "Process returned success", - "2": "Process returned failure" - }, - "Fields": { - "FileName": "File Name", - "FileName-Help": "The name of the file to execute", - "Arguments": "Arguments", - "Arguments-Help": "The arguments to be passed to the process to execute", - "WorkingDirectory": "Working Folder", - "WorkingDirectory-Help": "The folder where the process will be executed from", - "SuccessCode": "Success Code", - "SuccessCode-Help": "The exit code of the process indicating the process was successful. Usually this should be 0.", - "Timeout": "Timeout", - "Timeout-Help": "How long the process can run for before being terminated. Use 0 for no timeout.", - "Timeout-Suffix": "seconds", - "OutputVariable": "Output Variable", - "OutputVariable-Help": "An optional variable name to store the process output into", - "OutputErrorVariable": "Output Error Variable", - "OutputErrorVariable-Help": "An optional variable name to store the process error output into" - } - }, - "DirectoryDateCompare": { - "Description": "Checks if the directory creation or last write time matches the specified date constraint.", - "Outputs": { - "1": "Matches the date constraint.", - "2": "Does not match the date constraint." - }, - "Fields": { - "Path": "Path", - "Path-Help": "The path to the folder to check. Leave empty to check the current working file.\nIf a file is specified the directory containing the file will be checked.", - "Date": "Date", - "DateComparision": "Comparision" - } - }, - "FileDateCompare": { - "Description": "Checks if the file creation or last write time matches the specified date constraint.", - "Outputs": { - "1": "Matches the date constraint.", - "2": "Does not match the date constraint." - }, - "Fields": { - "FileName": "File Name", - "FileName-Help": "The file to check. Leave empty to check the current working file.", - "Date": "Date", - "DateComparision": "Comparision" - } - }, - "FileExtension": { - "Description": "Checks if the file has one of the configured extensions.\n\nOutput 1: Matches\nOutput 2: Does not match", - "Outputs": { - "1": "Extension match", - "2": "Extension did not match" - }, - "Fields": { - "Extensions": "Extensions", - "Extensions-Help": "A list of case insensitive file extensions that will be matched against.\nOutput 1 Matches\nOutput 2: Does not match" - } - }, - "FileExists": { - "Description": "Checks if a file exists\n\nOutput 1: File exists\nOutput 2: File does not exist", - "Outputs": { - "1": "File exists", - "2": "File does not exist" - }, - "Fields": { - "FileName": "File Name", - "FileName-Help": "The file to check. Leave empty to check the current working file." - } - }, - "HasHardLinks": { - "Description": "Checks if a file has hard links to it or not", - "Outputs": { - "1": "Hard links detected", - "2": "No hard links detected" - }, - "Fields": { - "FileName": "File Name", - "FileName-Help": "The file to check. Leave empty to check the current working file.", - "Count": "Count", - "Count-Help": "The number of hard links required to call output 1." - } - }, - "Delete": { - "Description": "Deletes a file or folder", - "Outputs": { - "1": "File deleted" - }, - "Fields": { - "FileName": "Path", - "FileName-Help": "A path to either a file or folder to delete.\n\nIf left blank the current working file will be deleted." - } - }, - "DirectoryIterator": { - "Description": "Iterates all files in a given directory and executes those files against a sub flow.", - "Outputs": { - "1": "Directory files iterated" - }, - "Fields": { - "Flow": "Flow", - "Flow-Help": "The sub flow to execute the files against.", - "Directory": "Directory", - "Directory-Help": "The directory whose files will be iterated.", - "Pattern": "Pattern", - "Pattern-Help": "Any optional pattern to limit the files for iteration, this can be a wildcard pattern starting with a `*` or a regular expression.", - "Recursive": "Recursive", - "Recursive-Help": "If files in all sub directories should also be iterated, or if only the top level files should be iterated." - } - }, - "FailFlow": { - "Description": "Fails a flow immediately, useful if you want a certain path to just fail.", - "Fields": { - "Reason": "Reason", - "Reason-Help": "An optional reason to record why the flow failed." - } - }, - "FileSize": { - "Description": "Checks if the file size matches the configured parameters. The values are in megabytes.\n\nOutput 1: Matches\nOutput 2: Does not match", - "Outputs": { - "1": "File size within range", - "2": "File size not within range" - }, - "Fields": { - "Comparison": "Comparison", - "Lower": "Greater Than", - "Lower-Suffix": "MB", - "Lower-Help": "The value it must be greater than this number of megabytes", - "Upper": "Less Than", - "Upper-Suffix": "MB", - "Upper-Help": "The value it must be less than than this number of megabytes. Leave as 0 to not test the upper limit." - } - }, - "FileSizeCompare": { - "Description": "Checks if the file size has changed sized from the original file.", - "Outputs": { - "1": "Smaller than original", - "2": "Same size as original", - "3": "Larger than original" - } - }, - "FileSizeWithin": { - "Description": "Checks if the new file size is within the allowed range of the original file size.", - "Value": "Value", - "Value-Help": "The difference allowed for the file size, this value can be either plus or minus this difference.", - "Outputs": { - "1": "File size is within allowed range", - "2": "File size is not within allowed range" - } - }, - "Function": { - "Outputs": { - "1": "returned 1", - "2": "returned 2", - "3": "returned 3", - "4": "returned 4", - "5": "returned 5", - "6": "returned 6", - "7": "returned 7", - "8": "returned 8", - "9": "returned 9", - "10": "returned 10" - }, - "Fields": { - "Outputs": "Outputs", - "Template": "Template", - "Template-Help": "WARNING: This will replace whatever is in the code block with the template you select.", - "Code": "Code", - "Code-Help": "return -1 for error and flow to stop. return 0 for flow to complete. return 1 or more for the desired output to be called" - } - }, - "GotoFlow": { - "Description": "This lets you switch to a different flow to process. This flow will exit and the parameters and working file will be passed into the new Flow", - "Fields": { - "Flow": "Flow", - "UpdateFlowUsed": "Update Flow", - "UpdateFlowUsed-Help": "If the files `Flow` should be updated to reference this new Flow or leave it as the original Flow." - } - }, - "Reprocess": { - "Description": "The flow element allows you to reprocess the original library file with a different processing node.\n\n If the same processing node is selected as the one currently processing the file, the flow will fail.", - "Fields": { - "Node": "Node", - "Node-Help": "The processing node to process this file." - } - }, - "IsProcessingOnNode": { - "Description": "Checks if the flow is currently processing on a specified processing node.", - "Fields": { - "Node": "Node", - "Node-Help": "The processing node to check." - }, - "Outputs": { - "1": "Is processing on node", - "2": "Is not processing on node" - } - }, - "IsDocker": { - "Description": "Determines if this flow is running on Docker", - "Outputs": { - "1": "Is running on Docker", - "2": "Is not running on Docker" - } - }, - "IsLinux": { - "Description": "Determines if this flow is running on Linux", - "Outputs": { - "1": "Is running on Linux", - "2": "Is not running on Linux" - } - }, - "IsMacOS": { - "Label": "Is MacOS", - "Description": "Determines if this flow is running on MacOS", - "Outputs": { - "1": "Is running on MacOS", - "2": "Is not running on MacOS" - } - }, - "IsWindows": { - "Description": "Determines if this flow is running on Windows", - "Outputs": { - "1": "Is running on Windows", - "2": "Is not running on Windows" - } - }, - "Log": { - "Description": "Logs a message to the flow log", - "Outputs": { - "1": "Message logged" - }, - "Fields": { - "LogType": "Type", - "Message": "Message" - } - }, - "Matches": { - "Description": "Compares a set of values and matches conditions to see which output should be called", - "Fields": { - "MatchConditions": "", - "MatchConditionsKey": "Value", - "MatchConditionsValue": "Expression", - "MatchConditions-Help": "The matches to test which output should be called." - } - }, - "MoveFile": { - "Description": "Moves a file to the destination folder", - "Outputs": { - "1": "File moved", - "2": "File moved, however original file could not be deleted" - }, - "Fields": { - "InputFile": "File To Move", - "InputFile-Help": "The file to move, if left empty then the working file will be moved", - "InputFile-Placeholder": "Working File", - "DestinationPath": "Destination Folder", - "DestinationPath-Help": "The folder where the file will be moved to", - "DestinationFile": "Destination File", - "DestinationFile-Help": "The filename to move the file to. If empty, the original filename will be used", - "MoveFolder": "Copy Folder", - "MoveFolder-Help": "If the relative library folder structure should be copied too", - "DeleteOriginal": "Delete Original", - "DeleteOriginal-Help": "If the original file should be deleted, this will only happen if the working file is different to the original file", - "AdditionalFiles": "Additional Files", - "AdditionalFiles-Help": "Additional files to move from the directory to the new directory.\nEach value can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn''t support regular expressions.", - "AdditionalFilesFromOriginal": "Original Directory", - "AdditionalFilesFromOriginal-Help": "If the additional files should be moved from the working directory or from the original directory. Turn on for original directory.", - "PreserverOriginalDates": "Preserve Dates", - "PreserverOriginalDates-Help": "If the original creation time and last write time of the original input file should be preserved." - } - }, - "OlderThan": { - "Description": "Checks if a folder is older than the range specified", - "Outputs": { - "1": "File is older", - "2": "File is not older" - }, - "Fields": { - "Number": "Number", - "Unit": "Unit", - "Date": "Date" - } - }, - "OriginalFile": { - "Description": "Sets the current working file in the flow to the original file that started the flow", - "Outputs": { - "1": "Working file set to original file" - } - }, - "PatternMatch": { - "Description": "Tests the working file and original file against a regular expression.\n\nOutput 1: Matches expression\nOutput 2: Does not match", - "Outputs": { - "1": "Matches expression", - "2": "Does NOT match" - }, - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression, using the C# specification for regular expressions." - } - }, - "PatternReplacer": { - "Label": "Filename Pattern Replacer", - "Description": "Lets you make replacements in the filename. Can use regular expressions for replacements, or simple string replacements.\n\nOutput 1: Replacement done\nOutput 2: No replacement done", - "Outputs": { - "1": "Replacement done", - "2": "No replacement done" - }, - "Fields": { - "Replacements": "Replacements", - "ReplacementsKey": "Pattern", - "ReplacementsValue": "Value", - "UseWorkingFileName": "Use Working Filename", - "UseWorkingFileName-Help": "If current working filename should be used, or if false, the original filename of the incoming file will be used." - } - }, - "Random": { - "Label": "Random", - "Description": "Chooses a random output", - "Fields": { - "Outputs": "Outputs", - "Outputs-Help": "The number of outputs that could possible be called." - } - }, - "ReplaceOriginal": { - "Description": "Replaces the original file with the working file.\n\nIf the extension is different on the working file, the original file will be deleted and the working file will be moved to the original with the new extension.\nE.g. from File.avi to File.mkv", - "Outputs": { - "1": "Original file replaced" - }, - "Fields": { - "PreserverOriginalDates": "Preserve Dates", - "PreserverOriginalDates-Help": "If the original creation time and last write time of the original input file should be preserved." - } - }, - "Renamer": { - "Description": "Renames the working file.\nVariables can be used by entering the key '{' inside the Pattern field.", - "Outputs": { - "1": "File renamed" - }, - "Fields": { - "Pattern": "New Name", - "Pattern-Help": "The new name of the file. Can use variables. Any empty () and '{}' will be removed.", - "DestinationPath": "Destination Folder", - "DestinationPath-Help": "If the file should be moved to a different folder.", - "LogOnly": "Log Only", - "LogOnly-Help": "Turn on if you just want to test this flow element without it actually renaming the file", - "CsvFile": "CSV File", - "CsvFile-Help": "Will append to this file the original name and the renamed file. Useful when using ''Log Only'' to test the renamer before changing files." - } - }, - "SetVariable": { - "Label": "Set Variable", - "Description": "Sets a variable in the flow.", - "Outputs": { - "1": "Variable set" - }, - "Fields": { - "Variable": "Variable", - "Variable-Help": "The name of the variable to set", - "Value": "Value", - "Value-Help": "The value of the variable to set." - } - }, - "SetWorkingFile": { - "Label": "Set Working File", - "Description": "Updates the current working file to the one specified.", - "Outputs": { - "1": "Working File Set" - }, - "Fields": { - "File": "File", - "File-Description": "The path to the new working file or folder.", - "DontDeletePrevious": "Don't Delete Previous", - "DontDeletePrevious-Help": "If the previous *temporary* working file should *not* be deleted.\nOnly temporary files will be deleted, files that have been created by FileFlows into the runners temporary directory." - } - }, - "Sleep": { - "Description": "Pauses the flow", - "Outputs": { - "1": "Flow resumed" - }, - "Fields": { - "Milliseconds": "Milliseconds", - "Milliseconds-Help": "How long to sleep the flow for. Must be between 1 millisecond and 1 hour" - } - }, - "Touch": { - "Description": "Touches a file or directory and sets the last write time to now.", - "Outputs": { - "1": "Successfully touched item" - }, - "Fields": { - "FileName": "File Name", - "FileName-Help": "Full filename of file or folder to touch.\nIf left blank the working file will be used." - } - }, - "VariableMatch": { - "Description": "Tests if a input matches a stored Variable", - "Fields": { - "Variable": "Variable", - "Variable-Help": "The variable to match against", - "Input": "Input", - "Input-Help": "The input to match the variable against." - }, - "Outputs": { - "1": "Input matched variable", - "2": "Input did not match variable" - } - }, - "WebRequest": { - "Description": "Allows you to send a web request", - "Outputs": { - "1": "Successfully sent", - "2": "Request returned a non-successful status code" - }, - "Fields": { - "Url": "URL", - "Url-Help": "The URL of the request", - "Method": "Method", - "Method-Help": "The web method to use when sending this request", - "ContentType": "Content Type", - "ContentType-Help": "The Content-Type of the message to send", - "Headers": "Headers", - "Headers-Help": "Optional headers to send with the request", - "HeadersKey": "Key", - "HeadersValue": "Value", - "Body": "Body", - "Body-Help": "The body of the request being sent. Variables can be used in this field." - } - }, - "Unpack": { - "Description": "Allows you to unpack an archive (zip, rar, tar, etc)", - "Outputs": { - "1": "File Unpacked" - }, - "Fields": { - "DestinationPath": "Destination Folder", - "DestinationPath-Help": "The destination folder where to unpack the file.", - "File": "File", - "File-Help": "The name of the file to unpack. Can be left blank and if so the current working file will be used." - } - }, - "Zip": { - "Description": "Allows you to zip the input", - "Outputs": { - "1": "Zip created" - }, - "Fields": { - "DestinationPath": "Destination Folder", - "DestinationPath-Help": "The destination folder where to put the zip file. If blank, the zip will be placed in the library root.", - "DestinationFile": "Destination File", - "DestinationFile-Help": "The filename of the newly created zip. If blank, the name of the item will be used as the zip file.", - "Path": "Path", - "Path-Help": "The path to the file or folder to zip. If blank, the working file will be zipped.", - "SetWorkingFile": "Set Working File", - "SetWorkingFile-Help": "If the newly created zip should become the new working file." - } - }, - "SevenZip": { - "Label": "7-Zip", - "Description": "Allows you to 7zip the input", - "Outputs": { - "1": "7zip created" - }, - "Fields": { - "DestinationPath": "Destination Folder", - "DestinationPath-Help": "The destination folder where to put the 7zip file. If blank, the 7zip will be placed in the library root.", - "DestinationFile": "Destination File", - "DestinationFile-Help": "The filename of the newly created 7zip. If blank, the name of the item will be used as the 7zip file.", - "CompressionLevel": "Compression Level", - "CompressionLevel-Help": "The level of compression to use when compressing the level.", - "CompressionMethod": "Compression Method", - "CompressionMethod-Help": "The compression method used for compression, LZMA2 is recommended." - } - }, - "IfBoolean": { - "Description": "Tests if a Variable is true or false", - "Outputs": { - "1": "True", - "2": "False" - }, - "Fields": { - "Variable": "Variable", - "Variable-Help": "The name of the variable to check" - } - }, - "IfString": { - "Description": "Tests if a Variable is matches a string", - "Outputs": { - "1": "Matched string 1", - "2": "Matched string 2", - "3": "Matched string 3", - "4": "Matched string 4", - "5": "Matched string 5", - "6": "Matched string 6", - "7": "Matched string 7", - "8": "Matched string 8", - "9": "Matched string 9", - "10": "Matched string 10" - }, - "Fields": { - "Variable": "Variable", - "Variable-Help": "The name of the variable to check", - "Outputs": "Outputs", - "Outputs-Help": "This should match the number of options there are", - "Options": "Options", - "Options-Help": "The string to match against." - } - }, - "WriteText": { - "Description": "Writes text to a file", - "Outputs": { - "1": "Text written to file" - }, - "Fields": { - "File": "File", - "File-Help": "The file to write the text to.", - "Text": "Text", - "Text-Help": "The text to write to the file. If left blank the current working file full path will be written." - } + "Fields": { + "Code": "Code" } } + }, + "CopyFile": { + "Description": "Copies a file to the destination folder", + "Outputs": { + "1": "File copied" + }, + "Fields": { + "InputFile": "File To Copy", + "InputFile-Help": "The file to copy, if left empty then the working file will be copied", + "InputFile-Placeholder": "Working File", + "DestinationPath": "Destination Folder", + "DestinationPath-Help": "The folder where the file will be copied to", + "DestinationFile": "Destination File", + "DestinationFile-Help": "The filename to copy the file to. If empty, the original filename will be used", + "CopyFolder": "Copy Folder", + "CopyFolder-Help": "If the relative library folder structure should be copied too", + "AdditionalFiles": "Additional Files", + "AdditionalFiles-Help": "Additional files to copy from the directory to the new directory.\nEach value can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn''t support regular expressions.", + "AdditionalFilesFromOriginal": "Original Directory", + "AdditionalFilesFromOriginal-Help": "If the additional files should be copied from the working directory or from the original directory. Turn on for original directory.", + "PreserverOriginalDates": "Preserve Dates", + "PreserverOriginalDates-Help": "If the original creation time and last write time of the original input file should be preserved." + } + }, + "DeleteSourceDirectory": { + "Label": "Delete Source Folder", + "Outputs": { + "1": "Source directory deleted", + "2": "Directory was NOT deleted" + }, + "Description": "Deletes the source folder of the original library file", + "Fields": { + "IfEmpty": "If Empty", + "IfEmpty-Help": "Only delete the source folder if the it is empty", + "IncludePatterns": "Include Patterns", + "IncludePatterns-Help": "Optional, if set only files matching these patterns will be counted to see if the folder is empty. Any of these patterns can match." + } + }, + "Executor": { + "Description": "Execute the following process against the file.\nOutput 1: The process returned the success exit code\nOutput 2: The process return a non-successful exit code.", + "Outputs": { + "1": "Process returned success", + "2": "Process returned failure" + }, + "Fields": { + "FileName": "File Name", + "FileName-Help": "The name of the file to execute", + "Arguments": "Arguments", + "Arguments-Help": "The arguments to be passed to the process to execute", + "WorkingDirectory": "Working Folder", + "WorkingDirectory-Help": "The folder where the process will be executed from", + "SuccessCode": "Success Code", + "SuccessCode-Help": "The exit code of the process indicating the process was successful. Usually this should be 0.", + "Timeout": "Timeout", + "Timeout-Help": "How long the process can run for before being terminated. Use 0 for no timeout.", + "Timeout-Suffix": "seconds", + "OutputVariable": "Output Variable", + "OutputVariable-Help": "An optional variable name to store the process output into", + "OutputErrorVariable": "Output Error Variable", + "OutputErrorVariable-Help": "An optional variable name to store the process error output into" + } + }, + "DirectoryDateCompare": { + "Description": "Checks if the directory creation or last write time matches the specified date constraint.", + "Outputs": { + "1": "Matches the date constraint.", + "2": "Does not match the date constraint." + }, + "Fields": { + "Path": "Path", + "Path-Help": "The path to the folder to check. Leave empty to check the current working file.\nIf a file is specified the directory containing the file will be checked.", + "Date": "Date", + "DateComparision": "Comparision" + } + }, + "FileDateCompare": { + "Description": "Checks if the file creation or last write time matches the specified date constraint.", + "Outputs": { + "1": "Matches the date constraint.", + "2": "Does not match the date constraint." + }, + "Fields": { + "FileName": "File Name", + "FileName-Help": "The file to check. Leave empty to check the current working file.", + "Date": "Date", + "DateComparision": "Comparision" + } + }, + "FileExtension": { + "Description": "Checks if the file has one of the configured extensions.\n\nOutput 1: Matches\nOutput 2: Does not match", + "Outputs": { + "1": "Extension match", + "2": "Extension did not match" + }, + "Fields": { + "Extensions": "Extensions", + "Extensions-Help": "A list of case insensitive file extensions that will be matched against.\nOutput 1 Matches\nOutput 2: Does not match" + } + }, + "FileExists": { + "Description": "Checks if a file exists\n\nOutput 1: File exists\nOutput 2: File does not exist", + "Outputs": { + "1": "File exists", + "2": "File does not exist" + }, + "Fields": { + "FileName": "File Name", + "FileName-Help": "The file to check. Leave empty to check the current working file." + } + }, + "HasHardLinks": { + "Description": "Checks if a file has hard links to it or not", + "Outputs": { + "1": "Hard links detected", + "2": "No hard links detected" + }, + "Fields": { + "FileName": "File Name", + "FileName-Help": "The file to check. Leave empty to check the current working file.", + "Count": "Count", + "Count-Help": "The number of hard links required to call output 1." + } + }, + "Delete": { + "Description": "Deletes a file or folder", + "Outputs": { + "1": "File deleted" + }, + "Fields": { + "FileName": "Path", + "FileName-Help": "A path to either a file or folder to delete.\n\nIf left blank the current working file will be deleted." + } + }, + "DirectoryIterator": { + "Description": "Iterates all files in a given directory and executes those files against a sub flow.", + "Outputs": { + "1": "Directory files iterated" + }, + "Fields": { + "Flow": "Flow", + "Flow-Help": "The sub flow to execute the files against.", + "Directory": "Directory", + "Directory-Help": "The directory whose files will be iterated.", + "Pattern": "Pattern", + "Pattern-Help": "Any optional pattern to limit the files for iteration, this can be a wildcard pattern starting with a `*` or a regular expression.", + "Recursive": "Recursive", + "Recursive-Help": "If files in all sub directories should also be iterated, or if only the top level files should be iterated." + } + }, + "FailFlow": { + "Description": "Fails a flow immediately, useful if you want a certain path to just fail.", + "Fields": { + "Reason": "Reason", + "Reason-Help": "An optional reason to record why the flow failed." + } + }, + "FileSize": { + "Description": "Checks if the file size matches the configured parameters. The values are in megabytes.\n\nOutput 1: Matches\nOutput 2: Does not match", + "Outputs": { + "1": "File size within range", + "2": "File size not within range" + }, + "Fields": { + "Comparison": "Comparison", + "Lower": "Greater Than", + "Lower-Suffix": "MB", + "Lower-Help": "The value it must be greater than this number of megabytes", + "Upper": "Less Than", + "Upper-Suffix": "MB", + "Upper-Help": "The value it must be less than than this number of megabytes. Leave as 0 to not test the upper limit." + } + }, + "FileSizeCompare": { + "Description": "Checks if the file size has changed sized from the original file.", + "Outputs": { + "1": "Smaller than original", + "2": "Same size as original", + "3": "Larger than original" + } + }, + "FileSizeWithin": { + "Description": "Checks if the new file size is within the allowed range of the original file size.", + "Value": "Value", + "Value-Help": "The difference allowed for the file size, this value can be either plus or minus this difference.", + "Outputs": { + "1": "File size is within allowed range", + "2": "File size is not within allowed range" + } + }, + "Function": { + "Outputs": { + "1": "returned 1", + "2": "returned 2", + "3": "returned 3", + "4": "returned 4", + "5": "returned 5", + "6": "returned 6", + "7": "returned 7", + "8": "returned 8", + "9": "returned 9", + "10": "returned 10" + }, + "Fields": { + "Outputs": "Outputs", + "Template": "Template", + "Template-Help": "WARNING: This will replace whatever is in the code block with the template you select.", + "Code": "Code", + "Code-Help": "return -1 for error and flow to stop. return 0 for flow to complete. return 1 or more for the desired output to be called" + } + }, + "GotoFlow": { + "Description": "This lets you switch to a different flow to process. This flow will exit and the parameters and working file will be passed into the new Flow", + "Fields": { + "Flow": "Flow", + "UpdateFlowUsed": "Update Flow", + "UpdateFlowUsed-Help": "If the files `Flow` should be updated to reference this new Flow or leave it as the original Flow." + } + }, + "Reprocess": { + "Description": "The flow element allows you to reprocess the original library file with a different processing node.\n\n If the same processing node is selected as the one currently processing the file, the flow will fail.", + "Fields": { + "Node": "Node", + "Node-Help": "The processing node to process this file." + } + }, + "IsProcessingOnNode": { + "Description": "Checks if the flow is currently processing on a specified processing node.", + "Fields": { + "Node": "Node", + "Node-Help": "The processing node to check." + }, + "Outputs": { + "1": "Is processing on node", + "2": "Is not processing on node" + } + }, + "IsDocker": { + "Description": "Determines if this flow is running on Docker", + "Outputs": { + "1": "Is running on Docker", + "2": "Is not running on Docker" + } + }, + "IsLinux": { + "Description": "Determines if this flow is running on Linux", + "Outputs": { + "1": "Is running on Linux", + "2": "Is not running on Linux" + } + }, + "IsMacOS": { + "Label": "Is MacOS", + "Description": "Determines if this flow is running on MacOS", + "Outputs": { + "1": "Is running on MacOS", + "2": "Is not running on MacOS" + } + }, + "IsWindows": { + "Description": "Determines if this flow is running on Windows", + "Outputs": { + "1": "Is running on Windows", + "2": "Is not running on Windows" + } + }, + "Log": { + "Description": "Logs a message to the flow log", + "Outputs": { + "1": "Message logged" + }, + "Fields": { + "LogType": "Type", + "Message": "Message" + } + }, + "Matches": { + "Description": "Compares a set of values and matches conditions to see which output should be called", + "Fields": { + "MatchConditions": "", + "MatchConditionsKey": "Value", + "MatchConditionsValue": "Expression", + "MatchConditions-Help": "The matches to test which output should be called." + } + }, + "MoveFile": { + "Description": "Moves a file to the destination folder", + "Outputs": { + "1": "File moved", + "2": "File moved, however original file could not be deleted" + }, + "Fields": { + "InputFile": "File To Move", + "InputFile-Help": "The file to move, if left empty then the working file will be moved", + "InputFile-Placeholder": "Working File", + "DestinationPath": "Destination Folder", + "DestinationPath-Help": "The folder where the file will be moved to", + "DestinationFile": "Destination File", + "DestinationFile-Help": "The filename to move the file to. If empty, the original filename will be used", + "MoveFolder": "Copy Folder", + "MoveFolder-Help": "If the relative library folder structure should be copied too", + "DeleteOriginal": "Delete Original", + "DeleteOriginal-Help": "If the original file should be deleted, this will only happen if the working file is different to the original file", + "AdditionalFiles": "Additional Files", + "AdditionalFiles-Help": "Additional files to move from the directory to the new directory.\nEach value can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn''t support regular expressions.", + "AdditionalFilesFromOriginal": "Original Directory", + "AdditionalFilesFromOriginal-Help": "If the additional files should be moved from the working directory or from the original directory. Turn on for original directory.", + "PreserverOriginalDates": "Preserve Dates", + "PreserverOriginalDates-Help": "If the original creation time and last write time of the original input file should be preserved." + } + }, + "OlderThan": { + "Description": "Checks if a folder is older than the range specified", + "Outputs": { + "1": "File is older", + "2": "File is not older" + }, + "Fields": { + "Number": "Number", + "Unit": "Unit", + "Date": "Date" + } + }, + "OriginalFile": { + "Description": "Sets the current working file in the flow to the original file that started the flow", + "Outputs": { + "1": "Working file set to original file" + } + }, + "PatternMatch": { + "Description": "Tests the working file and original file against a regular expression.\n\nOutput 1: Matches expression\nOutput 2: Does not match", + "Outputs": { + "1": "Matches expression", + "2": "Does NOT match" + }, + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression, using the C# specification for regular expressions." + } + }, + "PatternReplacer": { + "Label": "Filename Pattern Replacer", + "Description": "Lets you make replacements in the filename. Can use regular expressions for replacements, or simple string replacements.\n\nOutput 1: Replacement done\nOutput 2: No replacement done", + "Outputs": { + "1": "Replacement done", + "2": "No replacement done" + }, + "Fields": { + "Replacements": "Replacements", + "ReplacementsKey": "Pattern", + "ReplacementsValue": "Value", + "UseWorkingFileName": "Use Working Filename", + "UseWorkingFileName-Help": "If current working filename should be used, or if false, the original filename of the incoming file will be used." + } + }, + "Random": { + "Label": "Random", + "Description": "Chooses a random output", + "Fields": { + "Outputs": "Outputs", + "Outputs-Help": "The number of outputs that could possible be called." + } + }, + "ReplaceOriginal": { + "Description": "Replaces the original file with the working file.\n\nIf the extension is different on the working file, the original file will be deleted and the working file will be moved to the original with the new extension.\nE.g. from File.avi to File.mkv", + "Outputs": { + "1": "Original file replaced" + }, + "Fields": { + "PreserverOriginalDates": "Preserve Dates", + "PreserverOriginalDates-Help": "If the original creation time and last write time of the original input file should be preserved." + } + }, + "Renamer": { + "Description": "Renames the working file.\nVariables can be used by entering the key '{' inside the Pattern field.", + "Outputs": { + "1": "File renamed" + }, + "Fields": { + "Pattern": "New Name", + "Pattern-Help": "The new name of the file. Can use variables. Any empty () and '{}' will be removed.", + "DestinationPath": "Destination Folder", + "DestinationPath-Help": "If the file should be moved to a different folder.", + "LogOnly": "Log Only", + "LogOnly-Help": "Turn on if you just want to test this flow element without it actually renaming the file", + "CsvFile": "CSV File", + "CsvFile-Help": "Will append to this file the original name and the renamed file. Useful when using ''Log Only'' to test the renamer before changing files." + } + }, + "SetVariable": { + "Label": "Set Variable", + "Description": "Sets a variable in the flow.", + "Outputs": { + "1": "Variable set" + }, + "Fields": { + "Variable": "Variable", + "Variable-Help": "The name of the variable to set", + "Value": "Value", + "Value-Help": "The value of the variable to set." + } + }, + "SetWorkingFile": { + "Label": "Set Working File", + "Description": "Updates the current working file to the one specified.", + "Outputs": { + "1": "Working File Set" + }, + "Fields": { + "File": "File", + "File-Description": "The path to the new working file or folder.", + "DontDeletePrevious": "Don't Delete Previous", + "DontDeletePrevious-Help": "If the previous *temporary* working file should *not* be deleted.\nOnly temporary files will be deleted, files that have been created by FileFlows into the runners temporary directory." + } + }, + "Sleep": { + "Description": "Pauses the flow", + "Outputs": { + "1": "Flow resumed" + }, + "Fields": { + "Milliseconds": "Milliseconds", + "Milliseconds-Help": "How long to sleep the flow for. Must be between 1 millisecond and 1 hour" + } + }, + "Touch": { + "Description": "Touches a file or directory and sets the last write time to now.", + "Outputs": { + "1": "Successfully touched item" + }, + "Fields": { + "FileName": "File Name", + "FileName-Help": "Full filename of file or folder to touch.\nIf left blank the working file will be used." + } + }, + "VariableMatch": { + "Description": "Tests if a input matches a stored Variable", + "Fields": { + "Variable": "Variable", + "Variable-Help": "The variable to match against", + "Input": "Input", + "Input-Help": "The input to match the variable against." + }, + "Outputs": { + "1": "Input matched variable", + "2": "Input did not match variable" + } + }, + "WebRequest": { + "Description": "Allows you to send a web request", + "Outputs": { + "1": "Successfully sent", + "2": "Request returned a non-successful status code" + }, + "Fields": { + "Url": "URL", + "Url-Help": "The URL of the request", + "Method": "Method", + "Method-Help": "The web method to use when sending this request", + "ContentType": "Content Type", + "ContentType-Help": "The Content-Type of the message to send", + "Headers": "Headers", + "Headers-Help": "Optional headers to send with the request", + "HeadersKey": "Key", + "HeadersValue": "Value", + "Body": "Body", + "Body-Help": "The body of the request being sent. Variables can be used in this field." + } + }, + "Unpack": { + "Description": "Allows you to unpack an archive (zip, rar, tar, etc)", + "Outputs": { + "1": "File Unpacked" + }, + "Fields": { + "DestinationPath": "Destination Folder", + "DestinationPath-Help": "The destination folder where to unpack the file.", + "File": "File", + "File-Help": "The name of the file to unpack. Can be left blank and if so the current working file will be used." + } + }, + "Zip": { + "Description": "Allows you to zip the input", + "Outputs": { + "1": "Zip created" + }, + "Fields": { + "DestinationPath": "Destination Folder", + "DestinationPath-Help": "The destination folder where to put the zip file. If blank, the zip will be placed in the library root.", + "DestinationFile": "Destination File", + "DestinationFile-Help": "The filename of the newly created zip. If blank, the name of the item will be used as the zip file.", + "Path": "Path", + "Path-Help": "The path to the file or folder to zip. If blank, the working file will be zipped.", + "SetWorkingFile": "Set Working File", + "SetWorkingFile-Help": "If the newly created zip should become the new working file." + } + }, + "SevenZip": { + "Label": "7-Zip", + "Description": "Allows you to 7zip the input", + "Outputs": { + "1": "7zip created" + }, + "Fields": { + "DestinationPath": "Destination Folder", + "DestinationPath-Help": "The destination folder where to put the 7zip file. If blank, the 7zip will be placed in the library root.", + "DestinationFile": "Destination File", + "DestinationFile-Help": "The filename of the newly created 7zip. If blank, the name of the item will be used as the 7zip file.", + "CompressionLevel": "Compression Level", + "CompressionLevel-Help": "The level of compression to use when compressing the level.", + "CompressionMethod": "Compression Method", + "CompressionMethod-Help": "The compression method used for compression, LZMA2 is recommended." + } + }, + "IfBoolean": { + "Description": "Tests if a Variable is true or false", + "Outputs": { + "1": "True", + "2": "False" + }, + "Fields": { + "Variable": "Variable", + "Variable-Help": "The name of the variable to check" + } + }, + "IfString": { + "Description": "Tests if a Variable is matches a string", + "Outputs": { + "1": "Matched string 1", + "2": "Matched string 2", + "3": "Matched string 3", + "4": "Matched string 4", + "5": "Matched string 5", + "6": "Matched string 6", + "7": "Matched string 7", + "8": "Matched string 8", + "9": "Matched string 9", + "10": "Matched string 10" + }, + "Fields": { + "Variable": "Variable", + "Variable-Help": "The name of the variable to check", + "Outputs": "Outputs", + "Outputs-Help": "This should match the number of options there are", + "Options": "Options", + "Options-Help": "The string to match against." + } + }, + "WriteText": { + "Description": "Writes text to a file", + "Outputs": { + "1": "Text written to file" + }, + "Fields": { + "File": "File", + "File-Help": "The file to write the text to.", + "Text": "Text", + "Text-Help": "The text to write to the file. If left blank the current working file full path will be written." + } } + } } \ No newline at end of file diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index ef9c5bf90354a0025bda18b9f38e47886653210f..e39821286f6004fde206a05da9862689f21d65f6 100644 GIT binary patch delta 55372 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 Bk<9=A delta 55269 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%0D;&MrcF8hg#;vC{|M9}Fd@svMX=wjmR*GGI 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 ACjbBd delta 2698 zcmZ9O2~bm46o$_WB!pFhAYdV3bA-~!8X$;+6)XxWEgBNUscceFs*HeI9SJVXG>8hu zYPGhARfiF6t8uL|f-HjjhFBF)QE;h6D_|?4JqJm=<<0zg=X?LT=dQ_1Ln&`xDX%zi zR+0~ZdmccVFTfoh#?x~aWi0qA8}J$*0AP%Fcg1vw#CQkAQHsftcz=N0kcd1Xb72Z{ zDnGM-Y;NZyt@rHjjcv`AZqwvHC@FSubmRa$urZI zR4>Xh-UK{QVW=6XOw=0G_IM#wqLwIxP#bRwP4Q-MFWwxUp}JA#q2^$N>Ql#Cz!;?k zj1IK`7nBU+FjNF8T4@P$l~$0W90vJHYbZi#QQJ^usJo%oP>%Osl_EH&w1H;jaA;TB zf|bG+>`+}wI{=j(h)@oy5g<|7gEz__C098>Qj`Ov#9$Doa)eaXNSLSk2o|fvuu6sN z15#*GNudSx5cLezgX%}|6Qp2?vO_teMxmq$)P^o8$P94+e3PK%Oq?V^ureVCG^ou6 zlafPWd13&p(&@}Q9YxNtmUap+Q&c4f+KN$*Y9Yp_aOd=%333&~)j$Q#a32Qu6T_|;C!-qBFB%-Y2XZ6Bp2%kzmLi{H*dO^k z!@f7U1KKf!JDGyi!6SyLgU1Y$|Ab-k zpE6ATp98FZ|Bax8XH17K$bT_gLIdn#eB$Rr{1-zy_?uy>|B}hKM((D1>cK-nd)~t| zpb_>mOa)#s1E3Z9hw&-@Uxq3FHIq;E`xu|{-yo~?hm0EZGYx2jZyBZz-!V)p0KESn zQjTY0IJ7-z>zO(~iZa5*-oShdjCr6oJfH#aha?CXCf|f%nt_mE@=X~g-;81M%^4=& zf`{i%KO#!79FkzgF!>^$nIXRd*_LN*U@AC*$)_J0C!WaQ+aNm+VX;>3Z9eA${!EAm z9eO#u<-g}*T&qgt1t{`MkR$NzDjVdD$a%q4Zegiz{?Tkjw93aNZe?5-Er@C zMwV_$+7vOb1rtVS>wJnvh0wgJ!s*jxyeZVHsv=B5o>&!O262f=k*07A|1jv5`7SVa zae5Q}d5>$Yit@w*n^)O=GR`(~ z_qa{sgNj}C@wh`X z=l>9`+Of?wQ&X^7QYcUhL-x;ca(h+%vasCd>&w-LyN(qLWf}Q43q@;o-g4MwWwx(j z%Voj0DZkmp3HZB?SQ)p~%qj@i7&Y8=%|2NXB=XDq7vnr@QvtsE>IZQ?^XqEZMTt)_(V} z6(&8xV-qyB_v^MF$yWyUZrWIvv3$&)Fz;WcR#p@=gl7f+%sF?|E!}wK#hQoOvGKe$L;sHU6aL^_|fdpM5M-6&ebGZ)w5AIdh= NDzSF@h8&(d{0BD>^b!C7