Date in directory from filename and if-statement

Started by Inferi0r, October 05, 2020, 05:30:29 PM

Previous topic - Next topic

Inferi0r

Hello all,

I tried for several hours to take the date from a FileName for my Directory path. Even doing what is exactly in Example 12 it is not working for me, latest Exiftool version. I am working from Windows commandline and yes it are the famous Whatsapp files again:

These are the kind of files I have:
AUD-20180730-WA0002-1.m4a
IMG-20140925-WA0016.jpg
IMG-20200115-WA0019_5.jpg-1.jpg
VID-20171014-WA0004.mp4

And they should be transfered too + renamed like this:
\2018\07. July\2018-07-30 0000_002-1_Whatsapp.m4a
\2014\09. September\2014-09-25 0000_016_Whatsapp.jpg
\%Y\%m. %B\2020-01-15 0000_019-5_Whatsapp.jpg
\%Y\%m. %B\2014-04-16 0000_001_Whatsapp.jpg
\%Y\%m. %B\2017-10-14 0000_004_Whatsapp.mp4

Renaming is working with the following command:
exiftool "-FileName<${FileName;s/(\D{3})-(\d{4})(\d\d)(\d\d)-(\D\D\d)(\d{3}).*/$2-$3-$4 0000_$6/}%-c_Whatsapp.%le" DIR

I see, I could have also used this: exiftool "-FileName<${FileName;$_=substr($_,4,18);s/(\d{4})(\d\d)(\d\d)-(\D\D\d)(\d{3})/$1-$2-$3 0000_$5/}%-c_Whatsapp.%le" DIR

However, even when specifying -d  "%Y\%m. %B" "-Directory<FileName" the directory will be still exact the filename and not contain any of the requested dates.
When I put it like exiftool "-FileName<\%Y\%m. %B\${FileName;s/ ... directory will be just literaly %Y etc and not the real year.
How should I fix this, as according to the Exiftool guidance, it should recognise date and year from my original filenames?

Next to all of this, if this is fixed, I would like to add two more advanced -if statements.
-if "$FileName contains $CreateDate" than replace 0000 of new filename with %H of $CreateDate
-if "$FileName doesnot contain $CreateDate" than keep 0000 in filename (like my examples above)

How could I do that as I need to relate the Filename dating format to the CreateDate format?

This is because, when the filename (always correct DateOriginal) is the same as the CreateDate the hours are usually quitte in sync, when dates are different, hours are not related and I would like to reset them to 00:00 for further review.

StarGeek

Quote from: Inferi0r on October 05, 2020, 05:30:29 PM
However, even when specifying -d  "%Y\%m. %B" "-Directory<FileName" the directory will be still exact the filename and not contain any of the requested dates.

From the docs on the -d (dateFormat) option
   Set the format for date/time tag values

Filename is not a date/time tag, so it won't be formatted with the -d option.

QuoteWhen I put it like exiftool "-FileName<\%Y\%m. %B\${FileName;s/ ... directory will be just literaly %Y etc and not the real year.

The time related % tokens only work as part of the -d option.  They won't work directly as part of the command.  See the -w (textout) option for the % tokens that do work directly on the command, which are filename related.

QuoteHow should I fix this, as according to the Exiftool guidance, it should recognise date and year from my original filenames?

Your working command is pretty much the right idea.  You have to parse it into the format you want.

QuoteNext to all of this, if this is fixed, I would like to add two more advanced -if statements.
-if "$FileName contains $CreateDate" than replace 0000 of new filename with %H of $CreateDate
-if "$FileName doesnot contain $CreateDate" than keep 0000 in filename (like my examples above)

When you write different values to a tag, the last valid command takes precedent.  So put both options in the command, but the one that copies from CreateDate afterwards.  If CreateDate exists, then that part of the command will work.  If not, it falls back to the previous part of the command.
* 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).

Inferi0r

#2
Thank you Stargeek for your swift and usefull replies as always on this forum, I learned a lot based on that!

Quote from: StarGeek on October 05, 2020, 06:36:30 PM
Quote from: Inferi0r on October 05, 2020, 05:30:29 PM

When I put it like exiftool "-FileName<\%Y\%m. %B\${FileName;s/ ... directory will be just literaly %Y etc and not the real year.

QuoteThe time related % tokens only work as part of the -d option.  They won't work directly as part of the command.  See the -w (textout) option for the % tokens that do work directly on the command, which are filename related.

Your working command is pretty much the right idea.  You have to parse it into the format you want.

I have read the documentation but cannot think of any command that would put my files into the \%Y\%m. %B\ folder structure I already use? What specific command I should use, of do you have an example I can read to take it from there if I want to take that Year and Month from my FileName?


Quote
QuoteNext to all of this, if this is fixed, I would like to add two more advanced -if statements.
-if "$FileName contains $CreateDate" than replace 0000 of new filename with %H of $CreateDate
-if "$FileName doesnot contain $CreateDate" than keep 0000 in filename (like my examples above)

When you write different values to a tag, the last valid command takes precedent.  So put both options in the command, but the one that copies from CreateDate afterwards.  If CreateDate exists, then that part of the command will work.  If not, it falls back to the previous part of the command.

But CreateDate always exists, but we do not always want to use it?
OK, so that brings me to the following two statements, with 2 more questions:

exiftool -if '${FileName;$_=substr($_,4,11);s/(\d{4})(\d\d)(\d\d)/$3-$2-$1/} ne ${CreateDate} "-FileName<${FileName;$_=substr($_,4,18);s/(\d{4})(\d\d)(\d\d)-(\D\D\d)(\d{3})/$1-$2-$3 0000_$5/}%-c_Whatsapp.%le" -execute
-if '${FileName;$_=substr($_,4,11);s/(\d{4})(\d\d)(\d\d)/$3-$2-$1/} eq ${CreateDate}
"-FileName<${FileName;$_=substr($_,4,11);s/(\d{4})(\d\d)(\d\d)/$1-$2-$3 /}${CreateDate}${FileName;$_=substr($_,16,18);s/(.*)/_$1/}%-c_Whatsapp.%le" -d "\%Y\%m. %B\%H%M" -execute -common_args DIR

1. Is the double -execute statement the option to combine both -if statements?
2. Would dus -d do the trick as it understand it should replace CreateDate there in the middle of the string with the %H%M and also know now where to take the %Y\%m. from?

(Still need to fix the directory for the first -if statement, but that was my first question in previous paragraph)

BTW not sure if ne/eq works, maybe I should use it like: =~ /${CreateDate}/

Luuk2005

#3
Greetings Inferi0r, Im not think %B can be expanded from filename, but twelve s/find/replace can fix the %B yes?
But its very much to enter, so Im only do September and October, because still there is ten more to go!
${FileName;s/(\D{3})-(\d{4})(\d\d)(\d\d)-(\D\D\d)(\d{3}).*/$2-$3-$4 0000_$6/; s/(\d{4})-(09)(.*)/$1\/$2. September\/$1-$2$3/; s/(\d{4})-(10)(.*)/$1\/$2. October\/$1-$2$3/}

When all twelve is finished, to make the exiftool conduct different if CreateDate is in filename, it can be like..
-if "${Filename;Match} eq $CreateDate" -d %H -Filename"<${Filename;ChangesWithout000_$6} ${CreateDate}_${Filename;ChangesWithOnly_$6" Dir -execute
-if "${Filename;Match} ne $CreateDate"            -Filename"<${Filename;ChangesWith000_$6}                                                                                         Dir -execute

This because like StarGeek says -d %H only controls the date-tags like $CreateDate but not tags like %Filename.
Please to test with -TestName because maybe the shorter s/// without the \D{3} finds too many other filenames?
But if thats to be problem, you can use 12 much longer s/// but Im think its easier let another -if test filename for ^\D{3}-\d{8}-\D\D\d{4}.
Sorry if Im not explaining better, but I want to get this here, so the experts can help for improvements, and this is to be very very long command!
Windows8.1-64bit, exiftool-v12.11(standalone), sed-v4.0.7

StarGeek

Quote from: Inferi0r on October 06, 2020, 06:21:19 PM
I have read the documentation but cannot think of any command that would put my files into the \%Y\%m. %B\ folder structure I already use? What specific command I should use, of do you have an example I can read to take it from there if I want to take that Year and Month from my FileName?

Ah, I didn't recognize that the %B was the full month name and that you weren't just using the number.  It would be long and messy but Luuk2005's idea of parsing the month and then a long substitution for the name would be one way to go.  Myself, I would probably do two steps.  First, embed the date into any file that didn't already have it.  And then a second run using the -d (dateFormat) option on that embedded date.


QuoteNext to all of this, if this is fixed, I would like to add two more advanced -if statements.
-if "$FileName contains $CreateDate" than replace 0000 of new filename with %H of $CreateDate
-if "$FileName doesnot contain $CreateDate" than keep 0000 in filename (like my examples above)

QuoteBut CreateDate always exists, but we do not always want to use it?

Now I'm confused.  First you have a command for instances that don't have CreateDate.  Then you say it always exists.

QuoteOK, so that brings me to the following two statements, with 2 more questions:
<...>
1. Is the double -execute statement the option to combine both -if statements?

It's really hard to break all that down and figure it out.  Unfortunately, I don't have time atm. But first, you don't need two -execute statements, just the first.  The second command will run once it hits -common_args.

Quote2. Would dus -d do the trick as it understand it should replace CreateDate there in the middle of the string with the %H%M and also know now where to take the %Y\%m. from?

You may have to use the DateFmt helper function and repeat the tag a couple times. 

I'd suggest first trying to break everything down into simple commands that you can get to work before combining everything.
* 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).

Inferi0r

#5
Thanks both for the help!

At least this part is working for me, directory + filename combined (assuming -if $FileName contains $FileCreateDate):

exiftool -d "%Y\%m. %B" "-FileName<OUTPUT/${FileCreateDate}/${FileName;s/.*(\d{4})(\d\d)(\d\d).*/$1-$2-$3 /}${FileCreateDate#;s/.*( )(\d\d):(\d\d).*/$2$3/}_${FileName;$_=substr($_,16,3)}%-c_Whatsapp.%le" "DIR"

That ends up in like: /IMG-20140925-WA0021.jpg' --> 'OUTPUT/2014/09. september/2014-09-25 2221_021_Whatsapp.jpg' (perfect!)


But I also need a query for the files, assuming -if $FileName DOESNOT contain $FileCreateDate. A working start is this:

exiftool "-FileName<OUTPUT/${FileName;$_=substr($_,4,8);s/(\d{4})(\d\d)(\d\d)/$1\/$2. XYZ\/$1-$2-$3 0000_/}${FileName;$_=substr($_,16,3)}%-c_Whatsapp.%le" "DIR"

That creates this output: /IMG-20140925-WA0021.jpg' --> 'OUTPUT/2014/09. XYZ/2014-09-25 0000_021_Whatsapp.jpg' (great start!)

Thanks Luuk2005 on your help for the '%B' function, I had some trouble to put your solution in a working command, but than run accross this post: https://exiftool.org/forum/index.php?topic=6557.0 where Phill proposed to do it with a solution like this:
qq.{"01"=>"January","02"=>"February","03"=>"March","04"=>"April"}->{$2}.qq

So I was trying with something like this, but thats not the correct Perl:

exiftool "-TestName<OUTPUT/${FileName;$_=substr($_,4,8);s/(\d{4})(\d\d)(\d\d)/$1\/$2. qq.{"01"=>"January","02"=>"February","03"=>"March","04"=>"April"}->{$2}.qq\/$1-$2-$3 0000_/}${FileName;$_=substr($_,16,3)}%-c_Whatsapp.%le" "DIR"

So let me find out that first, before heading to the -if's again. @StarGeek: sorry I meant to see that FileCreateDate (not CreateDate, my fault) always exist ofcourse, but is not always usefull, thats where I would like to add the -if statement for later.

StarGeek

There might be a better way, but to make it less messy I use a helper function to convert month numbers to names.

In your .ExifTool_config, add this someplace before the line that says %Image::ExifTool::UserDefined = (
# Returns the number of a month if input is number, otherwise returns original data
sub MonthNumber2Name{
($_) = @_;
s/^0+//;
my %month_name;
@month_name{ 1 .. 12 } = qw(January February March April May June July August September October November December);
$_=((defined $month_name{$_}) ? $month_name{$_}:$_);
}


You can then call MonthNumber2Name helper function.  Example output using Filename as a placeholder.  It will return the month number if the input is a number otherwise it returns the original input.
C:\>exiftool -p "${Filename;MonthNumber2Name('12')}" y:\!temp\Test4.jpg
December

C:\>exiftool -p "${Filename;MonthNumber2Name('3')}" y:\!temp\Test4.jpg
March

C:\>exiftool -p "${Filename;MonthNumber2Name('0002')}" y:\!temp\Test4.jpg
February

C:\>exiftool -p "${Filename;MonthNumber2Name('zz')}" y:\!temp\Test4.jpg
zz
* 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).

Luuk2005

Greeting StarGeek and Inferi0r!
This why Im love coming here, always there is more to learn like helper functions, I cant wait for testing it! Im sorry to not explain better with words, so did all the coloring and formatting but its too long to fit in the page, so then its looks even much harder to understand. So I put examples like this, but on different lines, but now you must edit for the testing.
This to verify filename>18chars, and is like your explanation. The first -if is to be more exact, so the others can be much easier..
-if "$filename ne ${filename;s/^(.{19}).*/$1/} and ${Filename;s/^(.{19}).*/$1/} eq ${Filename;s/^(\D{3}-(19|20)\d{6}-\D\D\d{4}).*/$1/}" 
-if "${filename; s/^....(.{8}).*/$1/}!=${CreateDate;}" 
-TestName"<${FileName;s/.{4}(.{4})(..)(..)-...(...).*/$1\/$2. $2\/$1-$2-$3 0000_$4/;  s/ 01/ Jan/;s/ 02/ Feb/;s/ 03/ Mar/;s/ 04/ Apr/;s/ 05/ May/;s/ 06/ Jun/;s/ 07/ Jul/;s/ 08/ Aug/;s/ 09/ Sep/;s/ 10/ Oct/;s/ 10/ Nov/; s/ 10/ Dec/}%-c_Whatsapp.%le"  .       
-execute

For names without CreateDate in Filename, it makes the output like ...
'./IMG-20171014-WA0004.jpg' ----> '2017/10. Oct/2017-10-14 0000_004_Whatsapp.jpg'
'./IMG-20180730-WA0002-1.jpg' --> '2018/07. Jul/2018-07-30 0000_002_Whatsapp.jpg'
Please to see I cheat using !=${CreateDate;} so exiftool only compares date in CreateDate. This because I fail to use -d %format so the space in middle of "Date Time" makes -if stop comparing at the space. Also, the months is only three characters, because recently I make very big mistake with bad format like this, but then it was very difficult to edit with -Tagsfromfile, so I must come here to learn the hardlink tag to fix them. Sorry Im not preacher, but please to edit if you like the whole words instead.


This like the first one, but for names with CreateDate in Filename
-if "$filename ne ${filename;s/^(.{19}).*/$1/} and ${Filename;s/^(.{19}).*/$1/} eq ${Filename;s/^(\D{3}-(19|20)\d{6}-\D\D\d{4}).*/$1/}" 
-if "${filename; s/^....(.{8}).*/$1/}==${CreateDate;}"   
-d "%Y%m%d-%B %H%M"
-TestName"<${FileName;s/.{4}(.{4})(..)(..)-...(...).*/$1\/$2./} ${CreateDate;s/.*-(.*) .*/$1\//}${FileName;s/.{4}(.{4})(..)(..)-...(...).*/$1-$2-$3 /}${CreateDate;s/.* (.*)/$1_/}${filename; s/.{12}-...(...).*/$1/}%-c_Whatsapp.%le"   .                     
-execute
- common_args Your extensions and Dir and if you want to recurse?


For names with CreateDate in Filename, it makes the output like ...
'./IMG-20140925-WA0016.jpg' ----> '2014/09. September/2014-09-25 2048_016_Whatsapp.jpg'

Since Im used "%Y%m%d-%B %H%M" to control date-tags, Im cheat again with == so -if stops at "-" to only conduct the date.
Now we can use changes like ${CreateDate;s/.*-(.*) .*/$1} to get only the month words. Please also to see the %H%M so that minutes go to filename, because Im afraid to use only "20" because Im think 2048 is much better when also you have 0000, but you can destroy %M if you like it better. Also, beware this gives whole month words!! If its me, Im only use first three characters, but thinking you want whole words, so please to change one or the other to keep formats the same.

Im no idea if you can make it all on one command, but only tested each one by itself. I know there is -@ Argsfile for long commands, but always Im keeping everything on commandline, because Im learning the commandline too so is good practice, but this is longer than anything else in my whole life. When you save it all for testing, then Im sure you already know the TestName->Filename. If when you decide on the new filenames, and make the edits with the helper function, Im very much like to see the edit. Happy testing!
Windows8.1-64bit, exiftool-v12.11(standalone), sed-v4.0.7

Inferi0r

#8
@Luuk2005: I am so sorry, I was offline last hours to fix the command, now I am back online and I see you shared a lot of usefull information. Let me first share my working and in full command:

exiftool -if "${FileName;$_=substr($_,4,8)} eq ${FileCreateDate;DateFmt('%Y%m%d')}"
"-FileName<OUTPUT/${FileCreateDate;DateFmt('%Y/%m. %B')}/${FileName;s/.*(\d{4})(\d\d)(\d\d).*/$1-$2-$3 /}
${FileCreateDate;DateFmt('%H%M_')}${FileName;$_=substr($_,16,3)}%-c_Whatsapp.%le" -execute
-if "${FileName;$_=substr($_,4,8)} ne ${FileCreateDate;DateFmt('%Y%m%d')}"
"-FileName<OUTPUT/${FileName;s/.*(\d{4})(\d\d)\d\d.*/$1\/$2#/
;s/01#/01. januari/;s/02#/02. februari/;s/03#/03. maart/;s/04#/04. april/;s/05#/05. mei/;s/06#/06. juni/;s/07#/07. juli/
;s/08#/08. augustus/;s/09#/09. september/;s/10#/10. oktober/;s/11#/11. november/;s/12#/12. december/}/
${FileName;s/.*(\d{4})(\d\d)(\d\d).{4}(\d{3}).*/$1-$2-$3 0000_$4/}%-c_Whatsapp.%le" -common_args "DIR"


IMG-20140925-WA0019.jpg (FileCreateDate=2014:09:25) --> 'OUTPUT/2014/09. september/2014-09-25 2221_019_Whatsapp.jpg'
IMG-20140925-WA0021.jpg (FileCreateDate=2014:09:25) --> 'OUTPUT/2014/09. september/2014-09-25 2221_021_Whatsapp.jpg'
IMG-20090925-WA0020-1.jpg' (FileCreateDate=2019:01:01) --> 'OUTPUT/2009/09. september/2009-09-25 0000_020_Whatsapp.jpg'
IMG-20101025-WA0020.jpg' (FileCreateDate=2010:01:01) --> 'OUTPUT/2010/10. oktober/2010-10-25 0000_020_Whatsapp.jpg'
IMG-20140202-WA0020.jpg-1.jpg' (FileCreateDate=2014:01:01) --> 'OUTPUT/2014/02. februari/2014-02-02 0000_020_Whatsapp.jpg'


Maybe, it is possible to do it more short than above,, but at least this seems to be working in full, thank you all for the help. Tomorrow, I will have a look at the other suggestions.

@Luuk2005: at least I can share with you that the risk with just simple 01/02 replacements is that that numbers are already in the file or directory number because of the used Year. That why I finally came up with the easy but very usefull trick to add a '#' myself at first.

Quote from: Luuk2005 on October 07, 2020, 06:27:06 PM
Since Im used "%Y%m%d-%B %H%M" to control date-tags, Im cheat again with == so -if stops at "-" to only conduct the date.
Now we can use changes like ${CreateDate;s/.*-(.*) .*/$1} to get only the month words.

So, I learned about the ${CreateDate;DateFmt('%m')}, which is a very easy and quick solutions for splitting dates like that  8)

@StarGeek thanks for the DateFmt, thanks to that I/we can fully remove the -d function in our queries. I have seen your adjustment of the Exiftool config as well, great to know thats possible as a last resort!

Luuk2005

#9
Greetings Inferi0r, it looks to be excellent!
Thanks much for posting the DateFmt, because Im not that far yet, so always Im using s/// to get the parts, and this format is MUCH better for the editing.
Also mine is over strict to match filenames, so is slower. Dont try my codes because Im think you mean CreateDate literally lol, instead of FileCreateDate.
Please also to be careful look for names like aaa.jpg or 12341234.jpg because the exiftool would then want to move them also.
Nice work!
Windows8.1-64bit, exiftool-v12.11(standalone), sed-v4.0.7