Rename images and videos at once (single rename run)

TL;DR
Rename script for renaming images and videos at once (one run) with advanced settings.

Usecase
I have several devices being able to capture images and videos (camera, smartphone...) and I want them to name them by "year-month-date time" so that i can sort them by capturing time without having to look into metadata (this a very slow process compared to sort by name). It is using leading 0 since without the sort order will go crazy (10-19 comes between 1 and 2).
Because the time the media was captured is saved in different metadata fields depending on the media/metadata type, a general renaming approach/command is not able to do this.
So this script extracts the corresponding metadata field and formats the date regarding the pattern.
If no metadata field is found you can enable a fallback date (date the file was created which works as long as the file was untouched on the device it was created at).
You can also perform a regex check so that renaming only is done when the name does not match the pattern (honestly not sure if neccessary or the saved time - if at all - worth the effort; but you can).

Regex explanation
For those of you who are not familiar with regular expressions (in this script used to check wether to rename if name does not match the regex pattern), no worries: ill explain it shortly (in case you want to change the pattern / date time format).
I know it looks horrible

([12]\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) (?:[01]\d|2[0123])-(?:[012345]\d)-(?:[012345]\d)

but its easy

  • ([12]\d{3}) means a 4 digit starting with either 1 or 2 followed by 3 digits stands for the year (either from the last or the current millennial; 1000-2999)
  • (0[1-9]|1[0-2]) stands for the month, either with a leading 0 or the months 10, 11 or 12 (01 - 12)
  • (0[1-9]|[12]\d|3[01]) stands for the days, either with leading 0 or the the two digit days till 31 (01-31)
  • (?:[01]\d|2[0123]) for the hours with leading (00-23)
  • (?:[012345]\d) for the minuts/seconds (00 - 59)
  • the - is the seperator between the parts of the date / time

Button for renaming the files directly with the rename script

<?xml version="1.0"?>
<button backcol="none" display="both" hotkey="ctrl+alt+R" label_pos="right" textcol="none">
	<label>Batch rename time taken</label>
	<icon1>#currentformattype</icon1>
	<function type="normal">
		<instruction>Rename ADVANCED PRESET=&quot;Camera&quot;</instruction>
	</function>
</button>

Download

// v1.0(2021-07-07)

var DefaultDateRegex = /([12]\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) (?:[01]\d|2[0123])-(?:[012345]\d)-(?:[012345]\d)/;
var DefaultDateFormat = "D#yyyy-MM-dd T#HH-mm-ss";
var Logging = true;

//https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Scripting/OnGetNewName.htm
//https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Scripting/GetNewNameData.htm	
function OnGetNewName(getNewNameData)
{
	// Add script code here.
	// 
	// Main inputs (all read-only):
	// 
	// - getNewNameData.item:
	//     Object with information about the item being renamed.
	//     e.g. item.name, item.name_stem, item.ext,
	//          item.is_dir, item.size, item.modify,
	//          item.metadata, etc.
	//     item.path is the path to the parent folder.
	//     item.realpath is the full path to the file, including its name,
	//          and with things like Collections and Libraries resolved to
	//          the real directories that they point to.
	// - getNewNameData.oldname_field:
	// - getNewNameData.newname_field:
	//     Content of the "Old Name" and "New Name" fields in the Rename dialog.
	// - getNewNameData.newname:
	// - getNewNameData.newname_stem and newname_stem_m:
	// - getNewNameData.newname_ext  and newname_ext_m:
	//     The proposed new name for the item, based on the non-script
	//     aspects of the Rename dialog. Scripts should usually work from this
	//     rather than item.name, so that they add to the dialog's changes.
	//     newname_ext is the file extension, or an empty string if none.
	//     newname_stem is everything before the file extension.
	//     The *_m versions handle multi-part extensions like ".part1.rar".
	// - getNewNameData.custom:
	//     Contains any custom field values for additional user input.
	// 
	// Return values:
	// 
	// - return true:
	//     Prevents rename.
	//     The proposed getNewNameData.newname is not used.
	// - return false: (Default)
	//     Allows rename.
	//     The proposed getNewNameData.newname is used as-is.
	// - return "string":
	//     Allows rename.
	//     The file's new name is the string the script returns.

	try
	{
		var item = getNewNameData.item;
		Logging = getNewNameData.custom.activatelog;

		
		if(item.is_dir)
		{
			Log(item + " is directory");
			return true; //dont rename
		}

		if(getNewNameData.custom.userenamepreventionregex && getNewNameData.custom.renamepreventionregex.length > 0) //do check before renaming
		{
			var regex = new RegExp(getNewNameData.custom.renamepreventionregex);
			if(regex.test(item.name)) // if matches my desired name pattern already dont rename
			{
				Log(item + " already matches the desired name pattern, skipping ...");
				return true;//dont rename
			}
		}
		
		var result = DateTakenFromFile(item, getNewNameData.custom.usecreationdateasfallback);
		if(result == null)
		{
			return true; //dont rename
		}

		var format = getNewNameData.custom.format.length > 0 ? getNewNameData.custom.format : DefaultDateFormat;
		var newFileName = result.date.Format(format) + item.ext;
		//Log(item + ": Renaming (" + result.metatype + ") '" + item.name + "' \t=> '" + newFileName + "'");
		Log(item + ": Renaming (" + result.metatype + ")\t=> '" + newFileName + "'");
		
		return newFileName; //rename
	}
	catch(e)
	{
		Log(item + " ERROR: " + e, true);
		return true; //dont rename
	}
}

//Extract desired date from metadata based on type
function DateTakenFromFile(file, useFallback)
{
	var currentMeta = file.metadata;
	if(currentMeta == null)	
	{
		if(useFallback)
			return { date : file.create, metatype: "file creation meta" };
		else
		{
			Log(item + ": Cannot find metadata. Skipping...", true);
			return null
		}
	}

	else if(currentMeta == "image")
		return { date : currentMeta.image.datetaken, metatype: "image meta" };
	else if(currentMeta == "video")
		return { date : currentMeta.video.releasedate, metatype: "video meta" };
	else if(useFallback)
		return { date : file.create, metatype: "file creation meta" };//FallbackDate(file); //two references because meta cann be null or something else than image or video

	//Log("Cannot find metadata in " + file.name + ". Skipping...", true);
	Log(item + ": Cannot find metadata. Skipping...", true);
	return null;
}

//https://www.gpsoft.com.au/help/opus12/index.html#!Documents/Scripting/GetCustomFieldData.htm
function OnGetCustomFields(getCustomFieldData)
{
	getCustomFieldData.fields.format="D#yyyy-MM-dd T#HH-mm-ss";
 	getCustomFieldData.field_labels('format')='Custom Datetime format';
 	getCustomFieldData.field_tips('format')='Specify the format how the extracted date should be used for the new name of the file.';

	getCustomFieldData.fields.userenamepreventionregex=false;
 	getCustomFieldData.field_labels('userenamepreventionregex')='Use regex check'; //jshint ignore:line
 	getCustomFieldData.field_tips('userenamepreventionregex')='If regex is defined than filename is checked against regex and if matches than no rename will happen'; //jshint ignore:line

	getCustomFieldData.fields.renamepreventionregex="([12]\\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01]) (?:[01]\\d|2[0123])-(?:[012345]\\d)-(?:[012345]\\d)";
 	getCustomFieldData.field_labels('renamepreventionregex')='Regex'; //jshint ignore:line
 	getCustomFieldData.field_tips('renamepreventionregex')='Regex for filename checking before renaming'; //jshint ignore:line

 	getCustomFieldData.fields.usecreationdateasfallback=true;
 	getCustomFieldData.field_labels('usecreationdateasfallback')='Use creationdate as fallback'; //jshint ignore:line
 	getCustomFieldData.field_tips('usecreationdateasfallback')='Use creationdate as fallback date if neither image nor video meta was found'; //jshint ignore:line

	getCustomFieldData.fields.activatelog=true;
 	getCustomFieldData.field_labels('activatelog')='Logging'; //jshint ignore:line
 	getCustomFieldData.field_tips('activatelog')='Log rename script outputs'; //jshint ignore:line
}

function Log(msg, e)
{
	if(Logging)
		DOpus.output(String(msg), e || false);
}

v1.0 (2021-07-07)
Camera.orp (7.2 KB)

Installation
https://resource.dopus.com/t/how-to-use-rename-presets-from-this-forum/26726

1 Like