Are there any 'gold standard' EXIFtool example scripts?

Started by Martin Z, May 16, 2023, 04:02:22 PM

Previous topic - Next topic

Martin Z

Summary #TLDR
Does Phil, StarGeek (or anyone else) have any 'super' scripts that they would share or recommend, or any scripts they've written or use themselves that essentially 'bake in' a lot of best practice tips, recommendations, pro-active screening for common issues, etc?

Full post
I've been using EXIFtool for a few months now and have been gradually extending and refining my 'wrapper scripts' that I use to call EXIFtool do to certain things. Based on reading and copying examples from others, I've put together two little helper scripts for example...

Some of my 'enhanced' but NOT best practice scripts...
EXIFTool-ImportCSV.cmd
----------------------
EXIFTool -csv=%1 -e -d "%%d/%%m/%%Y %%H:%%M:%%S" -sep ";"
  -progress:"Writing metadata: %%p%%  [%%f]"
  "-AllDates<CreateDate" "-FileModifyDate<CreateDate" "-FileCreateDate<CreateDate"
  -overwrite_original
  --ext CSV --ext LNK --ext TXT --ext URL

EXIFTool-ExportCSV.cmd
----------------------
EXIFTool -csv -e -d "%%d/%%m/%%Y %%H:%%M:%%S" -sep ";"
  -progress:"Extracting metadata: %%p%%  [%%f]"
  --ext CSV --ext LNK --ext TXT --ext URL
  * >EXIFMetadata.csv

Minor issues
Using the above, I sometimes got an error/warning saying 'no writable tags set for...' however I was able to figure out why and solve that as someone else had issue and this had already been asked/answered here (TLDR; warning occurs when file doesn't have 'CreateDate' tag, consider using FileModifyDate instead)...

Possible sub-optimisations
•  At one time the above scripts included the parameter "-all:all<all:all", which I picked up from some other posts on the site... At the same time, I've also read other posts with slightly different code being used such as "-xmp:all<xmp:all" and "-xmp:all<all:all" and I don't really know if these are all fine or if say [X] option is generally always the best one to use, etc
•  Another thing on my radar (but not immediate to do list) is perfecting the 'date alignment' parameters as again I've used "-AllDates<xxxxx" but have "-time:all<xxxxx" been used on a few posts, so not sure if I should be using that code instead
•  I don't currently use any API methods/parameters (due to current knowledge limits) but I don't know if I am potentially 'missing a trick' by not doing that, etc
>> To clarify, the above are just meant as examples rather than specific things I am asking for help on in this post

Thinking there's probably a better way
•  I have no problem learning from my mistakes, or as I go
•  Equally, I ACTIVELY want to learn more about EXIFtool and understand how to use it better, so I'm not asking anyone to 'do my homework for me'
•  At the same time, I realise that the forum is inherently going to have lots of 'not great' code posted by others because they need help so it possibly isn't the best place to copy code from
•  And rather than re-invent the wheel from scratch myself, there's probably loads of people that have already sussed these things and already built some awesome scripts!

It would be great if...
So in summary, if anyone has any of the below they're happy to share that would be amazing!...
•  Scripts for specific tasks (e.g. exporting to CSV) with any applicable best practice 'baked-in'
•  Snippets/parameter sets that are useful in various situations (e.g. like my exclusion of .lnk (shortcuts) and other filetypes)
•  Any best practice advice or guidelines -- e.g. if you need to include "FOO" always remember to include "BAR" as well... or 'if you want to align dates, I found XXXXX is the best column to use as a source/reference, etc

Thanks in advance (I hope the above doesn't sound too crazy!) 🙂
Look forward to seeing what the community has to offer!
-- Martin

Phil Harvey

This is a loaded question because there are sooo many different things that ExifTool is used for.

Perhaps the best example of "baked-in" functions are the argfiles distributed in the full version:

  arg_files/                - Argument files to convert metadata formats:
    exif2iptc.args            - Arguments for converting EXIF to IPTC
    exif2xmp.args            - Arguments for converting EXIF to XMP
    gps2xmp.args              - Arguments for converting GPS to XMP
    iptc2exif.args            - Arguments for converting IPTC to EXIF
    iptc2xmp.args            - Arguments for converting IPTC to XMP
    iptcCore.args            - Complete list of IPTC Core XMP tags
    pdf2xmp.args              - Arguments for converting PDF to XMP
    xmp2exif.args            - Arguments for converting XMP to EXIF
    xmp2gps.args              - Arguments for converting XMP to GPS
    xmp2iptc.args            - Arguments for converting XMP to IPTC
    xmp2pdf.args              - Arguments for converting XMP to PDF

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

Martin Z

Thanks Phil!

PS -- You are right, and I actually meant to add a 'disclaimer' in advance, something along the lines of "I realise that people will use EXIFtool for a wide variety of things, but please feel free to share anything that you think is useful. I won't criticise any code provided or complain anything is too niche, etc... my main objective here is just to learn from you fabulous people"... But (a) TBH, I forgot to include it... and (b) I tend to be just slightly verbose (not sure if you have noticed 😉) so probably good I don't make my original post any longer at this point 🙂

Running summary
•  Pre-configured parameters (argfiles) for converting tags (e.g. IPTC➡️EXIF, EXIF➡️XMP) | credit: Phil

[Assuming there are a few replies, I will try to maintain a summary/list of contributions to avoid people having to scroll through everything]

StarGeek

My response was getting long so I'm splitting it up into separate subjects so I might reference an individual post in the future.

Quote from: Martin Z on May 16, 2023, 04:02:22 PMDoes Phil, StarGeek (or anyone else) have any 'super' scripts that they would share or recommend

I really don't have anything I would call a script with exiftool. I would more likely use an Args file -@ (Argfile) option or set up a text replacement (I use texter, written in AutoHotKey). For any complex manipulation of metadata I would probably create a user defined tag.

I have a few perl and AHK scripts that call exiftool for various reasons, but that is secondary to what the script actually does.

I thought I had a couple scripts that had to call exiftool with the -v (-verbose) option and parse through that output to get the correct details, but it turns out that I was able to do it without calling exiftool. 

QuoteEXIFTool-ExportCSV.cmd
----------------------
EXIFTool -csv -e -d "%%d/%%m/%%Y %%H:%%M:%%S" -sep ";"
  -progress:"Extracting metadata: %%p%%  [%%f]"
  --ext CSV --ext LNK --ext TXT --ext URL
  * >EXIFMetadata.csv

You should probably use the dot ., which stands for the current directory, instead of the asterisk. If you need to recurse into subdirectories, you can't use the asterisk.  See Common Mistake #2 for other possible problems.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

StarGeek

Quote•  At one time the above scripts included the parameter "-all:all<all:all"

Ok, rewriting everything.  The whole "-GROUP:ALL<GROUP:ALL" is something I don't quite have a handle on.  So I'm testing as I go and basically writing this as something I can reference in the future.

Any TAG<TAG operation implies -TagsFromFile @ unless an explicit -TagsFromFile for a different file is used (see the -TagsFromFile option).

The examples will start all data cleared except for XMP-crd:Description.  That tag is marked as Avoid, as the standard place would be XMP-dc:Description

First, copying -TagsFromFile @ -All:All results in no changes, as all tags are copied into the exact same locations.  This is true even if you clear the data with -All:All= in the same command before the copy.
C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]        XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]      Description                    : Test Description

C:\>exiftool -P -overwrite_original -TagsFromFile @ -All:All y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]        XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]      Description                    : Test Description

C:\>exiftool -P -overwrite_original -All:all= -TagsFromFile @ -All:All y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]        XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]      Description                    : Test Description[/tt]

Using "-All:All<All:All" does the same
C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]        XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]      Description                    : Test Description

C:\>exiftool -P -overwrite_original "-All:All<All:All" y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]        XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]      Description                    : Test Description

C:\>exiftool -P -overwrite_original -All= "-All:All<All:All" y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]        XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]      Description                    : Test Description

So there's no real difference between -TagsFromFile @ -All:All and "-All:All<All:All".

Quotewith slightly different code being used such as "-xmp:all<xmp:all"

Now things get tricky.  This copies all XMP into their preferred XMP locations.  If you clear the data just before the tag copy, then XMP-crd:Description is not copied back into the file.
C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]         XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]       Description                     : Test Description

C:\>exiftool -P -overwrite_original "-xmp:all<xmp:all" y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]         XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]       Description                     : Test Description
[XMP-dc]        Description                     : Test Description

C:\>exiftool -P -overwrite_original -all= -XMP-crd:Description="Test Description" y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]         XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]       Description                     : Test Description

C:\>exiftool -P -overwrite_original -All:all= "-xmp:all<xmp:all" y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -XMP:All y:\!temp\Test4.jpg
[XMP-x]         XMPToolkit                      : Image::ExifTool 12.62
[XMP-dc]        Description                     : Test Description

Quote"-xmp:all<all:all"

Things get moved even more with this. In addition to the change in XMP, tags in the FILE group are copied to the same name locations in XMP
C:\>exiftool -G1 -a -s -e --system:all y:\!temp\Test4.jpg
[ExifTool]      ExifToolVersion                 : 12.62
[File]          FileType                        : JPEG
[File]          FileTypeExtension               : jpg
[File]          MIMEType                        : image/jpeg
[File]          ImageWidth                      : 1749
[File]          ImageHeight                     : 1205
[File]          EncodingProcess                 : Baseline DCT, Huffman coding
[File]          BitsPerSample                   : 8
[File]          ColorComponents                 : 3
[File]          YCbCrSubSampling                : YCbCr4:2:0 (2 2)
[XMP-x]         XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]       Description                     : Test Description

C:\>exiftool -P -overwrite_original -TagsFromFile @ "-xmp:all<all:all" y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -G1 -a -s -e --system:all y:\!temp\Test4.jpg
[ExifTool]      ExifToolVersion                 : 12.62
[File]          FileType                        : JPEG
[File]          FileTypeExtension               : jpg
[File]          MIMEType                        : image/jpeg
[File]          ImageWidth                      : 1749
[File]          ImageHeight                     : 1205
[File]          EncodingProcess                 : Baseline DCT, Huffman coding
[File]          BitsPerSample                   : 8
[File]          ColorComponents                 : 3
[File]          YCbCrSubSampling                : YCbCr4:2:0 (2 2)
[XMP-x]         XMPToolkit                      : Image::ExifTool 12.62
[XMP-crd]       Description                     : Test Description
[XMP-dc]        Description                     : Test Description
[XMP-tiff]      BitsPerSample                   : 8
[XMP-tiff]      ImageHeight                     : 1205
[XMP-tiff]      ImageWidth                      : 1749
[XMP-tiff]      YCbCrSubSampling                : YCbCr4:2:0 (2 2)

I'll have to get back to the other stuff later, as I've already spent too long on this.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

Phil Harvey

Quote from: StarGeek on May 17, 2023, 02:38:49 PMSo there's no real difference between -TagsFromFile @ -All:All and "-All:All<All:All".

Correct.  If the target tag isn't specified then it is assumed to be the same as the source.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

Quote from: Martin Z on May 16, 2023, 04:02:22 PM•  Another thing on my radar (but not immediate to do list) is perfecting the 'date alignment' parameters as again I've used "-AllDates<xxxxx" but have "-time:all<xxxxx" been used on a few posts, so not sure if I should be using that code instead

These do two very different things.  AllDates is a Shortcut tag that writes to the three most important EXIF time stamps, CreateDate, DateTimeOriginal, and ModifyDate.  It will also update tags of the same name that already exist, such as the XMP tags with the same name.

I don't recommend writing to Time:All.  It will write to all the date time tags, which is over 90 tags in a jpg file.  It's much better to target the tags you actually want.  And if for some reason you feel you must write to Time:All, then you would probably want to use the -wm (-writeMode) option with -wm w which will only write to existing tags and not create any new ones.

Quote•  I don't currently use any API methods/parameters (due to current knowledge limits) but I don't know if I am potentially 'missing a trick' by not doing that, etc

I mostly use only two -api calls.  The -api Filter option and the -api QuickTimeUTC option-api Filter applies the Perl expression used to all tags in the file.  For example, you misspelled a word, say "Luck Skywalker" instead of "Luke Skywalker", you could apply -api "filter=s/Luck Skywalker/Luke Skywalker/gi" -TagsFromFile @ -All:all and all cases of "Luck Skywalker" would changed.

I tend to use this to write cleaner commands.  For example, I have some default text I put into my images when first copying from the camera.  It starts as "-Description<SUBJECT at EVENT...".  I can then use the -api Filter to replace SUBJECT and EVENT with a command like
exiftool -progress -P -overwrite_original -if "($Description# ne $Description) -tagsfromfile @ -Description -MyHeadline -api "Filter=s/SUBJECT/Actual Subject/;s/EVENT/actual event" /path/to/files/

The $Description# ne $Description compares the original Description, using the # version of -n (--printConv) option, to the filtered version.  If the two are different, then write the new value.  You could write this as -if "${Description;s/SUBJECT/Actual Subject/;s/EVENT/actual event} ne $Description" it would technically be a bit faster, but my actual command is more complex and would lead to a much longer command where I would have to make sure all the times I'm replacing SUBJECT and EVENT are correct.

Oh yeah, Filter will be applied to each entry of a List Type tag individually, making it much easier to apply changes to such tags.

And -api QuickTimeUTC is the option for dealing with Quicktime UTC time stamps.

Other commonly used api calls would be
-api Compact option, which can change the way exiftool will write XMP data.  Some programs have very poor XMP parsing routines and you might have to write the data differently
-api LargeFileSupport option, which allows for very big files (over 4 gigs? I think) to be processed.  See this post.
-api MissingTagValue option, for use with the -f (-ForcePrint) option
-API RequestAll option, in some cases, some tags may not be extracted as it might erode performance.  This option can be used to make sure these tags are listed.
-api TimeZone option, changes the local time zone temporarily for Mac/Linux.  Unfortunately it doesn't work on Windows.  You would use this most often with the -api QuicktimeUTC to temporarily change the local time zone.  For example, a video filmed on East Coast US, but edited on West Coast US, so you would temporarily change it to Eastern Time with this.

Minor rant: The Windows work around, using set TZ=<zone> on the command line first, is really messy as you can't just do something simple like set TZ=EDT.  No, you have to set the time zone name, negate the time zone number, then add the time zone name if it uses Daylight savings.  So technially it would be set TZ=EST+5EDT.  Except the time zone names don't do anything.  You could just as easily use set TZ=ABC+5XYZ and it would work. It does not do any sanity checks to make sure the time zones are correct.

Quote•  At the same time, I realise that the forum is inherently going to have lots of 'not great' code posted by others because they need help so it possibly isn't the best place to copy code from

I would say, as long as you read to the end of the thread, you're more likely to find better command examples here than anywhere else.  Here the command is more likely to have any errors corrected.  Elsewhere, you're more likely to find commands that jump through a lot of unneeded hoops to get the same result.

For example, I have an IFTTT set up to let me know when "exiftool" appears on Reddit.  Today, a person was trying to write a command that would pass all of the exiftool output to grep to get one tag, then do it again to get another tag, then try to do some regex to reformat the date, and then finally rename the file.  And all was needed was to use the to reformat the data and then directly  rename the file based upon the two desired tags.  And that doesn't bring in the fact that they probably would have tried looping through all the files separately.

Quote•  And rather than re-invent the wheel from scratch myself, there's probably loads of people that have already sussed these things and already built some awesome scripts!

The thing is, a significant portion of the questions here are extremely specific and don't always transfer to another command without some changes.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).