creating repo for plugins

This commit is contained in:
reven
2021-11-21 07:07:37 +13:00
commit 0f8c544436
26 changed files with 1781 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Reference Include="Plugin">
<HintPath>..\Plugin.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Jint" Version="3.0.0-beta-2035" />
</ItemGroup>
<ItemGroup>
<Content Include="BasicNodes.en.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,87 @@
{
"Enums":{
"LogType":{
"Info":"Information",
"Debug":"Debug",
"Warning":"Warning",
"Error":"Error"
}
},
"Flow":{
"Parts":{
"InputFile":{
"Description":"An input node for a library file. This is required and is the starting point of a flow. Any input node can be used, just one is required."
},
"CopyFile":{
"Description":"Copies a file to the destination path",
"Fields":{
"DestinationPath":"Destination Path",
"DestinationPath-Help":"The path where the file will be copied too",
"CopyFolder":"Copy Folder",
"CopyFolder-Help" :"If the relative library folder structure should be copied too"
}
},
"Log":{
"Description":"Logs a message to the flow log",
"Fields":{
"LogType":"Type",
"Message":"Message"
}
},
"FileExtension":{
"Description":"Checks if the file has one of the configured extensions.\n\nOutput 1: Matches\nOutput 2: Does not match",
"Fields":{
"Extensions":"Extensions",
"Extensions-Help":"A list of case insensitive file extensions that will be matched against.\nOuput 1 Matches\nOutput 2: Does not match"
}
},
"FileSize":{
"Description":"Checks if the file size matches the configured parameters.\n\nOutput 1: Matches\nOutput 2: Does not match",
"Fields":{
"Comparison":"Comparison",
"Lower":"Lower",
"Lower-Suffix":"MB",
"Lower-Help":"The value it must bet greater than",
"Upper":"Upper",
"Upper-Suffix":"MB",
"Upper-Help":"The value it must be less than. Leave as 0 to not test the upper limit."
}
},
"MoveFile":{
"Description":"Moves a file to the destination path",
"Fields":{
"DestinationPath":"Destination Path",
"DestinationPath-Help":"The path where the file will be moved too",
"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"
}
},
"RenameFile":{
"Description":"Renames the working file",
"Fields":{
"FileName":"File Name",
"FileName-Help":"The new filename"
}
},
"DeleteSourceDirectory":{
"Description":"Deletes the source directory of the original library file",
"Fields":{
"IfEmpty":"If Empty",
"IfEmpty-Help":"Only delete the source directory 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."
}
},
"Function":{
"Fields":{
"Outputs":"Outputs",
"Outputs-Help":"The number of outputs this node can have.",
"Code":"Code",
"Code-Help":"return -1 for error and flow to stop\nreturn 0 for flow to complete\nreturn 1 or more for the desired output to be called"
}
}
}
}
}

107
BasicNodes/File/CopyFile.cs Normal file
View File

@@ -0,0 +1,107 @@
namespace FileFlows.BasicNodes.File
{
using System.ComponentModel;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class CopyFile : Node
{
public override int Inputs => 1;
public override int Outputs => 1;
public override FlowElementType Type => FlowElementType.Process;
public override string Icon => "far fa-copy";
private string _DestinationPath = string.Empty;
[Folder(1)]
public string DestinationPath
{
get => _DestinationPath;
set { _DestinationPath = value ?? ""; }
}
[Boolean(2)]
public bool CopyFolder { get; set; }
private bool Canceled;
public override Task Cancel()
{
Canceled = true;
return base.Cancel();
}
public override int Execute(NodeParameters args)
{
Canceled = false;
string dest = DestinationPath;
if (string.IsNullOrEmpty(dest))
{
args.Logger.ELog("No destination specified");
args.Result = NodeResult.Failure;
return -1;
}
args.Result = NodeResult.Failure;
if (CopyFolder)
dest = Path.Combine(dest, args.RelativeFile);
else
dest = Path.Combine(dest, new FileInfo(args.FileName).Name);
var destDir = new FileInfo(dest).DirectoryName;
if (Directory.Exists(destDir) == false)
Directory.CreateDirectory(destDir);
// have to use file streams so we can report progress
int bufferSize = 1024 * 1024;
using (FileStream fsOut = new FileStream(dest, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
{
using (FileStream fsIn = new FileStream(args.WorkingFile, FileMode.Open, FileAccess.Read))
{
try
{
long fileSize = fsIn.Length;
fsOut.SetLength(fileSize);
int bytesRead = -1;
byte[] bytes = new byte[bufferSize];
while ((bytesRead = fsIn.Read(bytes, 0, bufferSize)) > 0 && Canceled == false)
{
fsOut.Write(bytes, 0, bytesRead);
float percent = fsOut.Position / fileSize * 100;
if (percent > 100)
percent = 100;
args.PartPercentageUpdate(percent);
}
if (Canceled == false)
args.PartPercentageUpdate(100);
}
catch (Exception ex)
{
args.Logger.ELog("Failed to move file: " + ex.Message + Environment.NewLine + ex.StackTrace);
return -1;
}
}
}
if (Canceled)
{
try
{
System.IO.File.Delete(dest);
}
catch (Exception) { }
args.Logger.ELog("Action was canceled.");
return -1;
}
else
{
args.SetWorkingFile(dest);
return base.Execute(args);
}
}
}
}

View File

@@ -0,0 +1,82 @@
namespace FileFlows.BasicNodes.File
{
using System.ComponentModel;
using System.Threading.Tasks;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class DeleteSourceDirectory : Node
{
public override int Inputs => 1;
public override int Outputs => 2;
public override FlowElementType Type => FlowElementType.Process;
public override string Icon => "far fa-trash-alt";
[Boolean(1)]
public bool IfEmpty { get; set; }
[StringArray(2)]
public string[] IncludePatterns { get; set; }
public override int Execute(NodeParameters args)
{
string path = args.FileName.Substring(0, args.FileName.Length - args.RelativeFile.Length);
args.Logger.ILog("Library path: " + path);
int pathIndex = args.RelativeFile.IndexOf(System.IO.Path.DirectorySeparatorChar);
if (pathIndex < 0)
{
args.Logger.ILog("File is in library root, will not delete");
return base.Execute(args);
}
string topdir = args.RelativeFile.Substring(0, pathIndex);
string pathToDelete = Path.Combine(path, topdir);
if (IfEmpty)
{
var files = new System.IO.DirectoryInfo(pathToDelete).GetFiles("*.*", SearchOption.AllDirectories);
if (IncludePatterns?.Any() == true)
{
var count = files.Where(x =>
{
foreach (var pattern in IncludePatterns)
{
if (x.FullName.Contains(pattern))
return true;
try
{
if (System.Text.RegularExpressions.Regex.IsMatch(x.FullName, pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase))
return true;
}
catch (Exception) { }
}
return false;
}).Count();
if (count > 0)
{
args.Logger.ILog("Directory is not empty, cannot delete: " + pathToDelete);
return 2;
}
}
else if (files.Length == 0)
{
args.Logger.ILog("Directory is not empty, cannot delete: " + pathToDelete);
return 2;
}
}
args.Logger.ILog("Deleting directory: " + pathToDelete);
try
{
System.IO.Directory.Delete(pathToDelete, true);
}
catch (Exception ex)
{
args.Logger.ELog("Failed to delete directory: " + ex.Message);
return -1;
}
return base.Execute(args);
}
}
}

View File

@@ -0,0 +1,17 @@
namespace FileFlows.BasicNodes.File
{
using System.ComponentModel;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class FileExtension : Node
{
public override int Inputs => 1;
public override int Outputs => 2;
public override string Icon => "far fa-file-excel";
[StringArray(1)]
public string[] Extensions { get; set; }
public override FlowElementType Type => FlowElementType.Logic;
}
}

View File

@@ -0,0 +1,31 @@
namespace FileFlows.BasicNodes.File
{
using System.ComponentModel;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class FileSize : Node
{
public override int Inputs => 1;
public override int Outputs => 2;
public override FlowElementType Type => FlowElementType.Logic;
public override string Icon => "fas fa-balance-scale-right";
[NumberInt(1)]
public int Lower { get; set; }
[NumberInt(2)]
public int Upper { get; set; }
public override int Execute(NodeParameters args)
{
long size = new FileInfo(args.WorkingFile).Length;
if (size < (Lower * 1024 * 1024))
return 2;
if (Upper > 0 && size > (Upper * 1024 * 1024))
return 2;
return 1;
}
}
}

View File

@@ -0,0 +1,13 @@
namespace FileFlows.BasicNodes.File
{
using System.ComponentModel;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class InputFile : Node
{
public override int Outputs => 1;
public override FlowElementType Type => FlowElementType.Input;
public override string Icon => "far fa-file";
}
}

View File

@@ -0,0 +1,89 @@
namespace FileFlows.BasicNodes.File
{
using System.ComponentModel;
using System.Threading.Tasks;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
public class MoveFile : Node
{
public override int Inputs => 1;
public override int Outputs => 1;
public override FlowElementType Type => FlowElementType.Process;
public override string Icon => "fas fa-file-export";
[Folder(1)]
public string DestinationPath { get; set; }
[Boolean(2)]
public bool MoveFolder { get; set; }
[Boolean(3)]
public bool DeleteOriginal { get; set; }
public override int Execute(NodeParameters args)
{
string dest = DestinationPath;
if (string.IsNullOrEmpty(dest))
{
args.Logger.ELog("No destination specified");
args.Result = NodeResult.Failure;
return -1;
}
args.Result = NodeResult.Failure;
if (MoveFolder)
dest = Path.Combine(dest, args.RelativeFile);
else
dest = Path.Combine(dest, new FileInfo(args.FileName).Name);
var destDir = new FileInfo(dest).DirectoryName;
if (Directory.Exists(destDir) == false)
Directory.CreateDirectory(destDir);
long fileSize = new FileInfo(args.WorkingFile).Length;
bool moved = false;
Task task = Task.Run(() =>
{
try
{
if (System.IO.File.Exists(dest))
System.IO.File.Delete(dest);
System.IO.File.Move(args.WorkingFile, dest, true);
if (DeleteOriginal && args.WorkingFile != args.FileName)
{
System.IO.File.Delete(args.FileName);
}
args.SetWorkingFile(dest);
moved = true;
}
catch (Exception ex)
{
args.Logger.ELog("Failed to move file: " + ex.Message);
}
});
while (task.IsCompleted == false)
{
long currentSize = 0;
var destFileInfo = new FileInfo(dest);
if (destFileInfo.Exists)
currentSize = destFileInfo.Length;
args.PartPercentageUpdate(currentSize / fileSize * 100);
System.Threading.Thread.Sleep(50);
}
if (moved == false)
return -1;
args.PartPercentageUpdate(100);
return base.Execute(args);
}
}
}

View File

@@ -0,0 +1,57 @@
namespace FileFlows.BasicNodes.Functions
{
using System.ComponentModel;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
using Jint.Runtime;
using Jint.Native.Object;
using Jint;
using System.Text;
public class Function : Node
{
public override int Inputs => 1;
public override FlowElementType Type => FlowElementType.Logic;
public override string Icon => "fas fa-code";
[DefaultValue(1)]
[NumberIntAttribute(1)]
public new int Outputs { get; set; }
[DefaultValue("// VideoFile object contains info about the video file\n\n// return 0 to complete the flow.\n// return -1 to signal an error in the flow\n// return 1+ to indicate which output to process next\n\n return 0;")]
[Code(2)]
public string Code { get; set; }
delegate void LogDelegate(params object[] values);
public override int Execute(NodeParameters args)
{
args.Logger.DLog("Code: ", Environment.NewLine + new string('=', 40) + Environment.NewLine + Code + Environment.NewLine + new string('=', 40));
if (string.IsNullOrEmpty(Code))
return base.Execute(args); // no code, means will run fine... i think... maybe... depends what i do
var sb = new StringBuilder();
var log = new
{
ILog = new LogDelegate(args.Logger.ILog),
DLog = new LogDelegate(args.Logger.DLog),
WLog = new LogDelegate(args.Logger.WLog),
ELog = new LogDelegate(args.Logger.ELog),
};
var engine = new Engine(options =>
{
options.LimitMemory(4_000_000);
options.MaxStatements(100);
})
.SetValue("Logger", args.Logger)
.SetValue("FileSize", new FileInfo(args.WorkingFile).Length)
//.SetValue("ILog", log.ILog)
;
var result = engine.Evaluate(Code).ToObject();
if (result as bool? != true)
args.Result = NodeResult.Failure;
return base.Execute(args);
}
}
}

View File

@@ -0,0 +1,36 @@
namespace FileFlows.BasicNodes.Functions
{
using System.ComponentModel;
using FileFlows.Plugin;
using FileFlows.Plugin.Attributes;
using Jint.Runtime;
using Jint.Native.Object;
using Jint;
using System.Text;
public class Log : Node
{
public override int Inputs => 1;
public override int Outputs => 1;
public override FlowElementType Type => FlowElementType.Logic;
public override string Icon => "far fa-file-alt";
[Enum(1, LogType.Info, LogType.Debug, LogType.Warning, LogType.Error)]
public LogType LogType { get; set; }
[TextArea(2)]
public string Message { get; set; }
public override int Execute(NodeParameters args)
{
switch (LogType)
{
case LogType.Error: args.Logger.ELog(Message); break;
case LogType.Warning: args.Logger.WLog(Message); break;
case LogType.Debug: args.Logger.DLog(Message); break;
case LogType.Info: args.Logger.ILog(Message); break;
}
return base.Execute(args);
}
}
}

11
BasicNodes/Plugin.cs Normal file
View File

@@ -0,0 +1,11 @@
namespace FileFlows.BasicNodes
{
using System.ComponentModel.DataAnnotations;
public class Plugin : FileFlows.Plugin.IPlugin
{
public string Name => "Basic Nodes";
public void Init() { }
}
}