Skip to main content
Known Participant
March 25, 2023
Answered

PS script moving layers and folders to another folder

  • March 25, 2023
  • 2 replies
  • 6496 views

Im trying to write a script that searches layer and group names for BOOK and COMP then make a new group called FINAL and move the layers and groups named BOOK and COMP into the new folder called FINAL.

This is what i have so far. The problem is only the layers BOOK and COMP are moved into the FINAL folder. I also have folders called BOOK and COMP but they are not moved.

 

// Define the search terms
var searchTerms = ["BOOK", "COMP"];

// Get a reference to the active document
var doc = app.activeDocument;

// Check if the "FINAL" group exists, and create it if it doesn't
var finalGroup;
try {
  finalGroup = doc.layerSets.getByName("FINAL");
} catch (e) {
  finalGroup = doc.layerSets.add();
  finalGroup.name = "FINAL";
}

// Loop through all layers and groups in the document
for (var i = 0; i < doc.layers.length; i++) {
  var layer = doc.layers[i];

  // Check if the layer or group name contains any of the search terms
  var nameContainsSearchTerm = false;
  for (var j = 0; j < searchTerms.length; j++) {
    if (layer.name.indexOf(searchTerms[j]) !== -1) {
      nameContainsSearchTerm = true;
      break;
    }
  }

  if (nameContainsSearchTerm) {
    // Move the layer or group into the FINAL group
    layer.move(finalGroup, ElementPlacement.INSIDE);
  }
}
This topic has been closed for replies.
Correct answer c.pfaffenbichler

I ignored your last point but the other things should be addressed. 

// 2023, use it at your own risk;
// Define the search terms
var searchTerms = ["BOOK", "COMP"];
// Get a reference to the active document;
var doc = app.activeDocument;
// Check if the "FINAL" group exists, and create it if it doesn't;
var finalGroup;
try {
    finalGroup = doc.layerSets.getByName("FINAL");
    doc.activeLayer = finalGroup;
} catch (e) {
    finalGroup = doc.layerSets.add();
    finalGroup.name = "FINAL";
};
var finalId = getLayerIndex ();
// Loop through all layers and groups in the document;
var theLayers = collectLayersByNames (searchTerms);
for (var i = 0; i < theLayers.length; i++) {
    moveLayerTo(theLayers[i][2], finalId);
};
////////////////////////////////////
////// collect layers with certain name //////
function collectLayersByNames (theNames) {
    // the file;
    var myDocument = app.activeDocument;
    // get number of layers;
    var ref = new ActionReference();
    ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
    ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
    var applicationDesc = executeActionGet(ref);
    var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
    // process the layers;
    var theLayers = new Array;
    for (var m = 0; m <= theNumber; m++) {
    try {
    var ref = new ActionReference();
    ref.putIndex( charIDToTypeID( "Lyr " ), m);
    var layerDesc = executeActionGet(ref);
    var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
    var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
    // if group collect values;
    if (layerSet != "layerSectionEnd" /*&& layerSet != "layerSectionStart" && isBackground != true*/) {
    var theName = layerDesc.getString(stringIDToTypeID('name'));
    var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
    var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
    for (var x = 0; x < theNames.length; x++) {
        if (theName.indexOf(theNames[x]) != -1) {theLayers.push([theName, theIndex, theID])}
    }
    };
    }
    catch (e) {};
    };
    return theLayers
    };
////// move active layer in front of other layer in layer stack //////
function moveLayerTo (thisLayerId, theIndex) {
   selectLayerByID(thisLayerId, false);
var idlayer = stringIDToTypeID( "layer" );
    var desc58 = new ActionDescriptor();
        var ref19 = new ActionReference();
        ref19.putEnumerated( idlayer, stringIDToTypeID( "ordinal" ), stringIDToTypeID( "targetEnum" ) );
    desc58.putReference( stringIDToTypeID( "null" ), ref19 );
        var ref20 = new ActionReference();
        ref20.putIndex( idlayer, theIndex );
    desc58.putReference( stringIDToTypeID( "to" ), ref20 );
    desc58.putBoolean( stringIDToTypeID( "adjustment" ), false );
    desc58.putInteger( stringIDToTypeID( "version" ), 5 );
        var list11 = new ActionList();
        list11.putInteger(thisLayerId);
    desc58.putList( stringIDToTypeID( "layerID" ), list11 );
executeAction( stringIDToTypeID( "move" ), desc58, DialogModes.NO );
};
////// based on code by mike hale and paul riggott //////
function selectLayerByID(index,add){ 
    add = undefined ? add = false:add 
    var ref = new ActionReference();
        ref.putIdentifier(charIDToTypeID("Lyr "), index);
        var desc = new ActionDescriptor();
        desc.putReference(charIDToTypeID("null"), ref );
            if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
            desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
        try{
        executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
    }catch(e){
    alert(e.message); 
    }
    };
////// by mike hale, via paul riggott //////
function getLayerIndex(){
    var ref = new ActionReference(); 
    ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('itemIndex'));
//    ref.putIdentifier(charIDToTypeID("Lyr "), theId); 
    ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt")); 
    d = executeActionGet(ref);
    return (d.getInteger(stringIDToTypeID('itemIndex'))-1); 
    };

 

2 replies

Participant
March 28, 2023

It seems like the issue with your current script is that you are only checking the names of the layers, not the names of the layer sets (groups) in the document. To move the layer sets named BOOK and COMP into the FINAL group, you need to modify your script to check for the presence of the search terms in the names of the layer sets as well.

Here's a modified version of your script that should move both the layers and layer sets named BOOK and COMP into the FINAL group:

// Define the search terms
var searchTerms = ["BOOK", "COMP"];

// Get a reference to the active document
var doc = app.activeDocument;

// Check if the "FINAL" group exists, and create it if it doesn't
var finalGroup;
try {
finalGroup = doc.layerSets.getByName("FINAL");
} catch (e) {
finalGroup = doc.layerSets.add();
finalGroup.name = "FINAL";
}

// Loop through all layers and layer sets in the document
for (var i = 0; i < doc.layers.length; i++) {
var layer = doc.layers[i];

// Check if the layer or layer set name contains any of the search terms
var nameContainsSearchTerm = false;
for (var j = 0; j < searchTerms.length; j++) {
if (layer.name.indexOf(searchTerms[j]) !== -1) {
nameContainsSearchTerm = true;
break;
}
}

if (nameContainsSearchTerm) {
// Move the layer or layer set into the FINAL group
if (layer.typename == "LayerSet") {
layer.move(finalGroup, ElementPlacement.INSIDE);
} else {
layer.parent.move(finalGroup, ElementPlacement.INSIDE);
}
}
}

In this version of the script, we've added an additional check to see if the current layer is a layer set (group). If it is, we move the entire layer set into the FINAL group using the move method. If it's not a layer set, we use the parent property to move the layer's parent layer set (group) into the FINAL group.

Known Participant
March 28, 2023

Thanks for the reply.

I tried your amended script, it seems to fail on this line

layer.move(finalGroup, ElementPlacement.INSIDE);

Photoshop doesn't show an error but also doesn't move any layers or groups

VSCode says Eval Error (#1220): "Illegal Argument"

Stephen Marsh
Community Expert
Community Expert
March 26, 2023

Please attach a sample PSD file, it only needs to be 1x1 px in size as this is all about the layer structure, not the canvas size. A screenshot of the layers panel that clearly illustrates the before and after result would also be helpful to those volunteering their time to help.

Known Participant
March 26, 2023

Attached is a before and after PSD.

Screen shots of before and after below

 

I actually want to get the FINAL folder to replace the location of the COMP folder but i can't figure out how to do that yet either.

c.pfaffenbichler
Community Expert
Community Expert
March 28, 2023

 

quote

I also need to understand how to only search an move root level layers and folders. I will have a situation with duplicate names inside groups which using the current script get moved out of their subfolders within COMP and end up directly inside the FINAL folder therefore breaking the structure

You can either amend the function collectLayersByNames to disregard Layers and Groups in Groups or revert back to a DOM-approach. 

quote

The line 

moveLayerTo(theLayers[i][2], finalId);

moves one Layer (identified by its Identifier) in front of another (identified by Index). 

 

quote

I also need to understand how to only search an move root level layers and folders. I will have a situation with duplicate names inside groups which using the current script get moved out of their subfolders within COMP and end up directly inside the FINAL folder therefore breaking the structure

You can either amend the function collectLayersByNames to disregard Layers and Groups in Groups or revert back to a DOM-approach. 


By @c.pfaffenbichler

Sorry to be a pain but i can't read it, the DOM-approach wouldn't move groups so i can't go back to that.

I can see the function collectLayerByNames is split with comments

// get number of layers;
// process the layers;
// if group collect values;

Do i need to comment out something below one of these sections?

 


No, in AM code Groups aren’t parental to their filial Layers so much as they enclose them; so one would need to track the »layerSectionStart«-Layers against the »layerSectionEnd«-Layers and only collect the Layers and Groups at a »depth« of 0. 

 

A bit of a hassle but certainly doable with an Integer as a variable that is additionally used in the if-clause (for example). 

Start with 0, for every layerSectionStart add 1, for every layerSectionEnd subtract 1 and only push a Layer/Group’s [theName, theIndex, theID] to the Array if the number is equal to 0.