Copy link to clipboard
Copied
I run a heritage website, and have a lot of image files that are uploaded onto that website. After uploading the image to the website it gets assigned an asset ID. I want a way to add that asset ID into the file name where our backup of files is stored.
From my heritage website I can extract a document with file names and asset IDs, so I think the easiest way is if I can get the asset ID added into the image metadata then I can used batch rename in Bridge to add this asset ID into the file name.
Is there a way in Bridge to bulk add unique values to the metadata of multiple files?
This would require a custom script. I have one that renames files from a CSV document. It works on all selected files in a single folder. You would have to generate a CSV that contains the current filename and the new file name.
If you are interested, I can share the script and help you with he process.
Here's an outline of the process:
In Bridge
- Select the files you want to rename
Open the script
- Click 'Create List'. This will save a CSV list of the current file names
In a spreadsheet
- O
Copy link to clipboard
Copied
This would require a custom script. I have one that renames files from a CSV document. It works on all selected files in a single folder. You would have to generate a CSV that contains the current filename and the new file name.
If you are interested, I can share the script and help you with he process.
Here's an outline of the process:
In Bridge
- Select the files you want to rename
Open the script
- Click 'Create List'. This will save a CSV list of the current file names
In a spreadsheet
- Open the CSV list of files
- Enter new the filenames in 'New File Name' column
- Save as CSV UTF8 text file (.csv)
In Bridge
- Open the script
- Specify the CSV file as the source
- Click 'Rename Files'
Copy link to clipboard
Copied
Hi there,
This sounds like a great solution, I would love if you could send me a copy of the script you use!
Copy link to clipboard
Copied
The script is still a work in progress. I've tested it and it works consistantly for me.
Let me know if you run into any problems or need help.
Things to know:
I tried to make the UI self-explanatory and there are instructions.
You must use the supplied CSV format. Do step 1 (export a list of your files). Only use the resulting spreadsheet columns.
The first column, "File Folder Path" must be included. It allows you to work with files visible when you set Bridge to "Show items from subfolders".
I separated out the file names and extensions to, hopefully, make it easier to see and edit.
You can change the file extension format (.JPG to .jpeg). There is a safeguard that prevents you from changing the file type.
Here is the code.
Copy the code text to the clipboard
Paste the code text into a plain-text editor (not in a word processor)
Save as a JavaScript file: rename_files_from_csv.jsx
Installation
Windows
- Go to Edit --> Preferences --> Startup Scripts
Mac:
- Go to Adobe Bridge --> Preferences --> Startup Scripts
Look for the menu "Metadata Deluxe" at the top of the Bridge window.
#target bridge
if (BridgeTalk.appName == '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.
*/
if(BridgeTalk.appName == 'bridge'){
// menu text
var mdMenu = "Metadata_Deluxe"; // computer friendly. filenames - don't use spaces, use _ example: Metadata_Deluxe
var mdMenuLabel = mdMenu.split("_").join(" ") // human friendly, replace _ with space
var RnfcsvMeI = "Rename Files From CSV";
var RnfcsvMeIVersion = "1.0.0";
var RnfcsvMeICodeDate = "2023-02-28";
//Create a menu option within Adobe Bridge
var findMdMenu = MenuElement.find (mdMenu);
if (findMdMenu == null){
var addMdMenu = new MenuElement ('menu', mdMenuLabel, 'before Help', mdMenu);
}
var RnfcsvMenuExpImp = new MenuElement ('command', RnfcsvMeI, 'at the beginning of '+mdMenu);
RnfcsvMenuExpImp.onSelect = function(){runRnfcsv()};
/* enable after debugging
try{
// create menu item in Tools
var Rnfcsv = MenuElement.create('command', 'Rename Files From CSV', 'at the end of Tools');
Rnfcsv.onSelect = function(){runRnfcsv()};
}
catch(e){
alert(e + ' ' + e.line);
}
*/
}
function runRnfcsv(){
try{
// folder and file location variables
if (Folder.fs == "Windows"){
var slash = "\\";
}
else{
var slash = "/";
}
// Main windows
var dialog = new Window("palette", "Rename Files From CSV", undefined, {resizeable: true, closeButton:true});
dialog.minimumSize = [450,450];
dialog.orientation = "column";
dialog.alignChildren = ["fill","top"];
dialog.spacing = 20;
dialog.margins = 16;
var group1 = dialog.add("group", undefined);
group1.orientation = "row";
// group1.alignChildren = ["left","center"];
group1.spacing = 10;
group1.margins = 0;
/*
var statictext1 = group1.add("statictext", undefined, undefined, {name: "statictext1"});
statictext1.text = "Current folder: "+currentFolderPath;
*/
var instButton = group1.add("button", undefined, "Instructions");
instButton.alignment = ["right","top"];
instButton.onClick = showInst;
// instruction windows
function showInst(){
var instructionsText =
" In Bridge\n"+
" Select the files you want to rename\n" +
" Open the script\n"+
" Click 'Create List'. This will save a CSV list of the current file names\n\n" +
" In a spreadsheet\n"+
" Open the CSV list of files.\n"+
" If your filenames have special characters, import the list as UTF8\n" +
" Enter new the filenames in 'New File Name' column\n" +
" You can change New File Extension case and variation, i.e. .jpg = .jpeg = .JPG = .JPEG\n" +
" You cannot change New File Extension type, i.e. .jpg ≠ .tiff\n" +
" Save as CSV UTF8 text file (.csv)\n\n" +
" In Bridge\n"+
" Open the script\n"+
" Specify the CSV file as the source\n"+
" Click 'Rename Files'"
var instructions = new Window("palette", "Instructions");
ExportInstText = instructions.add("statictext", undefined, instructionsText, {multiline:true});
ExportInstText.minimumSize = [600,300];
ExportInstText.maximumSize = [600,300];
instructionsCancelBtn = instructions.add("button", undefined, "Close");
instructionsCancelBtn.onClick = function(){
instructions.hide();
instructions.close();
dialog.active = true;
}
instructions.show();
instructions.active = true;
}
// var spacer1 = dialog.add("statictext", undefined, "");
// spacer1.minimumSize = [20,20];
var panel1 = dialog.add("panel", undefined, "Step 1");
panel1.orientation = "column";
panel1.alignChildren = ["left","top"];
panel1.spacing = 5;
panel1.margins = 10;
var statictext3 = panel1.add("statictext", undefined, "Create CSV (Comma Separated Values) list of selected files and current names");
var button1 = panel1.add("button", undefined, "Create List");
button1.minimumSize = [140,40];
button1.alignment = ["center","top"];
button1.onClick = exportToFile;
var group2 = panel1.add("group", undefined);
group2.orientation = "row";
group2.alignChildren = ["left","center"];
group2.spacing = 10;
group2.margins = 0;
var statictext4 = group2.add("statictext", undefined, undefined);
statictext4.minimumSize = [350,20];
statictext4.text = "";
var panel2 = dialog.add("panel", undefined, "Step 2");
panel2.orientation = "column";
panel2.alignChildren = ["left","top"];
panel2.spacing = 10;
panel2.margins = 10;
var statictext6 = panel2.add("group");
statictext6.orientation = "column";
statictext6.alignChildren = ["left","center"];
statictext6.spacing = 0;
statictext6.add("statictext", undefined, "- Open the list of files in a spreadsheet");
statictext6.add("statictext", undefined, "- Enter new names in 'New File Name' column");
statictext6.add("statictext", undefined, "- Save as CSV UTF8 text file (.csv)");
var panel3 = dialog.add("panel", undefined, "Step 3");
panel3.orientation = "column";
panel3.alignChildren = ["left","top"];
panel3.spacing = 10;
panel3.margins = 10;
var statictext7 = panel3.add("statictext", undefined, "Rename files using CSV file");
var group3 = panel3.add("group", undefined);
group3.orientation = "row";
group3.alignChildren = ["left","center"];
group3.spacing = 10;
group3.margins = 0;
var edittext1 = group3.add("statictext", undefined, "browse for file");
edittext1.minimumSize = [320,25];
edittext1.justify = "right";
var button2 = group3.add("button", undefined, "Browse");
button2.onClick= getRenameFilePath;
var checkbox1 = panel3.add("checkbox", undefined, "Preserve current filename in XMP metadata");
checkbox1.alignment = "center";
checkbox1.value = true;
var button3 = panel3.add("button", undefined, "Rename Files");
button3.minimumSize = [120,40];
button3.alignment = ["center","top"];
button3.enabled = false;
button3.onClick = renameFiles;
var button4 = dialog.add("button", undefined, "Close");
button4.alignment = ["right","top"];
button4.onClick = closeWindow;
dialog.show(); // window is defined, now open it
// Functions
function closeWindow(){
dialog.close();
}
function exportToFile(){
var selectedFiles = app.document.selections;
if(selectedFiles.length == 0){
app.beep();
Window.alert("You must select at least one file");
return false
}
else{
// Open the Save dialog to choose a file name and directory for the export file
var dataExport = File.saveDialog("File List", "Comma separated:*.csv" );
// Create empty variables to store pass/fail data during export
var filePass = 0;
var fileFail = 0;
if (dataExport){
dataExport.encoding = "UTF8";
dataExport.open ("w", "TEXT", "ttxt"); // open text file so values can be written
dataExport.write ("File Folder Path,"); // write column header 1
dataExport.write ("Current File Name,"); // write column header 2
dataExport.write ("Current File Extension,"); // write column header 3
dataExport.write ("New File Name,"); // write column header 4
dataExport.write ("New File Extension"); // write column header 5
// dataExport.write ("Content Date Created,"); // original creation date
// dataExport.write ("File Date Created"); // file creation date
for (var L1 = 0; L1 < selectedFiles.length; L1++){
if(selectedFiles[L1].spec instanceof File){ // if selectedFiles is a file, we don't want to list folders
try{
/* other methods
var fileFullName = selectedFiles[L1].spec.fullName; // path and file name with UTF-8 encoded special characters
var filePath = selectedFiles[L1].spec.path; // just the file directory with UTF-8 encoded special characters
var filePathClean = Folder.decode(selectedFiles[L1].spec.path); // just the file directory showing spaces and other special characters
var fileName = selectedFiles[L1].spec.name; // just the file name with UTF-8 encoded special characters
var fileExtension = '.' + fileName.substr(fileName.lastIndexOf('.')+1);
var fileNameClean = File.decode(fileName); // just the file name showing spaces and other special characters
*/
var filePath = selectedFiles[L1].path; // directory and file name showing spaces and other special characters
var splicePathIndex1 = filePath.lastIndexOf (slash) // index of last "/"
var justDirectory = filePath.substr(0,splicePathIndex1+1); // just the file directory based on lastIndexOf ("\\")
var justFileName = selectedFiles[L1].name // just the file name showing spaces and other special characters
var fileNameExtensionIndex = justFileName.lastIndexOf ("."); // index of last "."
var fileName = justFileName.substr(0, fileNameExtensionIndex);
var fileNameExtension = justFileName.slice(fileNameExtensionIndex+1) // just the file extension based on lastIndexOf (".")
/* NOT IMPLEMENTED read DateTimeOriginal and DateCreated
var fileContentDateCreated = "";
if (selectedFiles[L1].hasMetadata){
var md = selectedFiles[L1].synchronousMetadata; // read embedded metadata
var xmp = new XMPMeta(md.serialize()); // read embedded XMP
var fileDateCreated = selectedFiles[L1].spec.created.getFullYear() // 2016-11-10T08:03:13-07:00
var x = new Date(); // get file date created and format to ISO
x = selectedFiles[L1].spec.created;
var YYYY = x.getFullYear();
var MM = x.getMonth();
if(MM < 10){MM = "0"+MM}
var DD = x.getDay();
if(DD < 10){DD = "0"+DD}
var TT = x.toTimeString(); // x.getHours()+":"+x.getMinutes()+":"+x.getSeconds();
TT = TT.split(" GMT").join("");
$.writeln(YYYY+"-"+MM+"-"+DD+"T"+TT)
var fileContentDateCreated = "";
var exifDateTimeOriginal = xmp.getProperty(XMPConst.NS_EXIF, "DateTimeOriginal"); // Exif Date Time Original
var psDateCreated = xmp.getProperty(XMPConst.NS_PHOTOSHOP, "DateCreated"); // IPTC (Photoshop) Date Created
if(exifDateTimeOriginal){
fileContentDateCreated = exifDateTimeOriginal;
}
if(psDateCreated){
fileContentDateCreated = psDateCreated;
}
}
*/
dataExport.write ("\r"); // write return to start file list
dataExport.write(justDirectory+","); // write image file path
dataExport.write(fileName+","); // write image file name
dataExport.write("."+fileNameExtension+","); // write image file extension
dataExport.write(","); // write empty value for new file name
dataExport.write("."+fileNameExtension); // write image file extension
// dataExport.write(fileContentDateCreated+","); // write content date created
// dataExport.write(YYYY+"-"+MM+"-"+DD+"T"+TT); // write file date created
filePass++;
}
catch(e){
fileFail++;
}
} // CLOSE if(selectedFiles instanceof File == true)
} // CLOSE for (var L1 = 0; L1 < selectedFiles.length; L1++)
dataExport.close(); // Close the exported text file
dialog.close();
// show completed message
alert("List of "+filePass+" files saved to: "+dataExport.fullName)
statictext4.text = "List save to "+dataExport.fullName;
edittext1.text = dataExport.fullName;
} // CLOSE if (dataExport)
} // CLOSE if(selectedFiles.length == 0) else
} // CLOSE function exportToFile()
// browse for CSV rename file path
function getRenameFilePath(){
var filePath = File.openDialog("File List", "Comma separated:*.csv,Comma separated:*.txt");
if(filePath){
edittext1.text = File.decode(filePath.fsName) // C:\Users\Computer User\Desktop\test.csv
button3.enabled = true;
}
}
// rename files
// TODO should the original filename be saved in case of a misnaming mistake? NS_XMP_MM mpMM:PreservedFileName
function renameFiles(){
var renamePass = 0;
var renameFail = [];
var writeXMPFail = [];
var textFileLoad = File.encode(edittext1.text); // data source text file
var textFileLoad = File (textFileLoad); // open the data text file
textFileLoad.open ('r');
var textFile = textFileLoad.read().split ('\n');
textFileLoad.close();
var textFileHeaders = textFile[0].split (","); // split first row by commas into currentName and newName column headers
if(checkbox1.value == true){ // if Preserve current filename is selected, load add needed XMP components
// Load the XMP Script library
if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
// register xmpMM namespace
var NS_XMP_MM = "http://ns.adobe.com/xap/1.0/mm/";
XMPMeta.registerNamespace (NS_XMP_MM, "xmpMM");
}
// validate CSV file before running rename
var csvFail = 0;
var csvProblem = [];
for (var L3 = 1; L3 < textFile.length; L3++){ // starting with the second row, split row by comma into currentName and newName column values
try{
if(textFile[L3].length > 0){ // make sure each row of textFile has data because Excel adds an empty row when it saves changes
var testTextFileRead = textFile[L3].split (",")
var testCurrentDirectory = testTextFileRead[0];
var testCurrentName = testTextFileRead[1];
var testCurrentExtension = testTextFileRead[2];
var testNewName = testTextFileRead[3];
var testNewExtension = testTextFileRead[4];
// Current File Name and New File Name have same file extension
var testCurrentExtension = testTextFileRead[2].toLowerCase().split("jpeg").join("jpg").split("tiff").join("tif");
var testNewExtension = testTextFileRead[4].toLowerCase().split("jpeg").join("jpg").split("tiff").join("tif");
// var testCurrentFile = testCurrentDirectory+testCurrentName
// var testCurrentExtensionIndex = testCurrentFile.lastIndexOf (".");
// var testCurrentExtension = testCurrentFile.slice(testCurrentExtensionIndex+1).toLowerCase().split("jpeg").join("jpg").split("tiff").join("tif");
// var testNewExtensionIndex = testNewName.lastIndexOf (".");
// var testNewExtension = testNewName.slice(testNewExtensionIndex+1).toLowerCase().split("jpeg").join("jpg").split("tiff").join("tif");
// has File Folder Path
if(!testCurrentDirectory){
csvFail++;
csvProblem.push("Row "+L3+" Current Directory: no value");
}
// has Current File Name
if(!testCurrentName || !testCurrentExtension){
csvFail++;
csvProblem.push("Row "+L3+" Current File Name/Directory: no value");
}
// has New File Name
if(!testNewName || !testNewExtension){
csvFail++;
csvProblem.push("Row "+L3+" New File Name/Extension: no value");
}
/*
// New File Name has .file extension
if(testNewExtension.length < 2 || testNewExtension.length > 4){ // test for 2 to 4 characters after testNewExtensionIndex
csvFail++;
csvProblem.push(testNewName+": no file extension");
}
*/
// Current File Name and New File Name have the same extension
if(testCurrentExtension != testNewExtension){
csvFail++;
csvProblem.push("Row "+L3+testCurrentName+testCurrentExtension+": different file extension than: "+testNewName+testNewExtension);
}
}
}
catch(e){
csvFail++;
}
}
// if validate CSV file failed, show report and don't rename
// alert(csvProblem.join("\n"));
if(csvFail > 0){
var csvErrorWindow = new Window("palette", "CSV FIle Error", undefined, {closeButton:true});
csvErrorWindow.alignChildren = ["center","top"];
// csvErrorWindow.minimumSize = [600,500];
csvErrorMessage1 = csvErrorWindow.add("statictext", undefined, "Bad news: there are problems with the CSV file that will prevent proper renaming")
csvErrorList = csvErrorWindow.add ("edittext", undefined, csvProblem.join("\n"), {multiline:true});
csvErrorList.minimumSize = [450, 300];
csvErrorList.maximumSize = [450, 300];
csvErrorWindowOkBtn = csvErrorWindow.add("button", undefined, "Close");
csvErrorWindowOkBtn.onClick = function(){
csvErrorWindow.hide();
}
csvErrorWindow.show();
}
if(csvFail == 0){
for (var L1 = 1; L1 < textFile.length; L1++){ // starting with the second row, split row by comma into currentName and newName column values
try{
if(textFile[L1].length > 0){ // make sure each row of textFile has data because Excel adds an empty row when it saves changes
var textFileRead = textFile[L1].split (",")
var currentDirectory = textFileRead[0];
var currentName = textFileRead[1];
var currentExtenstion = textFileRead[2];
var newName = textFileRead[3];
var newExtenstion = textFileRead[4];
// if Preserve current filename is selected, write current filename to XMP
if(checkbox1.value == true){
try{
var changeXMP = currentDirectory+currentName+currentExtenstion;
// get XMP from file
var xmpFile = new XMPFile(changeXMP, XMPConst.UNKNOWN, XMPConst.OPEN_FOR_UPDATE);
// delete existing XMP
var xmpData = xmpFile.getXMP();xmpData.deleteProperty(NS_XMP_MM, "PreservedFileName");
// add new XMP
xmpData.setProperty (NS_XMP_MM, "PreservedFileName", currentName);
// save new XMP to file
if (xmpFile.canPutXMP(xmpData)) {
xmpFile.putXMP(xmpData);
}
xmpFile.closeFile(XMPConst.CLOSE_UPDATE_SAFELY);
}
catch(e){
writeXMPFail.push(writeXMPFail);
}
}
// rename file
var currentFile = new File(currentDirectory+currentName+currentExtenstion);
currentFile.rename(newName+newExtenstion);
renamePass++;
}
}
catch(e){
renameFail.push(currentFile);
}
} // CLOSE for (var L1 = 1; L1 < textFile.length; L1++)
dialog.close();
// alert(renamePass+" files renamed");
// Show report that import is complete
var complete = new Window("palette", "Rename Complete");
// complete.preferredSize = [400,400];
var filesForRenaming = textFile.length-1;
complete.spacing = 3;
complete.alignChildren = 'center';
complete.header = complete.add('statictext', undefined, "Success!");
complete.msg1= complete.add('statictext', undefined, renamePass+" files renamed");
complete.msg1.preferredSize = [400,40];
complete.msg1.justify = 'center';
// List of files that could not be opened to write metadata
complete.problem1 = complete.add('group');
complete.problem1.orientation = 'column';
complete.problem1.maximumSize = [0,0];
complete.problem1.header = complete.problem1.add('statictext', undefined, "But...");
//complete.problem1.header.graphics.font = ScriptUI.newFont ('Arial', 'BOLD', 16);
complete.problem1.msg1 = complete.problem1.add('statictext', undefined, "These files could not be opened for renaming:");
complete.problem1.list = complete.problem1.add ('edittext', [0, 0, 500, 150], renameFail.join("\n"), {multiline:true});
// If there are files that couln't be opened, make problem1 visible
if (renameFail.length > 0){
complete.problem1.minimumSize = [500,400];
}
complete.okBtn = complete.add('button', undefined, 'Close');
complete.okBtn.onClick = function(){
complete.hide();
}
complete.show();
}
} // CLOSE if(csvFail == 0)
} // CLOSE TRY
catch(e){
alert(e + ' ' + e.line);
}
} // CLOSE runRnfcsv()
Copy link to clipboard
Copied
Another method uses the native operating system commands:
https://community.adobe.com/t5/bridge-discussions/rename-multiple-files/m-p/12786213
Here is an example screenshot of my preparation template file for Proper Case name conversion, however it could be used for any batch renaming from a spreadsheet:
Note: LibreOffice/OpenOffice was used as Excel doesn't support regular expression-based formulas which were used to work with variable 3 or 4 character length filename extensions.
Copy link to clipboard
Copied
@Stephen_A_Marsh thanks for remembering those previous conversations. I think the problem was already solved.
The command line method is probably the most straightforward. @Stephen_A_Marsh also posted a good script solution at the end of this thread:
Copy link to clipboard
Copied
@Stephen_A_Marsh thanks for remembering those previous conversations. I think the problem was already solved.
Yes, the problem was solved, however, your script isn't directly available.
It can't hurt to have other options, which was the point of the post. For example, the whole reason that I created the Excel template to help me batch rename in Proper Case is that Adobe Bridge only offers Original case/UPPERCASE/lowercase – but not Proper Case. This has always been a glaring omission in my opinion.