Main Menu

Recent posts

#1
Newbies / Re: How to extract the content...
Last post by StarGeek - Today at 02:55:40 PM
Running the command on multiple files, I do see there is a problem where subsequent files will return an entry containing HASH(0x...) for previously defined tags, so I'll have to work on that.  But on single files, it works correctly.

Quote from: FixEUser on Today at 04:48:34 AMThere are at least 3 problems with your script:

1) It doesn't return any other value then without -config join_tags_ID3-config

I'm not quite sure what you mean here. It still extracts all the rest of the data normally and as I said, extracting just the data you want will probably require a config file. Maybe Phil can figure out some way of extracting just the data for a specific copy of the tag without requiring it to be the exact same copy location each time, but I can't think of any way to do that.

Quote2) It returns an error "join_tags_ID3.config did not return a true value at Image/ExifTool.pm line 9675."

That sounds like you didn't save the complete config file.  Line 9675 in the code is checking for the the very last line of the config file
1; #end
Quote3) For other readers: The config file needs to be named exactly the same as you use it in the command line:
exiftool -config join_tags_ID3.config -G1 -a -s -UserDefinedText Y:\temp\x\y\test.mp3

I'm not sure what your point is. If you're using a config file with the -Config option, you have to use the same name you use when you saved it to disk.

Quote@StarGeek: I'm not sure if you understand my initial question:

I asked for a solution to get 1 (one) specific tag content, for example "MusicBrainz Album Artist Id".
The idea would be a (not yet working) syntax like
exiftool -config specificID3.config -G1 -a -s -UserDefinedText("MusicBrainz Album Artist Id") music.mp3and then get only this value:
d87e52c5-bb8d-4da8-b941-9f4928627dc8

How could I achieve that?

That's what my config file attempts to do. At least, once I fix the bug. It would take the UserDefinedText that contains "(MusicBrainz Album Artist Id)" and return the contents of that as a tag called MusicBrainzAlbumArtistId.

It works correctly on a single file, just not in batch ATM.
Example, the UserDefinedText that contains "(MusicBrainz TRM Id)" creates a tag called MusicBrainzTRMId which containts the value of "e5d018af-3a9d-4ed9-9593-a7b0b63c4579".
C:\>exiftool -config join_tags_ID3.config -G1 -a -s -MusicBrainzTRMId "Y:/Music/Music/Sorted/Albums/Journey/Greatest_Hits/01-Only_the_Young.mp3"
[Composite]     MusicBrainzTRMId                : e5d018af-3a9d-4ed9-9593-a7b0b63c4579

Listing all the "MusicBrainz" tags created
C:\>exiftool -config join_tags_ID3.config -G1 -a -s -UserDefinedText -*Brainz* "Y:/Music/Music/Sorted/Albums/Journey/Greatest_Hits/01-Only_the_Young.mp3"
[ID3v2_3]       UserDefinedText                 : (MusicBrainz TRM Id) e5d018af-3a9d-4ed9-9593-a7b0b63c4579
[ID3v2_3]       UserDefinedText                 : (MusicBrainz Artist Id) abd506e1-6f2b-4d6f-b937-92c267f6f88b
[ID3v2_3]       UserDefinedText                 : (MusicBrainz Album Id) 43ca7ac8-bd36-4468-bab4-004a9a34de66
[ID3v2_3]       UserDefinedText                 : (MusicBrainz Album Type) compilation
[ID3v2_3]       UserDefinedText                 : (MusicBrainz Album Status) official
[ID3v2_3]       UserDefinedText                 : (MusicBrainz Album Artist Id)
[ID3v2_3]       UserDefinedText                 : (MusicBrainz Album Release Country) US
[Composite]     MusicBrainzAlbumReleaseCountry  : US
[Composite]     MusicBrainzTRMId                : e5d018af-3a9d-4ed9-9593-a7b0b63c4579
[Composite]     MusicBrainzArtistId             : abd506e1-6f2b-4d6f-b937-92c267f6f88b
[Composite]     MusicBrainzAlbumId              : 43ca7ac8-bd36-4468-bab4-004a9a34de66
[Composite]     MusicBrainzAlbumType            : compilation
[Composite]     MusicBrainzAlbumStatus          : official
[Composite]     MusicBrainzAlbumArtistId        :

QuoteAre you sure that
my $table = Image::ExifTool::GetTagTable('Image::ExifTool::Composite');
is the correct way to get the UserDefinedText content?

This isn't getting the UserDefinedText. This is the part that creates the new tags.  The new tags get added to the Composite group.

The parts that get the UserDefinedText are
my $nameTag = 'UserDefinedText';and
            Desire => {
                0 => $nameTag,

Final edit: I haven't been able to fix the HASH problem when using it on multiple files, so I'm bugging Phil about fixing it.
#2
Quote from: maxardis on Today at 02:21:13 PMJust one question.  I cannot seem to find any mention of ConvertUnixTime() in man pages nor by googling (only mentioned on some other threads on this forum).  And you also say that it is an internal function.  So I guess it means that it might "disappear" with some future version of exiftool right?  It is kind of a hack, sort of, right?

Yes, the only way to know about it is to dig through the source code or have seen Phil use it in the past.  I seriously doubt it will disappear, as it is a basic part of so much of the exiftool code and would most likely require a huge rewrite of a lot of code to remove it. And Phil strives hard to make sure any changes are backwards compatible. For example, the -AddTagsFromFile option no longer appears in the documentation, as it has been replaced with a different format, but it still will work if you use it.

Hack? I wouldn't say so. It's more of a function that isn't documented outside of the source code

Quote
Quote from: StarGeek on Today at 12:13:34 PMYou don't mention your OS, but you appear to be on Mac/Linux

I am on Linux if that is important, yes.  I can translate Windows CMD into Linux one no problem.  It's pretty much the same

It's important when it comes to quoting, as double quotes on Linux/Mac will change something like $DateTimeOriginal from an exiftool tag into a shell variable.  It's also important with something like the asterisk, as using it as an exiftool wildcard such as -*Date will cause file globbing on Mac/Linux unless single quotes are used '-*Date'
#3
That works perfectly.  Thank you very much.

Just one question.  I cannot seem to find any mention of ConvertUnixTime() in man pages nor by googling (only mentioned on some other threads on this forum).  And you also say that it is an internal function.  So I guess it means that it might "disappear" with some future version of exiftool right?  It is kind of a hack, sort of, right?

Quote from: StarGeek on Today at 12:13:34 PMYou don't mention your OS, but you appear to be on Mac/Linux

I am on Linux if that is important, yes.  I can translate Windows CMD into Linux one no problem.  It's pretty much the same
#4
Quote from: maxardis on Today at 06:52:02 AMI am trying to do this:

exiftool -p '${exif:DateTimeOriginal;ShiftTime(${exif:OffsetTimeOriginal}, -1)} ${directory}/${filename}' ./dir/*

And what I get is a warning:
Warning: Bareword "OffsetTimeOriginal" not allowed while "strict subs" in use for 'exif:DateTimeOriginal'.  I don't understand that message and I don't know what I am doing wrong, nor how to fix it.

Nice attempt, but it isn't that simple to access a different tag within the processing of another tag. The error message is directly from the underlying Perl processor. Accessing a second tag from within a tag can be done, but I think this would be a better way.

First, instead of using DateTimeOriginal, use SubSecDateTimeOriginal.  This is a Composite tag that combines DateTimeOriginal, OffsetTimeOriginal, and SubSecTimeOriginal.  Then the DateFmt helper function is used to convert that to a Unix time stamp, the internal exiftool function of ConvertUnixTime is used to convert that to a normal date in the standard EXIF format (colons instead of hyphens), and DateFmt is used again to convert that into the format you're looking for.

Example
C:\>exiftool -G1 -a -s -SubSecDateTimeOriginal y:\!temp\Test4.jpg
[Composite]     SubSecDateTimeOriginal          : 2024:05:20 12:00:00-07:00

C:\>exiftool -p "${SubSecDateTimeOriginal;DateFmt('%s');$_=ConvertUnixTime($_);DateFmt('%Y-%m-%dT%H:%M:%S')}" y:\!temp\Test4.jpg
2024-05-20T19:00:00

You don't mention your OS, but you appear to be on Mac/Linux.  The above command would be for Windows CMD, so you'll have to swap double/single quotes.
#5
Newbies / Re: How to extract the content...
Last post by FixEUser - Today at 08:56:52 AM
I think, I have found a workaround with a Windows batch file.
This may be a little bit more convenient for Windows users.

Write (copy & paste) this code in a batch file and name it like
ShowContentOfThisUndefinedText.cmd

ECHO OFF
@CLS
SETLOCAL enabledelayedexpansion
FOR /F "tokens=2 delims=)" %%M IN ('   
    exiftool.exe -a -UserDefinedText -ext mp3 -recurse . ^| findstr /c:%1 /i
    ') DO (   
          SET LeftTrimmedValue=%%M         
          ECHO !LeftTrimmedValue:~1!         
          )

This batch file assumes, that exiftool.exe is in the same directory as the batch.
Otherwise, you have to write the full path to your exiftool.exe like
C:\Path\To\My\exiftool.exe

Then copy the batch file to the root directory in which the mp3 files to be checked are stored.

Open a CMD window in this root directory.

Start the batch file and add the string you want to search for in the UndefinedText ID3 tag like this:
ShowContentOfThisUndefinedText "musicbrainz album artist id"and you get the wanted
d87e52c5-bb8d-4da8-b941-9f4928627dc8

Explanations for the batch code:
1) exiftool shows all the ID3 TXXX tags (aka "UserDefinedText") for all mp3 files recursively
2) the Windows command FINDSTR searches for all lines that contain the given string like "musicbrainz album artist id" case-IN-sensitive
3) to get only the tag content (neither "UserDefinedText" nor the tag name in brackets), only the second token after the closing bracket will be outputted
3) to left trim the found content, the first character will be stripped away

Remark:
This batch is only intended for MP3 files and the ID3 TXXX "UserDefinedText" tag.
#6
Hello,

What I would like is to generate dates(*) in UTC (in ISO format) from exif tags for all files in directory without modifying files.

Similarly to a tool like sha1sum I would like to write something like: exiftool (magic options here...) ./directory/* and get output to stdout like so:

2024-01-01T10:10:10  ./directory/file1.jpg
2024-01-01T10:11:10  ./directory/file2.jpg
2024-01-02T10:10:10  ./directory/file3.jpg
...

Output similar to sha1sum but instead of hashes I get dates.

(*) When I say dates what I mean exactly is combination of tags exif:DateTimeOriginal + exif:OffsetTimeOriginal.


What I was able to figure out is:

$ exiftool -d '%Y-%m-%dT%H:%M:%S' -p '${exif:DateTimeOriginal}${exif:OffsetTimeOriginal} ${directory}/${filename}' ./dir/*

This gives me almost what I want.  It gives me the information to stdout in format similar to sha1sum, it gives me dates in ISO format, but it doesn't give me the dates in UTC.

By googling around I can see that there is something like ShiftTime() function that maybe I could use, but unfortunately I cannot make it work.  So I am here for your help.


I am trying to do this:

exiftool -p '${exif:DateTimeOriginal;ShiftTime(${exif:OffsetTimeOriginal}, -1)} ${directory}/${filename}' ./dir/*

And what I get is a warning: Warning: Bareword "OffsetTimeOriginal" not allowed while "strict subs" in use for 'exif:DateTimeOriginal'.  I don't understand that message and I don't know what I am doing wrong, nor how to fix it.

Hope you can help me here.  Thank you in advance.
#7
Newbies / Re: How to extract the content...
Last post by FixEUser - Today at 04:48:34 AM
Thank you for your attempt.

There are at least 3 problems with your script:

1) It doesn't return any other value then without -config join_tags_ID3-config
2) It returns an error "join_tags_ID3.config did not return a true value at Image/ExifTool.pm line 9675."
3) For other readers: The config file needs to be named exactly the same as you use it in the command line:
exiftool -config join_tags_ID3.config -G1 -a -s -UserDefinedText Y:\temp\x\y\test.mp3

@StarGeek: I'm not sure if you understand my initial question:

I asked for a solution to get 1 (one) specific tag content, for example "MusicBrainz Album Artist Id".
The idea would be a (not yet working) syntax like
exiftool -config specificID3.config -G1 -a -s -UserDefinedText("MusicBrainz Album Artist Id") music.mp3and then get only this value:
d87e52c5-bb8d-4da8-b941-9f4928627dc8

How could I achieve that?

PS
Are you sure that
my $table = Image::ExifTool::GetTagTable('Image::ExifTool::Composite');
is the correct way to get the UserDefinedText content?
#8
Newbies / Re: Help requested - Syntax Co...
Last post by StarGeek - May 19, 2024, 08:40:48 PM
One thing that comes to mind is the sidecar files. They might (probably?) not have the same file system time stamps as the main files.

Also, you say "original create date on the file (not the last modified" but you are using CreateDate, not the file system tag, FileCreateDate. CreateDate is a tag embedded in the file and should just about always be exactly the same as DateTimeOriginal, though DateTimeOriginal is less likely to be in videos.

But then you run into the problem that the CreateDate in video files is set to UTC, not local time.  I believe that iPhones will set CreationDate to the local time, so you might put an entry for that to the right of CreateDate.

And you can always test things out by using Testname instead of Filename.  That will output what the file path/name would be without actually moving the file.
#9
Newbies / Re: How to extract the content...
Last post by StarGeek - May 19, 2024, 04:08:22 PM
Ok, I got an idea and was able to edit the join_tags.config to make something that may work.

#------------------------------------------------------------------------------
# File:         join_tags_ID3.config
#
# Description:  ExifTool config file to generate new tags from ID3:UserDefinedText,
# based upon the original join_tags.config
#
# Revisions:    2020-11-16 - P. Harvey created
# 2024-05-19 - Bryan (StarGeek) Williams edited
#
#------------------------------------------------------------------------------

my $nameTag = 'UserDefinedText';

sub JoinTags($$)
{
    my ($val, $et) = @_;
    my $table = Image::ExifTool::GetTagTable('Image::ExifTool::Composite');
    my $i;
    for ($i=0; ;++$i) {
        my $suffix = $i ? " ($i)" : '';
my $temp = $et->GetValue("$nameTag$suffix") or last;
$temp=~m/^\(([^)]+)\)\s*(.*)/;
my $name = $1 or last;
        my $value = $2;
        last unless defined $value;
        my $tagInfo = Image::ExifTool::AddTagToTable($table, $name, {
            Name => Image::ExifTool::MakeTagName($name),
        });
        $et->FoundTag($tagInfo, $value);
    }
    return undef;
}

%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        JoinTagsID3 => {
            Desire => {
                0 => $nameTag,
                1 => $valueTag,
            },
            RawConv => \&JoinTags,
        },
    },
);

1; #end

This will look at the UserDefinedText tags, parse out the data between the parentheses (only if it is at the start of the tag data), create a tag name based upon that, and give that tag a value equal to the rest of the string, trimming leading spaces.

A couple of tests.
C:\>exiftool -config join_tags_ID3.config -G1 -a -s -UserDefinedText -Composite:all Y:\!temp\x\y\test1.mp3
[ID3v2_3]       UserDefinedText                 : (Rip date) 2008-06-22
[ID3v2_3]       UserDefinedText                 : (Source) CD (LP)
[ID3v2_3]       UserDefinedText                 : (Ripping tool) EAC
[ID3v2_3]       UserDefinedText                 : (Release type) Normal Release
[Composite]     DateTimeOriginal                : 2008:24:06
[Composite]     AudioBitrate                    : 206 kbps
[Composite]     Duration                        : 0:03:22 (approx)
[Composite]     Releasetype                     : Normal Release
[Composite]     Ripdate                         : 2008-06-22
[Composite]     Source                          : CD (LP)
[Composite]     Rippingtool                     : EAC

Here's one I thought would break it.  It has a tag with "([rating]) 3" and another with "(Rating) 0".  I thought the brackets might break this.
C:\>exiftool -config join_tags_ID3.config -G1 -a -s -UserDefinedText -composite:all Y:\!temp\x\y\test2.mp3
[ID3v2_3]       UserDefinedText                 : ([rating]) 3
[ID3v2_3]       UserDefinedText                 : (Release type) Normal release
[ID3v2_3]       UserDefinedText                 : (Rip date) 2007-09-14
[ID3v2_3]       UserDefinedText                 : (Ripping tool) EAC
[ID3v2_3]       UserDefinedText                 : (Source) CD
[ID3v2_3]       UserDefinedText                 : (Rating) 0
[Composite]     DateTimeOriginal                : 2007:11:09
[Composite]     AudioBitrate                    : 186 kbps
[Composite]     Duration                        : 0:03:45 (approx)
[Composite]     Rating                          : 0
[Composite]     Rating                          : 3
[Composite]     Releasetype                     : Normal release
[Composite]     Ripdate                         : 2007-09-14
[Composite]     Rippingtool                     : EAC
[Composite]     Source                          : CD

I do not know what will happen if there's a UserDefinedText tag that does not start with parentheses.  It might break in that case. If it does, send me a sample and I'll see if I can fix it.
#10
Newbies / Re: How to extract the content...
Last post by StarGeek - May 19, 2024, 03:10:25 PM
Quote from: FixEUser on May 19, 2024, 07:58:15 AMHow can I extract the content of a specific ID3 "User Defined Text" tag?

To get a specific one might take a user defined tag.

QuoteWhat exiftool-syntax would it be if the only way to get the content is using "ID3:Copy4"?
This won't work as you have specified an actual tag name. You could try ID3:Copy4:UserDefinedText but that assumes the item you are looking for is in the exact same location for every file, which seems unlikely.

With a user defined tag, you could look through all copies of that tag to find the correct one and return that.  But the problem is how to pass all copies of that tag name. I'm pretty sure I asked this question once, but can't remember the context, so it's hard to search for it.

I'll keep trying to figure it out, but it may require input from Phil.