using FileFlows.Plugin; using FileFlows.Plugin.Attributes; using FileHelper = FileFlows.Plugin.Helpers.FileHelper; namespace FileFlows.BasicNodes.File; /// /// Flow element to delete the source directory /// public class DeleteSourceDirectory : Node { /// /// Gets the number of inputs /// public override int Inputs => 1; /// /// Gets the number of outputs /// public override int Outputs => 2; /// /// Gets the flow element type /// public override FlowElementType Type => FlowElementType.Process; /// /// Gets the icon /// public override string Icon => "far fa-trash-alt"; /// /// Gets the Help URL /// public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/delete-source-directory"; /// /// Gets or sets if the directory should only be deleted if empty /// [Boolean(1)] public bool IfEmpty { get; set; } /// /// Gets or sets an optional list of file patterns to include in the If empty check. /// eg if [mkv, mp4, mov, etc] is the list, if any video file is found the directory will not be deleted. /// [StringArray(2)] public string[] IncludePatterns { get; set; } /// /// Executes the flow element /// /// the node parameters /// the output to call next, -1 to abort flow, 0 to end flow public override int Execute(NodeParameters args) { string libraryPath = args.LibraryFileName.Substring(0, args.LibraryFileName.Length - args.RelativeFile.Length) .TrimEnd('/') .TrimEnd('\\'); args.Logger?.ILog("Library File Name: " + args.LibraryFileName); args.Logger?.ILog("Library Path: " + libraryPath); args.Logger?.ILog("Relative File: " + args.RelativeFile); //args.Logger?.ILog("IsRemote: " + args.IsRemote); int pathIndex = args.RelativeFile.IndexOfAny(new[] { '\\', '/' }); 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 pathSeparator = args.FileService.PathSeparator.ToString(); args.Logger?.ILog("Path Separator: " + pathSeparator); string pathToDelete = libraryPath.EndsWith(pathSeparator) ? libraryPath + topdir : libraryPath + pathSeparator + topdir; args.Logger?.ILog("Path To Delete: " + pathToDelete); // if (args.IsRemote) // { // if (args.LibraryFileName.StartsWith(pathToDelete)) // { // args.Logger?.ILog("Deleting original file remotely: " + args.LibraryFileName); // args.DeleteRemote(args.LibraryFileName, false, // null); // first delete the source file since its in this directory we are deleting // } // // args.Logger?.ILog("Sending request to delete remote path: " + pathToDelete); // // bool deleted = args.DeleteRemote(pathToDelete, IfEmpty, IncludePatterns); // if (deleted) // args.Logger?.ILog("Successfully deleted remote path: " + pathToDelete); // else // args.Logger?.WLog("Failed to delete remote path: " + pathToDelete); // return deleted ? 1 : 2; // } if (IfEmpty) { string libFileDirectory = args.IsDirectory ? args.FileName : FileHelper.GetDirectory(args.LibraryFileName); args.Logger?.ILog("libFileDirectory: " + libFileDirectory); return RecursiveDelete(args, libraryPath, libFileDirectory, true); } args.Logger?.ILog("Deleting directory: " + pathToDelete); var result = args.FileService.DirectoryDelete(pathToDelete, true); if (result.IsFailed) { args.Logger?.WLog("Failed to deleted directory: " + result.Error); return 2; } return 1; } private int RecursiveDelete(NodeParameters args, string root, string path, bool deleteSubFolders) { if (string.IsNullOrWhiteSpace(path)) return 1; args.Logger?.ILog("Checking directory to delete: " + path); //DirectoryInfo dir = new DirectoryInfo(path); if (string.Equals(path, root, StringComparison.CurrentCultureIgnoreCase)) { args.Logger?.ILog("At root, stopping deleting: " + root); return 1; } if (path.Length <= root.Length) { args.Logger?.ILog("At root2, stopping deleting: " + root); return 1; } if (deleteSubFolders == false) { if (args.FileService.GetDirectories(path).ValueOrDefault?.Any() == true) { args.Logger?.ILog("Directory contains subfolders, cannot delete: " + path); return 2; } } var files = args.FileService.GetFiles(path, "", true).ValueOrDefault ?? new string [] {}; args.Logger?.ILog($"Directory contains {files.Length} file{(files.Length == 1 ? "" : "s")}"); foreach (var file in files) { args.Logger?.ILog("File: " + file); } if(files.Any(x => x.ToLowerInvariant().EndsWith(".fftemp"))) { args.Logger?.ILog("Temporary FF file found, cannot delete."); return 2; } if (IncludePatterns?.Any() == true) { var includeFiles = files.Where(x => { foreach (var pattern in IncludePatterns) { if (x.Contains(pattern)) return true; try { if (System.Text.RegularExpressions.Regex.IsMatch(x, pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase)) return true; } catch (Exception) { } } return false; }).ToList(); if (includeFiles.Any()) { args.Logger?.ILog("Directory is not empty, cannot delete: " + path + Environment.NewLine + string.Join(Environment.NewLine, includeFiles.Select(x => " - " + x))); return 2; } } else if (files.Any()) { args.Logger?.ILog("Directory is not empty, cannot delete: " + path + Environment.NewLine + string.Join(Environment.NewLine, files.Select(x => " - " + x))); return 2; } args.Logger?.ILog("Deleting directory: " + path); try { args.FileService.DirectoryDelete(path, true); } catch (Exception ex) { args.Logger?.WLog("Failed to delete directory: " + ex.Message); return args.FileService.DirectoryExists(path).Is(true) ? 2 : 1; // silently fail } string parent = FileHelper.GetDirectory(path); return RecursiveDelete(args, root, parent, false); } }