Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

How to *smoothly* add keywords to several non-indentically tagged pics?

Participant ,
Nov 23, 2018 Nov 23, 2018

Hello, tagging with keywords in Bridge CC (preferred over Lightroom Classic), I often want to add one more keyword to several images in a row that already have various non-identical keywords. I want to add the new keyword(s) so that the existing keywords remain there and are not replaced, but added-to. I think LR has a specific field to type keywords into; they will be added to selected images, but existing keywords remain.

Example:

Image A:

Existing keyword 1: beach

Existing keyword 2: sunset

Image B:

Existing keyword 1: street

Existing keyword 2: traffic light

Both images should receive the new keyword icecream, while the existing, non-identical keywords remain in-image. But when I select both images in Bridge, open "File Info" (translating menu commands here from other language) and type the new keywords, the old keywords are lost. I believe only LR has the small box that accepts keywords as additions, not replacements.

I found these ways to add – not replace – keywords to several selected images in one go in Bridge, but none is totally satisfactory:

  1. 1. way: In Keywords panel, right-click on Other Keywords, add a new keyword, select your images and click into the desired keyword's check-box in the Keywords panel.
  2. 2. way: Select only one image, open File Info, type the new keywords in, the existing ones will remain, and close. Wait (patiently) until the fresh keywords appear in the Keywords panel, select the other images and click into the keyword's check-box in the Keywords panel.
  3. 3. way: For more often used (groups of) keywords, create metadata templates. They can be easily applied to selected images by menu command Add Metadata (not Replace Metadata)
  4. 4. way: For rarer keywords, create a generic metadata template called "1 metadata" (so it's alphabetically on top), fill it with your keywords du jour, save, select images, apply.

I am also aware of hierachical keywords and of importing tabbed text files as keywords. But I use many keywords and I am a fast and safe typer. On the other hand, my Keywords panel gets way too long very quickly, even if I empty it all the time; I don't like to use it. My list of metadata templates has grown too long too, but you can easily clean up by moving or deleting some xmp files.

Do you know a smoother way how to rapid-add keywords to several, already non-identically tagged images in Bridge?

  Thanks!

5.6K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

Community Expert , Nov 23, 2018 Nov 23, 2018

I just tested and It works in CC2019 on Windows… Although the script would need adjustment for nicer GUI colours!

 

It is not too complicated, copy the following 194 lines of source code and paste into a plain text editor like TextEdit.app or Notepad.exe, and save the file with a .jsx extension rather than .txt:

 

// https://stackoverflow.com/questions/47797219/edit-script-for-editing-metadata-in-adobe-bridge-how-should-i-put-key-words
#target bridge

   if( BridgeTalk.appName == "bridge" ) {
ke
...
Translate
Community Expert ,
Nov 23, 2018 Nov 23, 2018

I’m not having much luck with this one, however it probably just needs adjustment to work with later versions:

https://stackoverflow.com/questions/47797219/edit-script-for-editing-metadata-in-adobe-bridge-how-sh...

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 23, 2018 Nov 23, 2018

Stephen, thanks.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 23, 2018 Nov 23, 2018

Your welcome… but does it work?

The OK or Cancel buttons don’t do anything for me in Bridge CS6 or CC2018, so it is not possible to apply the new common keyword.

I forgot to add the following to my original reply:

Prepression: Downloading and Installing Adobe Scripts

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 23, 2018 Nov 23, 2018

Stephen, i did not try this. It is too complicated for me - more so when you tell me before it might not work.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 23, 2018 Nov 23, 2018

I just tested and It works in CC2019 on Windows… Although the script would need adjustment for nicer GUI colours!

 

It is not too complicated, copy the following 194 lines of source code and paste into a plain text editor like TextEdit.app or Notepad.exe, and save the file with a .jsx extension rather than .txt:

 

// https://stackoverflow.com/questions/47797219/edit-script-for-editing-metadata-in-adobe-bridge-how-should-i-put-key-words
#target bridge

   if( BridgeTalk.appName == "bridge" ) {
keyReplace = MenuElement.create("command", "Add-Replace-Remove Keyword", "at the end of tools");
}
keyReplace.onSelect = function () {
      mainReplaceKeyword();
      }

function mainReplaceKeyword(){
if(app.version.substr(0,app.version.indexOf('.'))==1){
alert("Sorry You Need CS3 or CS4 to run this script!");
return;
    }
var dlg =
"dialog{text:'Script Interface',bounds:[100,100,500,310],"+
"panel0:Panel{bounds:[10,10,390,200] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"title:StaticText{bounds:[60,10,350,40] , text:'Add/Replace/Remove Keyword' ,properties:{scrolling:undefined,multiline:undefined}},"+
"panel1:Panel{bounds:[10,40,370,150] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"addKey:Checkbox{bounds:[20,10,160,31] , text:'Add Keyword' },"+
"statictext1:StaticText{bounds:[20,40,119,60] , text:'Replace' ,properties:{scrolling:undefined,multiline:undefined}},"+
"From:EditText{bounds:[120,40,350,60] , text:'' ,properties:{multiline:false,noecho:false,readonly:false}},"+
"statictext2:StaticText{bounds:[20,80,90,97] , text:'With' ,properties:{scrolling:undefined,multiline:undefined}},"+
"To:EditText{bounds:[120,80,350,100] , text:'' ,properties:{multiline:false,noecho:false,readonly:false}}},"+
"button0:Button{bounds:[10,160,180,181] , text:'Ok' },"+
"button1:Button{bounds:[200,160,370,181] , text:'Cancel' }}};";
var win = new Window(dlg,"Replace Keyword");
win.center();

win.panel0.title.graphics.font = ScriptUI.newFont("Times","BOLDITALIC",20);
g = win.graphics;
b=win.panel0.title.graphics;
var myBrush = g.newBrush(g.BrushType.SOLID_COLOR, [0.99, 0.99, 0.20, 1]);
g.backgroundColor = myBrush;
var myPen =b.newPen (g.PenType.SOLID_COLOR, [0.00, 0.00, 0.99, 1],lineWidth=1);
var myPen2 =b.newPen (g.PenType.SOLID_COLOR, [0.99, 0.00, 0.00, 1],lineWidth=1);
g.foregroundColor = myPen;
b.foregroundColor = myPen2;
win.panel0.panel1.From.active=true;
win.panel0.panel1.addKey.onClick = function() {
if(win.panel0.panel1.addKey.value) {
    win.panel0.panel1.statictext1.text = "New Keyword";
    win.panel0.panel1.From.active=true;
    win.panel0.panel1.statictext2.visible=false;
    win.panel0.panel1.To.visible=false;
    }
if(!win.panel0.panel1.addKey.value) {
    win.panel0.panel1.statictext1.text = "Replace";
    win.panel0.panel1.statictext2.visible=true;
    win.panel0.panel1.To.visible=true;
    win.panel0.panel1.From.active=true;
    }
}
win.center();
var done = false;
    while (!done) {
      var x = win.show();
      if (x == 0 || x == 2) {
        win.canceled = true;
        done = true;
      } else if (x == 1) {
        done = true;
       var result = valiDate();
        if(result != true) {
            alert(result);
            return;
        }else{
            var Replace = win.panel0.panel1.From.text;
            var With = win.panel0.panel1.To.text;
            var addKey = win.panel0.panel1.addKey.value;
            processKeyword(Replace,With,addKey);
        }
      }
   }

function valiDate(){
    if(win.panel0.panel1.From.text =='') return "No Keyword Entered!";
return true;
}
function processKeyword(Replace,Witha,ddKey){
try{
loadXMPScript();
}catch(e){
alert("Can not load XMPScript\r" + e.message);
    }

var items = app.document.selections;
  for (var i = 0; i < items.length; i++){
      var file=new Thumbnail(items[i]);
try{
var xmpFile = new XMPFile(file.path, XMPConst.UNKNOWN,XMPConst.OPEN_FOR_UPDATE);
}catch(e){
        alert("Problem opening xmp for update:-\r" + file.path +"\r" +e.message);
        return;
    }
try{
var xmp = xmpFile.getXMP();
}catch(e){
        alert("Problem opening xmp data:-\r"  + e.message);
        return;
    }
try{
var tmpCount =  xmp.countArrayItems(XMPConst.NS_DC, "subject");
}catch(e){
    alert("Cannot get count \r" + e.message);
    }
            if(addKey){
                xmp.appendArrayItem(XMPConst.NS_DC, "subject", Replace, 0,XMPConst.ARRAY_IS_ORDERED);
                }
if(tmpCount >0 && !addKey){
        for (var a =0;a<tmpCount;a++){
            var     Keyword = xmp.getArrayItem(XMPConst.NS_DC,'subject', a+1);
            if(Keyword == Replace && With == '') {
                xmp.deleteArrayItem(XMPConst.NS_DC,'subject', a+1);
                }
            if(Keyword == Replace && With != ''){
                xmp.setArrayItem(XMPConst.NS_DC,'subject', a+1,With);
                }
        }
}

if (xmpFile.canPutXMP(xmp)) {
xmpFile.putXMP(xmp);
}else{
alert(e.message);
    }
xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
}
unloadXMPScript();
}
}

function loadXMPScript()
{
    var results = new XMPLibMsg("XMPScript Library already loaded", 0, false);

    if (!ExternalObject.AdobeXMPScript)
    {
        try
        {
            ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
            results.message = "XMPScript Library loaded";
        }
        catch (e)
        {
            alert("Could not load AdobeXMPScript \r" + e.message);
            results.message = "ERROR Loading AdobeXMPScript: " + e;
            results.line = e.line;
            results.error = true;
        }
    }

    return results;
}
function unloadXMPScript()
{
    var results = new XMPLibMsg("XMPScript Library not loaded", 0, false);

    if( ExternalObject.AdobeXMPScript )
    {
        try
        {
            ExternalObject.AdobeXMPScript.unload();
            ExternalObject.AdobeXMPScript = undefined;
            results.message = "XMPScript Library successfully unloaded";
        }
        catch (e)
        {
            results.message = "ERROR unloading AdobeXMPScript: " + e;
            results.line = e.line;
            results.error = true;
        }
    }

    return results;
}
function XMPLibMsg (inMessage, inLine, inError)
{
    this.message = inMessage;
    this.line = inLine;
    this.error = inError;
}

 

Then:

 

  1. Open Adobe Bridge, then open Bridge’s preferences dialog
  2. Under Startup Scripts - click the "Reveal My Startup Scripts" button
  3. Copy/Paste or drag-n-drop your .jsx script files into the folder/directory
  4. Quit and restart Bridge and answer "Yes" to enable the script.

 

The script will be available under the Tools menu as "Add-Replace-Remove Keyword”.

 

add-replace-keyword-script.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 24, 2018 Nov 24, 2018

Stephen, big thanks! It works! If only for one keyword at a time. Also thanks for the detailed 1-2-3 instruction, which was helpful in my case. It works as desired - it adds 1 keyword to several variously tagged images without removing existing keywords.

I don't mind the UI (here a little different from your screenshot), but i still have some quibbles:

  1. It seems i can add only one keyword at a time. When i separate keywords with comma or semicolon in the script's dialog, the whole line appears as one single keyword in the images. For instance, i type "ice cream, summer", the images show only 1 new keyword called "ice cream, summer". (Almost always i want to add more than one keyword per command, esp. as i tag bilingually.)
  2. Each time i want to add a keyword that way, i still have to 1) click "Tools > Add-Replace-Remove Keyword", then 2) click "Add" in the dialog, because the dialog always comes up in Replace mode, not in Add mode. (I'd prefer an always-open panel with a field always ready to accept new keywords to to type into. It should be on top of the Keywords panel. Maybe i still have to use LR for that.)

It's also nice to have keyword replacing function here in the script you recommended, say after a typo. Replacing was already possible in Bridge, but it's easier with the script. It would also be nice to replace one keyword with two keywords, say replace "summer" with "summer, holidays" (as two different keywords), but i guess this doesn't work. Not adding or replacing more than one keyword at a time is a severe restriction. Should you hear about a new script version adding more than 1 keyword per go, I'd be interested.

Anyway, thanks again for your very clear instructions and i certainly will use this script sometimes - if not as often as hoped for.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 24, 2018 Nov 24, 2018

As a hack, I have another Bridge script that will separate a single string of keywords separated by a comma into separate individual keywords, removing the commas.

It is rare to find a script that is perfectly written for your use when it was made by somebody else for their use. The thing about scripting is that they can be changed, you just need to know how or find somebody willing to help. I’m just starting out at scripting, however I am finding Bridge and Acrobat to be much harder than Photoshop/Illustrator/InDesign.

If you are willing to step outside of Bridge, I can introduce you to ExifTool command line code that will allow you to append multiple keywords. Depending on whether you are Mac or Win based, there are some pretty easy methods to set up the code so that it can be more easily applied, for example using a GUI or drag-n-drop etc.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 24, 2018 Nov 24, 2018

Stephen, thanks. I'd certainly be interested in the hack that adds more than one keyword within Bridge. Separating them by comma is very natural (better than semicolon or blank space).

I have Win 10 with the current Bridge CC. If in that hack you could make the dialogue *start* with the Add function instead of starting with the Replace function, that would be the icing on the cake (so no extra click on "Add" would be needed). I noted that in my localized version, i can open the dialog not only with mouseclicks in the Tools menu, but also by typing Alt-W-A. Would love to have that on an F key (for instance F4) or as a button

Thanks, I'm aware of other IPTC editors incl. Exiftool, FastPhotoTagger etc. etc., and i have some of them, even super-oldie ThumbsPlus (which easily adds 1 or more keywords to several differently tagged images without wiping out existing tags), but i like Bridge for the way it displays and deals with thumbnails and full screen previews. It's also really fast.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 24, 2018 Nov 24, 2018

Henrik,

 

The script I have to separate keywords is not working in CS6/CC18/CC19 when I know it used to...

 

// https://forums.adobe.com/thread/2415320
#target bridge
if (BridgeTalk.appName == "bridge") {
    sepkeys = MenuElement.create("command", "Seperate Keywords", "at the end of Tools");
}
sepkeys.onSelect = function () {
    var thumbs = app.document.selections;
    if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
    var FolderName = decodeURI(Folder(app.document.presentationPath).name);
    for (var a = 0; a < thumbs.length; a++) {
        var selectedFile = new Thumbnail(thumbs[a]);
        app.synchronousMode = true;
        var xmp = new XMPMeta(selectedFile.synchronousMetadata.serialize());
        var keys = getArrayItems(XMPConst.NS_DC, "subject");
        if (keys.length == 1) {
            xmp.deleteProperty(XMPConst.NS_DC, 'subject');
            keys = keys[0].toString().replace(/"/g, '').split(",");
            for (var k in keys) {
                xmp.appendArrayItem(XMPConst.NS_DC, "subject", keys[k].toString(), 0, XMPConst.PROP_IS_ARRAY);
            }
            var newPacket = xmp.serialize(XMPConst.SERIALIZE_USE_COMPACT_FORMAT);
            selectedFile.metadata = new Metadata(newPacket);
        }
    }
    ExternalObject.AdobeXMPScript.unload();
    ExternalObject.AdobeXMPScript = undefined;

    function getArrayItems(ns, prop) {
        var arrItem = [];
        var items = xmp.countArrayItems(ns, prop);
        for (var i = 1; i <= items; i++) {
            arrItem.push(xmp.getArrayItem(ns, prop, i));
        }
        return arrItem;
    };
};

 

Or perhaps this version:

 

// https://forums.adobe.com/thread/2415320
// https://forums.adobe.com/message/10658929#10658929
// break each keyword separated by a space into a separate keyword separated by a comma
#target bridge
if (BridgeTalk.appName == "bridge") {
    sepkeys = MenuElement.create("command", "Seperate Keywords v2", "at the end of Tools");
}
sepkeys.onSelect = function () {
    var thumbs = app.document.selections;
    if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");
    var FolderName = decodeURI(Folder(app.document.presentationPath).name);
    for (var a = 0; a < thumbs.length; a++) {
        var selectedFile = new Thumbnail(thumbs[a]);
        app.synchronousMode = true;
        var xmp = new XMPMeta(selectedFile.synchronousMetadata.serialize());
        var keys = getArrayItems(XMPConst.NS_DC, "subject");
        if (keys.length == 1) {
            xmp.deleteProperty(XMPConst.NS_DC, 'subject');
            keys = keys[0].toString().replace(/ /g, ',').split(",");
            for (var k in keys) {
                xmp.appendArrayItem(XMPConst.NS_DC, "subject", keys[k].toString(), 0, XMPConst.PROP_IS_ARRAY);
            }
            var newPacket = xmp.serialize(XMPConst.SERIALIZE_USE_COMPACT_FORMAT);
            selectedFile.metadata = new Metadata(newPacket);
        }
    }
    ExternalObject.AdobeXMPScript.unload();
    ExternalObject.AdobeXMPScript = undefined;

    function getArrayItems(ns, prop) {
        var arrItem = [];
        var items = xmp.countArrayItems(ns, prop);
        for (var i = 1; i <= items; i++) {
            arrItem.push(xmp.getArrayItem(ns, prop, i));
        }
        return arrItem;
    };
};
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 24, 2018 Nov 24, 2018

Stephen, thanks for trying anyway. Maybe someone else has a solution.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 27, 2018 Nov 27, 2018

Stephen, just a follow-up. I occasionally used the script when i wanted to add 1 or 2 keywords to a larger number of all differently tagged images (in that situation it's one of the easiest ways compared to Bridge's own ways, in theory). I noted that sometimes the script doesn't work - after clicking "OK", it just does nothing, without producing any error message. There is no Bridge activity in the status frame noticeable (unlike when actually keywords *are* written to file, the file names appear in the status frame in rapid succession). This does not depend on the number of files selected.

Then again, sometimes it works. But it's not reliable, and you have to have sharp eyes (depending on your personal UI and eyesight) to even detect if the script *did* add the tags or not. I can't pin down when it fails. Somehow it feels as if the script usually did work shortly after opening Bridge and got less reliable an hour or 2 into a session. But i'm not really sure about that.

I never tried the replacing feature, only the adding feature.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 27, 2018 Nov 27, 2018

This would leave ExifTool as the only reliable alternative that I would recommend, however I did not previously mention it as you seem very particular about a “smooth workflow” and this may not be considered that smooth by you… For example:

 

exiftool -overwrite_original -sep "," -subject+="keyword1,keyword2,keyword3" -r *

 

You would just need to update the multiple common keywords as indicated in blue in-between the double quotes (Mac users would use single quotes rather than double quotes in all places).

 

Although known as a CLI tool and not GUI, it is easy enough to incorporate the ExifTool CLI code into a more “user friendly” wrapper. It will depend on whether you are Mac or Win OS based on how you may approach this task. For example, you could drag-n-drop selected files from a non-maximised Bridge window onto a desktop icon to batch process them (leveraging Bridge’s browsing, sorting, filtering, collections etc).

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Participant ,
Nov 27, 2018 Nov 27, 2018

Stephen, thanks. Dragging the files from Bridge onto an EXIFTool icon sounds relatively reasonable, even though for now i'd prefer to stay within Bridge only and use the "workarounds" available there.

I still believe that LR solves my problem too, so i could also use that and might re-try it also (but find it much less "smooth" than Bridge otherwise).

Maybe someone sees this here and improves the script or maybe i'll dive into it myself, but probably not. If i should manage to alter the script to my plans, i'll certainly report here.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
New Here ,
Dec 21, 2021 Dec 21, 2021

Stephen,

Wonder if you still monitor this thread.  We're attempting to make the above script work and need a little guidance.

The Add/Remove/Remove Keyword dialog box appears.  But when we enter data and hit "OK", the pop-up disappears but nothing seems to happen.

 

We note that the URL: // https://stackoverflow.com/questions/47797219/edit-script-for-editing-metadata-in-adobe-bri is no longer active.  We cut-and-pasted the above, but note that our line count appears to be only 171.

 

We have tried this script in both Bridge 2019 and 2022

Winston

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
LEGEND ,
Dec 21, 2021 Dec 21, 2021

I haven't tested this script, just be sure it is complete. Beyond that you may need to debug it since Adobe has made changes to how some older scripts work.

I personally do everything in the Keyword panel, File Info is not reliable unfortunately.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Dec 21, 2021 Dec 21, 2021

I found a few problems with the script:

 

OLD: function processKeyword(Replace,Witha,ddKey){

NEW: function processKeyword(Replace,With,addKey){

 

OLD: var file=new Thumbnail(items);

NEW: var file=new Thumbnail(items[i]);

 

OLD: xmp.appendArrayItem(XMPConst.NS_DC, "subject", Replace, 0,XMPConst.ARRAY_IS_ORDERED);

NEW: xmp.appendArrayItem(XMPConst.NS_DC, "subject", Replace, 0,XMPConst.ARRAY_IS_UNORDERED);

 

After these changes, I think the script works, but it could use some improvements.

#target bridge
   if( BridgeTalk.appName == "bridge" ) {
keyReplace = MenuElement.create("command", "Add-Replace-Remove Keyword", "at the end of tools");
}
keyReplace.onSelect = function () {
      mainReplaceKeyword();
      }
function mainReplaceKeyword(){
if(app.version.substr(0,app.version.indexOf('.'))==1){
alert("Sorry You Need CS3 or CS4 to run this script!");
return;
    }
var dlg =
"dialog{text:'Script Interface',bounds:[100,100,500,310],"+
"panel0:Panel{bounds:[10,10,390,200] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"title:StaticText{bounds:[60,10,350,40] , text:'Add/Replace/Remove Keyword' ,properties:{scrolling:undefined,multiline:undefined}},"+
"panel1:Panel{bounds:[10,40,370,150] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"addKey:Checkbox{bounds:[20,10,160,31] , text:'Add Keyword' },"+
"statictext1:StaticText{bounds:[20,40,119,60] , text:'Replace' ,properties:{scrolling:undefined,multiline:undefined}},"+
"From:EditText{bounds:[120,40,350,60] , text:'' ,properties:{multiline:false,noecho:false,readonly:false}},"+
"statictext2:StaticText{bounds:[20,80,90,97] , text:'With' ,properties:{scrolling:undefined,multiline:undefined}},"+
"To:EditText{bounds:[120,80,350,100] , text:'' ,properties:{multiline:false,noecho:false,readonly:false}}},"+
"button0:Button{bounds:[10,160,180,181] , text:'Ok' },"+
"button1:Button{bounds:[200,160,370,181] , text:'Cancel' }}};";
var win = new Window(dlg,"Replace Keyword");
win.center();
win.panel0.title.graphics.font = ScriptUI.newFont("Times","BOLDITALIC",20);
g = win.graphics;
b=win.panel0.title.graphics;
var myBrush = g.newBrush(g.BrushType.SOLID_COLOR, [0.99, 0.99, 0.20, 1]);
g.backgroundColor = myBrush;
var myPen =b.newPen (g.PenType.SOLID_COLOR, [0.00, 0.00, 0.99, 1],lineWidth=1);
var myPen2 =b.newPen (g.PenType.SOLID_COLOR, [0.99, 0.00, 0.00, 1],lineWidth=1);
g.foregroundColor = myPen;
b.foregroundColor = myPen2;
win.panel0.panel1.From.active=true;
win.panel0.panel1.addKey.onClick = function() {
if(win.panel0.panel1.addKey.value) {
    win.panel0.panel1.statictext1.text = "New Keyword";
    win.panel0.panel1.From.active=true;
    win.panel0.panel1.statictext2.visible=false;
    win.panel0.panel1.To.visible=false;
    }
if(!win.panel0.panel1.addKey.value) {
    win.panel0.panel1.statictext1.text = "Replace";
    win.panel0.panel1.statictext2.visible=true;
    win.panel0.panel1.To.visible=true;
    win.panel0.panel1.From.active=true;
    }
}
win.center();
var done = false;
    while (!done) {
      var x = win.show();
      if (x == 0 || x == 2) {
        win.canceled = true;
        done = true;
      } else if (x == 1) {
        done = true;
       var result = valiDate();
        if(result != true) {
            alert(result);
            return;
        }else{
            var Replace = win.panel0.panel1.From.text;
            var With = win.panel0.panel1.To.text;
            var addKey = win.panel0.panel1.addKey.value;
            processKeyword(Replace,With,addKey);
        }
      }
   }
function valiDate(){
    if(win.panel0.panel1.From.text =='') return "No Keyword Entered!";
return true;
}
function processKeyword(Replace,With,addKey){
try{
loadXMPScript();
}catch(e){
alert("Can not load XMPScript\r" + e.message);
    }
var items = app.document.selections;
  for (var i = 0; i < items.length; i++){
      var file=new Thumbnail(items[i]);
try{
var xmpFile = new XMPFile(file.path, XMPConst.UNKNOWN,XMPConst.OPEN_FOR_UPDATE);
}catch(e){
        alert("Problem opening xmp for update:-\r" + file.path +"\r" +e.message);
        return;
    }
try{
var xmp = xmpFile.getXMP();
}catch(e){
        alert("Problem opening xmp data:-\r"  + e.message);
        return;
    }
try{
var tmpCount =  xmp.countArrayItems(XMPConst.NS_DC, "subject");
}catch(e){
    alert("Cannot get count \r" + e.message);
    }
            if(addKey){
                xmp.appendArrayItem(XMPConst.NS_DC, "subject", Replace, 0,XMPConst.ARRAY_IS_UNORDERED);
                }
if(tmpCount >0 && !addKey){
        for (var a =0;a<tmpCount;a++){
            var     Keyword = xmp.getArrayItem(XMPConst.NS_DC,'subject', a+1);
            if(Keyword == Replace && With == '') {
                xmp.deleteArrayItem(XMPConst.NS_DC,'subject', a+1);
                }
            if(Keyword == Replace && With != ''){
                xmp.setArrayItem(XMPConst.NS_DC,'subject', a+1,With);
                }
        }
}
if (xmpFile.canPutXMP(xmp)) {
xmpFile.putXMP(xmp);
}else{
alert(e.message);
    }
xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
}
unloadXMPScript();
}
}
function loadXMPScript()
{
    var results = new XMPLibMsg("XMPScript Library already loaded", 0, false);
    if (!ExternalObject.AdobeXMPScript)
    {
        try
        {
            ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
            results.message = "XMPScript Library loaded";
        }
        catch (e)
        {
            alert("Could not load AdobeXMPScript \r" + e.message);
            results.message = "ERROR Loading AdobeXMPScript: " + e;
            results.line = e.line;
            results.error = true;
        }
    }
    return results;
}
function unloadXMPScript()
{
    var results = new XMPLibMsg("XMPScript Library not loaded", 0, false);
    if( ExternalObject.AdobeXMPScript )
    {
        try
        {
            ExternalObject.AdobeXMPScript.unload();
            ExternalObject.AdobeXMPScript = undefined;
            results.message = "XMPScript Library successfully unloaded";
        }
        catch (e)
        {
            results.message = "ERROR unloading AdobeXMPScript: " + e;
            results.line = e.line;
            results.error = true;
        }
    }
    return results;
}
function XMPLibMsg (inMessage, inLine, inError)
{
    this.message = inMessage;
    this.line = inLine;
    this.error = inError;
}
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 25, 2022 Aug 25, 2022

@gregreser Hi, are you still around for one quick question sir? 🙂

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Aug 25, 2022 Aug 25, 2022

@Niksha I'm ready, but nervous 🙂

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 25, 2022 Aug 25, 2022

Hahaha, it's nothing scary 😁 I saw that you did some changes on this adobe bridge script and it works, but i am wondering can you help me about one more change? When i add new keywords they appear with " mark at the begging and end. For example if i add cat, dog, bird they will appear like this "cat, dog, bird " and then i would need to delete ". 

 

Can it be changed so the script doesn't add "?

 

Thanks

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Aug 25, 2022 Aug 25, 2022

I think that would be easy. How attatched are you to the bright yellow color of that script?

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 26, 2022 Aug 26, 2022

It's ugly AF but as long as it doing the job I don't mind the colors 😄

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Aug 26, 2022 Aug 26, 2022

Here's a modified version. Look for "Add-Replace Keywords" in the Tools menu

To add multiple keywords, separate them with a semicolon: cat;dog;bird  (you can also use semicolon+space cat; dog; bird)

 

 

#target bridge

/*
Terms and Conditions of Use:
MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

//Create a menu item within Adobe Bridge
if (BridgeTalk.appName == 'bridge') {
    var projectName3 = "Add-Replace Keywords"
    var plgnVers = "1.0.0";
    var codeVers = "2022-08-26";
keyAddReplace = MenuElement.create("command", projectName3, "at the end of tools");
}
// when the menu item is clicked, run the script
keyAddReplace.onSelect = function () {
    mainReplaceKeyword();
    }
    
function mainReplaceKeyword(){
     // Load the XMP Script library
    if ( ExternalObject.AdobeXMPScript == undefined ) {
        ExternalObject.AdobeXMPScript = new ExternalObject( "lib:AdobeXMPScript" );
        }

    // PALETTE
    // =======
    var palette = new Window("palette"); 
        palette.text = projectName3+" ("+codeVers+")"; 
        palette.orientation = "column"; 
        palette.alignChildren = ["center","top"]; 
        palette.spacing = 10; 
        palette.margins = 16; 

    var statictext1 = palette.add("statictext", undefined, undefined); 
        statictext1.text = "Edit Keywords"; 

    // GROUP1
    // ======
    var group1 = palette.add("group", undefined); 
        group1.orientation = "row"; 
        group1.alignChildren = ["left","center"]; 
        group1.spacing = 10; 
        group1.margins = 0; 

    var radiobutton1 = group1.add("radiobutton", undefined, undefined); 
        radiobutton1.text = "Add"; 
        radiobutton1.value = true; 

    var radiobutton2 = group1.add("radiobutton", undefined, undefined); 
        radiobutton2.text = "Replace"; 
    /*
    var radiobutton3 = group1.add("radiobutton", undefined, undefined); 
        radiobutton3.text = "Clear"; 
    */
    // PANEL1
    // ======
    var panel1 = palette.add("panel", undefined, undefined); 
        panel1.orientation = "column"; 
        panel1.alignChildren = ["left","top"]; 
        panel1.spacing = 2; 
        panel1.margins = 10; 

    // GROUP2
    // ======
    var group2 = panel1.add("group", undefined); 
        group2.orientation = "row"; 
        group2.alignChildren = ["left","center"]; 
        group2.spacing = 10; 
        group2.margins = 0; 

    var statictext2 = group2.add("statictext", undefined, undefined); 
        statictext2.text = "Add"; 
        statictext2.preferredSize.width = 60; 
        statictext2.justify = "right"; 

    var edittext1 = group2.add('edittext {properties: {name: "edittext1"}}'); 
        edittext1.preferredSize.width = 250;
        edittext1.helpTip = 'Bridge separates keywords with a semi-colon ;\nA keyword phrase can contain a comma and more than one word'; // \nA keyword phrase containing a comma will use quotes "Paris, France"

    // PANEL1
    // ======
    var statictext3 = panel1.add("statictext", undefined, undefined); 
        statictext3.text = "separate multiple keywords with semicolons (;)"; 
        statictext3.indent = 70;

    // GROUP3
    // ======
    var group3 = panel1.add("group", undefined); 
        group3.orientation = "row"; 
        group3.alignChildren = ["left","center"]; 
        group3.spacing = 10; 
        group3.margins = 0; 

    var statictext4 = group3.add("statictext", undefined, undefined); 
        statictext4.text = "With"; 
        statictext4.preferredSize.width = 60; 
        statictext4.justify = "right"; 

    var edittext2 = group3.add('edittext {properties: {name: "edittext2"}}'); 
        edittext2.preferredSize.width = 250; 

    var statictext5 = panel1.add("statictext", undefined, undefined); 
        statictext5.text = "leave blank to delete keyword"; 
      //  statictext5.alignment = ["right","top"]; 
        statictext5.indent = 70;

    var statictext6 = palette.add("statictext", undefined, undefined, {multiline: true}); 
    statictext6.preferredSize.width = 300; 
    statictext6.preferredSize.height = 30;
    statictext6.justify = "center"; 
    statictext6.graphics.font = ScriptUI.newFont ("Helvetica", "Bold", 12);
    statictext6.graphics.foregroundColor = statictext6.graphics.newPen (statictext6.graphics.PenType.SOLID_COLOR, [0, 0.7, 0], 1);
    
    // GROUP4
    // ======
    var group4 = palette.add("group", undefined); 
        group4.orientation = "row"; 
        group4.alignChildren = ["left","top"]; 
        group4.spacing = 40; 
        group4.margins = 0; 

    var ok = group4.add("button", undefined, undefined); 
        ok.text = "Add"; 
        ok.preferredSize.width = 150;
        ok.preferredSize.height = 30;

    var cancel = group4.add("button", undefined, undefined); 
        cancel.text = "Done"; 

    // open window and set view to Add Keyword
    statictext2.text = "Add"; 
    group3.visible = false;
   // statictext3.visible = true;
    statictext3.text = "separate multiple keywords with semicolons (;)";
    statictext5.visible=false;
    palette.show();

    // Dialog functions 
    if(app.document.selections.length == 0){
        ok.enabled = false;
        statictext6.text = "No file(s) selected. 'Done' then try again"
        };
    
    radiobutton1.onClick = function(){
        group2.visible = true;
        statictext2.text = "Add"; 
        edittext1.text = "";
        edittext2.text = "";
        group3.visible = false;
       // statictext3.visible = true;
        statictext3.text = "separate multiple keywords with semicolons (;)"
        statictext5.visible=false;
        ok.text = "Add"
        }

    radiobutton2.onClick = function(){
        group2.visible = true;
        statictext2.text = "Replace";
        edittext1.text = "";
        edittext2.text = "";
        group3.visible = true;
      //  statictext3.visible = false;
        statictext3.text = "keyword item/phrase exact match";
        statictext5.visible=true;
        ok.text = "Replace"
        }
    /*
        radiobutton3.onClick = function(){
        group2.visible = false;
        group3.visible = false;
        statictext3.visible = true;
        statictext3.text = "Click 'Edit' to clear all keywords";
        statictext5.visible=false;
        }
    */
    // clear result text when edittext1 is clicked
    edittext1.addEventListener ("focus", function (e){statictext6.text = ""});
    
    ok.onClick = function processKeyword(){
        var Replace = edittext1.text.split('\"').join("");
        var With = edittext2.text.split('\"').join("");
     //   With.split('\"').join(""); // remove quotes used for keyword phrase containing a comma
        var addKey = radiobutton1.value;
        var items = app.document.selections;
        if(items.length > 1){var fileTxt = "files"};
        else{var fileTxt = "file";}
        
      //  if(items.length == 0){alert("No item(s) selected. Close and try again."); statictext6.text = "No item(s) selected"};
        if(Replace.length == 0){alert("No keyword entered")};
        if(Replace.length > 0 && items.length > 0){
        /// write keywords to XMP
        for (var i = 0; i < items.length; i++){
            var file=new Thumbnail(items[i]);
            try{
            var xmpFile = new XMPFile(file.path, XMPConst.UNKNOWN,XMPConst.OPEN_FOR_UPDATE);
            }catch(e){
                    alert("Problem opening xmp for update:-\r" + file.path +"\r" +e.message);
                    return;
                }
            try{
            var xmp = xmpFile.getXMP();
            }catch(e){
                    alert("Problem opening xmp data:-\r"  + e.message);
                    return;
                }
            try{
            var tmpCount =  xmp.countArrayItems(XMPConst.NS_DC, "subject");
            }catch(e){
            alert("Cannot get count \r" + e.message);
            }
                if(addKey){
                  // split keywords separated by semicolon into an array (handle either "; " or ";")
                    var splitKeys = Replace.split('; ').join(';').split (';');
                    var keyTxt = " keyword";
                    if(splitKeys.length > 1){keyTxt = " keywords"};
                    for (var L1 = 1; L1 < (splitKeys.length + 1); L1++){
                        xmp.appendArrayItem(XMPConst.NS_DC, "subject", splitKeys[L1 - 1], 0, XMPConst.ARRAY_IS_UNORDERED);
                        }
                    statictext6.text = splitKeys.length+keyTxt+" added to "+items.length+" "+fileTxt; 
                    }
            if(tmpCount >0 && !addKey){
                var matchFound = 0;
                    for (var a =0;a<tmpCount;a++){
                        var     Keyword = xmp.getArrayItem(XMPConst.NS_DC,'subject', a+1);
                        if(Keyword == Replace && With == '') {
                            matchFound++
                            xmp.deleteArrayItem(XMPConst.NS_DC,'subject', a+1);
                            }
                        if(Keyword == Replace && With != ''){
                            matchFound++
                            xmp.setArrayItem(XMPConst.NS_DC,'subject', a+1,With);
                            }
                    }
                if(matchFound == 0){
                    //alert("'Replace' value was not found. No changes made.")
                    statictext6.text = "'"+Replace+ "' not found. No replacement made"; 
                    }
                else{
                    var matchTxt = " replacement";
                    if(matchFound > 1){matchTxt = " replacements"};
                    statictext6.text = matchFound+matchTxt+" made to "+items.length+" "+fileTxt; 
                    }
            }
            if (xmpFile.canPutXMP(xmp)) {
            xmpFile.putXMP(xmp);
            }else{
            alert(e.message);
                }
            xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
            }
        } // CLOSE for (var i = 0; i < items.length; i++)
    }

    cancel.onClick = function(){
        palette.close();
        }

    }// CLOSE function mainReplaceKeyword()
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Explorer ,
Aug 26, 2022 Aug 26, 2022

Works like a charm, plus looks good now. 🙂 Thank you so much sir!

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Aug 26, 2022 Aug 26, 2022

You're very welcome.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines