Put this code in a script-button, it is already setup to work for your specific use case (or download button below). Looks like much code at first, but it's a generic filter/selection approach. It's quite easy and quick to customize for other use cases I think. I use it to select and delete jpg-files, for which there is a raw-variant and finished photoshop acr exports e.g.
So, if you need to change conditions or filetypes, you can do so in the PreFilter(), MainFilter(), Evaluate() methods. This will only select the files you'd like to delete, so you can check results first before proceeding. If you want them to be deleted right away, alter the command in ExecuteForEach().
@script jscript
////////////////////////////////////////////////////////////////////////////////
var PreFilter = function( file ){
//return true if this file(type) is of interest in the process
return true;
}
////////////////////////////////////////////////////////////////////////////////
var MainFilter = function( file ){
//return true to run evaluation on this specific file(type)
if (file.ext!=".jpg") return true;
}
////////////////////////////////////////////////////////////////////////////////
var Evaluate = function( file ){
//return true to execute the foreach-operation on this file (select, delete etc.)
var jpgVariant = this.FileExists(file.baseName.esc()+'\.jpg');
if (!jpgVariant) return true;
}
////////////////////////////////////////////////////////////////////////////////
var ExecuteForEach = function( file ){
//execute for each file that passed evaluation
this.cmd.RunCommand('Select "'+file.name+'" EXACT');
}
////////////////////////////////////////////////////////////////////////////////
var ExecuteForAll = function(){
//execute finally
//this.cmd.RunCommand('SelectEx MAKEVISIBLE');
}
////////////////////////////////////////////////////////////////////////////////
function EasyFilter(filesIn,cmd,preFilter,mainFilter,evaluate,executeForEach,executeForAll){
this.version = 0.1;
this.files = [];
this.filesFiltered = [];
this.filesEvaluated = [];
this.cmd = cmd;
this.PreFilter = preFilter;
this.MainFilter = mainFilter;
this.Evaluate = evaluate;
this.ExecuteForEach = executeForEach;
this.ExecuteForAll = executeForAll;
////////////////////////////////////////////////////////////////////////////
String.prototype.esc = function(str){
return this.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
////////////////////////////////////////////////////////////////////////////
this.FileExists = function( fileNameRegex ){
fileNameRegex = new RegExp(fileNameRegex);
for(var i=0;i<this.files.length;i++){
if (this.files[i].name.search(fileNameRegex)!=-1)
return this.files[i];
}
return null;
}
////////////////////////////////////////////////////////////////////////////
DOpus.Output("PreFiltering ["+filesIn.length+"] files..");
for(var i=0;i<filesIn.length;i++){
if (this.PreFilter(filesIn[i])===true){
this.files[this.files.length] = filesIn[i];
DOpus.Output(" PreFilter passed ["+filesIn[i].name+"]");
} else {
//DOpus.Output(" PreFilter ignore ["+filesIn[i].name+"]");
}
}
DOpus.Output("");
////////////////////////////////////////////////////////////////////////////
DOpus.Output("MainFiltering ["+this.files.length+"] files..");
for(var i=0;i<this.files.length;i++){
if (this.MainFilter(this.files[i])===true){
DOpus.Output(" MainFilter passed ["+this.files[i].name+"]");
this.filesFiltered[this.filesFiltered.length] = this.files[i];
} else {
//DOpus.Output(" MainFilter ignore ["+filesIn[i].name+"]");
}
}
DOpus.Output("");
////////////////////////////////////////////////////////////////////////////
DOpus.Output("Evaluating ["+this.filesFiltered.length+"] files..");
for(var i=0;i<this.filesFiltered.length;i++){
if (this.Evaluate(this.filesFiltered[i])===true){
DOpus.Output(" Evaluation passed ["+this.filesFiltered[i].name+"]");
this.filesEvaluated[this.filesEvaluated.length] = this.filesFiltered[i];
} else {
//DOpus.Output(" Evaluation ignore ["+this.filesFiltered[i].name+"]");
}
}
DOpus.Output("");
////////////////////////////////////////////////////////////////////////////
DOpus.Output("Processing ["+this.filesEvaluated.length+"] files..");
for(var i=0;i<this.filesEvaluated.length;i++){
DOpus.Output(" Running ForEachOp ["+this.filesEvaluated[i].name+"]");
this.ExecuteForEach(this.filesEvaluated[i]);
}
DOpus.Output("");
////////////////////////////////////////////////////////////////////////////
DOpus.Output("Running ForAll-Operation..");
this.ExecuteForAll();
DOpus.Output("");
}
////////////////////////////////////////////////////////////////////////////////
function OnClick(data){
var filesTab = data.func.sourcetab.files, files = [];
var cmd = data.func.command; cmd.ClearFiles();
////////////////////////////////////////////////////////////////////////////
for(var i=0;i<filesTab.count;i++){
var file = { name : String(filesTab(i).name).toLowerCase(),
baseName : String(filesTab(i).name_stem).toLowerCase(),
ext : String(filesTab(i).ext).toLowerCase() };
files[files.length] = file;
}
var filter = new EasyFilter(files,cmd,PreFilter,MainFilter,Evaluate,ExecuteForEach,ExecuteForAll);
DOpus.Output("Done.");
}
Here's my simple version. Handles both the original inputs (deletes 2 files) and the revised ones (deletes 1 file).
Function OnClick(ByRef clickData)
Set cmd = clickData.func.command
Set fsu = DOpus.FSUtil
AnyFiles = False
cmd.ClearFiles
' Use selected_files if you only want to consider what's selected.
For Each Item In clickData.func.sourcetab.files
' Skip .jpg files, obviously.
If (LCase(Item.ext) <> ".jpg") Then
Set itemPath = fsu.NewPath(item.realpath)
' See if file exists with .jpg added to end.
If (Not fsu.Exists(itemPath & ".jpg")) Then
' See if file exists with ext changed to .jpg
itemPath.ext = ".jpg"
If (Not fsu.Exists(itemPath)) Then
cmd.AddFile(item)
AnyFiles = True
End If
End If
End If
Next
If (AnyFiles) Then
' Change to this if you want to select instead of delete:
' cmd.RunCommand "Select FROMSCRIPT DESELECTNOMATCH"
cmd.RunCommand "Delete"
End If
End Function
If you only care about the revised requirements, you can simplify things to this:
Function OnClick(ByRef clickData)
Set cmd = clickData.func.command
Set fsu = DOpus.FSUtil
AnyFiles = False
cmd.ClearFiles
For Each Item In clickData.func.sourcetab.files
If (LCase(Item.ext) <> ".jpg") Then
Set itemPath = fsu.NewPath(item.realpath)
itemPath.ext = ".jpg"
If (Not fsu.Exists(itemPath)) Then
cmd.AddFile(item)
AnyFiles = True
End If
End If
Next
If (AnyFiles) Then
cmd.RunCommand "Delete"
End If
End Function
I guess the (LCase(Item.ext) <> ".jpg") test is redundant (other than speed, perhaps), so it could be simplified even more:
Function OnClick(ByRef clickData)
Set cmd = clickData.func.command
Set fsu = DOpus.FSUtil
AnyFiles = False
cmd.ClearFiles
For Each Item In clickData.func.sourcetab.files
Set itemPath = fsu.NewPath(item.realpath)
itemPath.ext = ".jpg"
If (Not fsu.Exists(itemPath)) Then
cmd.AddFile(item)
AnyFiles = True
End If
Next
If (AnyFiles) Then
cmd.RunCommand "Delete"
End If
End Function
(That deletes the same files as the previous screenshot, but may be slightly slower.)
Your script worked great for years but now does not seem to work properly. Everything that is not a *.jpg file gets selected. I'm assuming some update in opus changed something. Can you help out again?
You wrote a script for me to do something similar (I think). It is (shown below). I highlight all the files to be processed and click the button. Mine is set to delete files where there is not an RW2 extension with the same name.
MagicExt = ".rw2"
Function OnClick(ByRef clickData)
Set cmd = clickData.func.command
cmd.deselect = False
Set setMagic = DOpus.Create.StringSetI
For Each file In cmd.files
If file.ext = MagicExt Then
setMagic.insert(file.name_stem)
cmd.RemoveFile(file)
End If
Next
For Each file In cmd.files
If setMagic.exists(file.name_stem) Then
cmd.RemoveFile(file)
End If
Next
' remove this loop once you're satisfied the script works correctly
For Each file In cmd.files
DOpus.Output "Will delete: " & file
Next
' uncomment this line to delete for real
cmd.RunCommand("delete")
End Function
I can't get this to work. Maybe I'm doing something wrong.
I copy and pasted Leo's script into a text document and saved it as specialDelete.js, and specialDelete.vbs (I noticed it says VBS in the code box). I tried to add it to Preferences > Toolbars > Scripts, but I get an error saying Failed (Parse).