phtools 0.11.2 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -4
- data/TODO.md +3 -0
- data/exe/phbackup +18 -17
- data/exe/phfixdto +29 -28
- data/exe/phfixfmd +22 -21
- data/exe/phgettags +28 -27
- data/exe/phls +29 -28
- data/exe/phmove +27 -26
- data/exe/phrename +66 -53
- data/exe/phtools +2 -1
- data/lib/phls.rb +5 -3
- data/lib/phrename.rb +40 -17
- data/lib/phtools/ph_file.rb +12 -5
- data/lib/phtools/runner.rb +6 -10
- data/lib/phtools/utils/ruby_version.rb +4 -2
- data/lib/phtools/version.rb +1 -1
- data/phtools.gemspec +2 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50c505c8d68963e5316f8d25a73ebff6c36522af
|
4
|
+
data.tar.gz: 1537c9723b68f2f413bb15f0bdee7df181a1f379
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 589135775c85fb42c059b097207ad2f8d4f7e2c89d63c2e29cb2e96f9301ad18e0084ad68fb26a98f16cb2e30fdd11996d073229f4b3e03338dda2d95d04c087
|
7
|
+
data.tar.gz: ca264e71b619e5c63ce81e28ac1b0a6d36740bcc9e0cadeec8d3b3628dfe9aea7c4288e191a3e21bfdd3968e4146e96c6daf719aeb9226b3401bd227fdad0732
|
data/.rubocop.yml
CHANGED
@@ -8,9 +8,9 @@ AllCops:
|
|
8
8
|
- 'Guardfile'
|
9
9
|
TargetRubyVersion: 2.3
|
10
10
|
|
11
|
-
Style/Encoding:
|
12
|
-
|
13
|
-
|
11
|
+
# Style/Encoding:
|
12
|
+
# EnforcedStyle: when_needed
|
13
|
+
# Enabled: true
|
14
14
|
|
15
15
|
#Style/FrozenStringLiteralComment:
|
16
16
|
# EnforcedStyle: always
|
@@ -24,6 +24,9 @@ Metrics/ClassLength:
|
|
24
24
|
Metrics/MethodLength:
|
25
25
|
Enabled: false
|
26
26
|
|
27
|
+
Metrics/BlockNesting:
|
28
|
+
Enabled: false
|
29
|
+
|
27
30
|
Metrics/CyclomaticComplexity:
|
28
31
|
Enabled: false
|
29
32
|
|
@@ -39,5 +42,11 @@ Style/Documentation:
|
|
39
42
|
Style/SignalException:
|
40
43
|
Enabled: false
|
41
44
|
|
42
|
-
Style/
|
45
|
+
Style/DateTime:
|
46
|
+
Enabled: false
|
47
|
+
|
48
|
+
Style/UnneededInterpolation:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Naming/AccessorMethodName:
|
43
52
|
Enabled: false
|
data/TODO.md
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
- [x] phls: use init method to initialize variables
|
8
8
|
- [x] phls: change -r to -R
|
9
9
|
- [ ] phls: make it work with .folders (like ftls did)
|
10
|
+
- [x] phls: sort files in alphabet order
|
10
11
|
|
11
12
|
### phmove
|
12
13
|
- [x] phmove: create phmove tool based on ftarrange code (see ftools repo)
|
@@ -23,9 +24,11 @@
|
|
23
24
|
- [x] phrename: make it safe and smart. Once the file was renamed to PHTOOL standard, re-run of phrename should not change the date-time info unless options -t or -s are used. If user wants to reset file name using exif tag - 1st clean it `phrename --clean`, then rename `phrename -a anb`
|
24
25
|
- [ ] phrename: make new usage mode: `phrename -t TAG`. Useful if user wants to re-set date-time using TAG keeping author-nickname unchanged
|
25
26
|
- [ ] phrename: add QuickTime.CreationDate into analysis when calculate date-time-in-the-name (useful for iOS mov files). In iOS QuickTime.CreateDate is wrong (always in Grinvich zone), while QuickTime.CreationDate is Ok
|
27
|
+
- [ ] phrename: new mode 'manual rename' renames files using given date-time template, author name and prefix. Good for mass renaming of the scanned films and photos (when date-time is not set in the tags and only human knows the real date-time)
|
26
28
|
|
27
29
|
### phgettags
|
28
30
|
- [x] create phgettags (based on ftmtags)
|
31
|
+
- [ ] support option -e --composite of exiftool
|
29
32
|
|
30
33
|
### phfixfmd
|
31
34
|
- [x] create phfixfmd - fix FileModifyDate to get equal to date-time-in-the-name
|
data/exe/phbackup
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,25 +9,25 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
#{tool_name} copies the input file to backup directory.
|
16
|
-
Optimized to be used with other *phtools* via pipes.
|
17
|
-
Example: phls | #{tool_name} | phrename ...
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} copies the input file to backup directory.
|
17
|
+
Optimized to be used with other *phtools* via pipes.
|
18
|
+
Example: phls | #{tool_name} | phrename ...
|
18
19
|
|
19
|
-
Usage:
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
Usage:
|
21
|
+
#{tool_name} [--backup DIR] [-D]
|
22
|
+
#{tool_name} -h | --help
|
23
|
+
#{tool_name} -v | --version
|
23
24
|
|
24
|
-
Options:
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
DOCOPT
|
25
|
+
Options:
|
26
|
+
-b DIR --backup=DIR Sets the backup directory [Default: ./backup]
|
27
|
+
-D --debug Turn on debugging (verbose) mode
|
28
|
+
-h --help Show this screen.
|
29
|
+
-v --version Show version.
|
30
|
+
DOCOPT
|
30
31
|
|
31
32
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
32
33
|
end
|
data/exe/phfixdto
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,36 +9,36 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
|
16
|
-
the date-time encoded in the filename (date-time-in-the-name). The file should
|
17
|
-
be renamed to phtools Standard Name before using this command (use phrename for
|
18
|
-
this).
|
19
|
-
|
20
|
-
(http://www.sno.phy.queensu.ca/~phil/exiftool/).
|
21
|
-
|
22
|
-
to be passed to STDIN, does its job on the files and produces no useful
|
23
|
-
(for other pipe-optimized programs) output.
|
24
|
-
In other words this command is intended to be used with other programs
|
25
|
-
connected via input pipes as a last command in the pipe chain, e.g.:
|
26
|
-
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} updates the input file's DateTimeOriginal (CreateDate) tags with
|
17
|
+
the date-time encoded in the filename (date-time-in-the-name). The file should
|
18
|
+
be renamed to phtools Standard Name before using this command (use phrename for
|
19
|
+
this).
|
20
|
+
This program uses external utility ExifTool created by Phil Harvey
|
21
|
+
(http://www.sno.phy.queensu.ca/~phil/exiftool/).
|
22
|
+
#{tool_name} acts as a 'sink' program meaning it expects the input files
|
23
|
+
to be passed to STDIN, does its job on the files and produces no useful
|
24
|
+
(for other pipe-optimized programs) output.
|
25
|
+
In other words this command is intended to be used with other programs
|
26
|
+
connected via input pipes as a last command in the pipe chain, e.g.:
|
27
|
+
phls | phrename - a anb | #{tool_name}
|
27
28
|
|
28
|
-
Usage:
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
Usage:
|
30
|
+
#{tool_name} [-N] [-D]
|
31
|
+
#{tool_name} -h | --help
|
32
|
+
#{tool_name} -v | --version
|
32
33
|
|
33
|
-
Options:
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
DOCOPT
|
34
|
+
Options:
|
35
|
+
-N --no_run Dry-run mode means no run exiftool command, only generate script
|
36
|
+
file 'exif_tagger_dto.txt'. User can check the script and
|
37
|
+
manually run the command: `exiftool -@ exif_tagger_dto.txt`
|
38
|
+
-D --debug Turn on debugging (verbose) mode
|
39
|
+
-h --help Show this screen.
|
40
|
+
-v --version Show version.
|
41
|
+
DOCOPT
|
41
42
|
|
42
43
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
43
44
|
end
|
data/exe/phfixfmd
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,29 +9,29 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
|
16
|
-
in the filename (date-time-in-the-name). Therefore the file should be renamed
|
17
|
-
to phtools Standard Name before using this command (use phrename for this).
|
18
|
-
|
19
|
-
to be passed to STDIN and after the job is done it produces STDOUT with the list
|
20
|
-
of processed files. In other words this command is intended to be used with
|
21
|
-
other programs connected via pipes, e.g.:
|
22
|
-
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} changes an input file's modify-date according to the date encoded
|
17
|
+
in the filename (date-time-in-the-name). Therefore the file should be renamed
|
18
|
+
to phtools Standard Name before using this command (use phrename for this).
|
19
|
+
#{tool_name} acts as a 'filter' program meaning it expects the input files
|
20
|
+
to be passed to STDIN and after the job is done it produces STDOUT with the list
|
21
|
+
of processed files. In other words this command is intended to be used with
|
22
|
+
other programs connected via pipes, e.g.:
|
23
|
+
phls | phrename -a anb | #{tool_name} | phmove ~/targed/folder
|
23
24
|
|
24
|
-
Usage:
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
Usage:
|
26
|
+
#{tool_name} [-D]
|
27
|
+
#{tool_name} -h | --help
|
28
|
+
#{tool_name} -v | --version
|
28
29
|
|
29
|
-
Options:
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
DOCOPT
|
30
|
+
Options:
|
31
|
+
-D --debug Turn on debugging (verbose) mode
|
32
|
+
-h --help Show this screen.
|
33
|
+
-v --version Show version.
|
34
|
+
DOCOPT
|
34
35
|
|
35
36
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
36
37
|
end
|
data/exe/phgettags
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,33 +9,33 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
to be passed to STDIN, does its job on the input files and produces no useful
|
19
|
-
(for other pipe-optimized programs) output.
|
20
|
-
In other words this command is intended to be used with other programs
|
21
|
-
connected via input pipes as a last command in the pipe chain, e.g.:
|
22
|
-
|
23
|
-
|
24
|
-
This program uses external utility ExifTool created by Phil Harvey
|
25
|
-
(http://www.sno.phy.queensu.ca/~phil/exiftool/).
|
26
|
-
|
27
|
-
Usage:
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
Options:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
DOCOPT
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} extracts the list of tags stored inside the given file.
|
17
|
+
|
18
|
+
#{tool_name} acts as a 'sink' program meaning it expects the input files
|
19
|
+
to be passed to STDIN, does its job on the input files and produces no useful
|
20
|
+
(for other pipe-optimized programs) output.
|
21
|
+
In other words this command is intended to be used with other programs
|
22
|
+
connected via input pipes as a last command in the pipe chain, e.g.:
|
23
|
+
phls | #{tool_name}
|
24
|
+
|
25
|
+
This program uses external utility ExifTool created by Phil Harvey
|
26
|
+
(http://www.sno.phy.queensu.ca/~phil/exiftool/).
|
27
|
+
|
28
|
+
Usage:
|
29
|
+
#{tool_name} [-f] [-D]
|
30
|
+
#{tool_name} -h | --help
|
31
|
+
#{tool_name} -v | --version
|
32
|
+
|
33
|
+
Options:
|
34
|
+
-f --full_dump Print all tags
|
35
|
+
-D --debug Turn on debugging (verbose) mode
|
36
|
+
-h --help Show this screen.
|
37
|
+
-v --version Show version.
|
38
|
+
DOCOPT
|
38
39
|
|
39
40
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
40
41
|
end
|
data/exe/phls
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,37 +9,37 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
|
16
|
-
output. In short it acts like a smart 'ls' command (or 'dir' in Windows).
|
17
|
-
Set DIRs to be scanned as a parameters. If no DIRs are set - current dir (.)
|
18
|
-
will be scanned. Set FILEMASKs as a parameters - and only files matching the
|
19
|
-
masks will be processed. If no FILEMASK is set '*.*' will be used by-default.
|
20
|
-
To avoid unnessesary mask extraction by OS - put it in ''.
|
21
|
-
Note, #{tool_name} works only with phtools-friendly file types: #{file_type * ','}
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} scans given directories and generates list of files to standard
|
17
|
+
output. In short it acts like a smart 'ls' command (or 'dir' in Windows).
|
18
|
+
Set DIRs to be scanned as a parameters. If no DIRs are set - current dir (.)
|
19
|
+
will be scanned. Set FILEMASKs as a parameters - and only files matching the
|
20
|
+
masks will be processed. If no FILEMASK is set '*.*' will be used by-default.
|
21
|
+
To avoid unnessesary mask extraction by OS - put it in ''.
|
22
|
+
Note, #{tool_name} works only with phtools-friendly file types: #{file_type * ','}
|
22
23
|
|
23
|
-
|
24
|
-
from STDIN, it generates list of files based on input parameters and send it
|
25
|
-
to STDOUT.
|
26
|
-
|
27
|
-
connected via pipes as a 1st command in the pipe chain, e.g.:
|
28
|
-
|
29
|
-
sends all found phtools friendly files filtered with *aaa* to phrename command.
|
24
|
+
#{tool_name} acts as a 'source' program meaning it does not require any input
|
25
|
+
from STDIN, it generates list of files based on input parameters and send it
|
26
|
+
to STDOUT.
|
27
|
+
In other words this command is intended to be used with other programs
|
28
|
+
connected via pipes as a 1st command in the pipe chain, e.g.:
|
29
|
+
#{tool_name} abc '*aaa*' | phrename -a anb => scans 'abc' folder and
|
30
|
+
sends all found phtools friendly files filtered with *aaa* to phrename command.
|
30
31
|
|
31
|
-
Usage:
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
Usage:
|
33
|
+
#{tool_name} [-D] [-R] [DIR_OR_FILEMASK...]
|
34
|
+
#{tool_name} -h | --help
|
35
|
+
#{tool_name} -v | --version
|
35
36
|
|
36
|
-
Options:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
DOCOPT
|
37
|
+
Options:
|
38
|
+
-D --debug Turn on debugging (verbose) mode
|
39
|
+
-R --recursive Recursively scan directories
|
40
|
+
-h --help Show this screen.
|
41
|
+
-v --version Show version.
|
42
|
+
DOCOPT
|
42
43
|
|
43
44
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
44
45
|
end
|
data/exe/phmove
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,32 +9,32 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
#{tool_name} moves input file(s) into TARGET_FOLDER.
|
16
|
-
If TARGET_FOLDER is not set - current folder (.) will be used as a target.
|
17
|
-
If --arrange option is set it separates photo files, RAW photo files and VIDEO files
|
18
|
-
to corresponding subfolders.
|
19
|
-
phtools friendly files: #{file_type * ','}
|
20
|
-
|
21
|
-
Optimized to be used with other *phtools* via pipes.
|
22
|
-
Example: phls | phrename -a anb | #{tool_name} -a target/folder
|
23
|
-
|
24
|
-
|
25
|
-
Usage:
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
Options:
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
DOCOPT
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} moves input file(s) into TARGET_FOLDER.
|
17
|
+
If TARGET_FOLDER is not set - current folder (.) will be used as a target.
|
18
|
+
If --arrange option is set it separates photo files, RAW photo files and VIDEO files
|
19
|
+
to corresponding subfolders.
|
20
|
+
phtools friendly files: #{file_type * ','}
|
21
|
+
|
22
|
+
Optimized to be used with other *phtools* via pipes.
|
23
|
+
Example: phls | phrename -a anb | #{tool_name} -a target/folder
|
24
|
+
|
25
|
+
|
26
|
+
Usage:
|
27
|
+
#{tool_name} [-D] [-a] [TARGET_FOLDER]
|
28
|
+
#{tool_name} -h | --help
|
29
|
+
#{tool_name} -v | --version
|
30
|
+
|
31
|
+
Options:
|
32
|
+
-a --arrange Move photos to TARGET_FOLDER, videos to TARGET_FOLDER/VIDEO
|
33
|
+
raw-files to TARGET_FOLDER/RAW
|
34
|
+
-D --debug Turn on debugging (verbose) mode
|
35
|
+
-h --help Show this screen.
|
36
|
+
-v --version Show version.
|
37
|
+
DOCOPT
|
37
38
|
|
38
39
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
39
40
|
end
|
data/exe/phrename
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
module PhTools
|
@@ -8,68 +9,80 @@ module PhTools
|
|
8
9
|
require tool_name.to_s
|
9
10
|
|
10
11
|
file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
|
11
|
-
usage =
|
12
|
-
***************************************************
|
13
|
-
phtools - *Keep Your Photos In Order* (c) ANB
|
14
|
-
***************************************************
|
15
|
-
#{tool_name} renames the input file to Standard Name:
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
By default date-time information will be taken from EXIF area as the 1st non-zero
|
21
|
-
value of the tags (shown in the order the program scans values):
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
Example: input file DSC03455.JPG will be renamed to 20130108-124145_ANB DSC03455.JPG
|
12
|
+
usage = <<~DOCOPT
|
13
|
+
***************************************************
|
14
|
+
phtools - *Keep Your Photos In Order* (c) ANB
|
15
|
+
***************************************************
|
16
|
+
#{tool_name} renames the input file to Standard Name:
|
17
|
+
YYYYmmdd-HHMMSS_AAA ORIGINAL.EXT, where:
|
18
|
+
YYYYmmdd-HHMMSS - Date-Time of photo creation,
|
19
|
+
AAA - the author nickname,
|
20
|
+
ORIGINAL.EXT - the photo name given by digital camera.
|
21
|
+
By default date-time information will be taken from EXIF area as the 1st non-zero
|
22
|
+
value of the tags (shown in the order the program scans values):
|
23
|
+
EXIF:DateTimeOriginal -> IPTC:DateCreated + IPTC:TimeCreated -> XMP:DateCreated ->
|
24
|
+
-> EXIF:CreateDate -> XMP:CreateDate -> IPTC:DigitalCreationDate + IPTC:DigitalCreationTime ->
|
25
|
+
-> FileModifyDate
|
26
|
+
Example: input file DSC03455.JPG will be renamed to 20130108-124145_ANB DSC03455.JPG
|
27
|
+
|
28
|
+
Input file should be one of the supported types: #{file_type * ','}.
|
29
|
+
#{tool_name} acts as a 'filter' meaning it expects the input files to be passed
|
30
|
+
to STDIN and after the job is done it produces STDOUT with the list of renamed
|
31
|
+
files. In other words this command is intended to be used with other programs
|
32
|
+
connected via pipes, e.g.:
|
33
|
+
phls | #{tool_name} -a anb | phmove ~/targed/folder
|
34
|
+
|
35
|
+
The program is designed to be safe to re-run on the same file several times
|
36
|
+
- every re-run produces the same result (idempotent behaviour).
|
37
|
+
Once the file was renamed to Standard Name, the date-time kept in the name
|
38
|
+
is considered as a master date-time of the photo creation and will not be
|
39
|
+
changed by re-running #{tool_name} unless user explicitly sets '-t' or '-s' option.
|
26
40
|
|
27
|
-
|
28
|
-
|
29
|
-
to STDIN and after the job is done it produces STDOUT with the list of renamed
|
30
|
-
files. In other words this command is intended to be used with other programs
|
31
|
-
connected via pipes, e.g.:
|
32
|
-
phls | #{tool_name} -a anb | phmove ~/targed/folder
|
41
|
+
This program uses external utility ExifTool created by Phil Harvey
|
42
|
+
(http://www.sno.phy.queensu.ca/~phil/exiftool/).
|
33
43
|
|
34
|
-
|
35
|
-
-
|
36
|
-
|
37
|
-
|
38
|
-
|
44
|
+
Usage:
|
45
|
+
#{tool_name} -a NICK [-t TAG] [-D]
|
46
|
+
#{tool_name} -s DELTA [-D]
|
47
|
+
#{tool_name} -m DT -a NICK [-s DELTA] [-H HEADER][-D]
|
48
|
+
#{tool_name} -c [-H HEADER][-D]
|
49
|
+
#{tool_name} -h | --help
|
50
|
+
#{tool_name} -v | --version
|
39
51
|
|
40
|
-
|
41
|
-
|
52
|
+
Options:
|
53
|
+
-a NICK --author=NICK Author nickname size should be #{PhFile::NICKNAME_SIZE} chars,
|
54
|
+
supports only latin ASCII chars (e.g. ANB).
|
55
|
+
No digits, no spaces, no other non-word chars allowed.
|
42
56
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#{tool_name} -v | --version
|
57
|
+
-t TAG --tag_date=TAG Force program to use TAG as a Date-Time creation
|
58
|
+
info instead of standard phtools tags.
|
59
|
+
You can retreive all existing tags using command:
|
60
|
+
`phls filename|phgettags -f` OR
|
61
|
+
`exiftool -s filename`
|
49
62
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
-s DELTA --shift_time=DELTA DELTA (in seconds) will be added to Date-Time value
|
64
|
+
kept in the name. If DELTA is positive the photo
|
65
|
+
will become yonger: e.g. 20140720-100005, DELTA = 65
|
66
|
+
result = 20140720-100110. If DELTA is negative the photo
|
67
|
+
will get DELTA seconds older.
|
68
|
+
In manual_date mode -s DELTA is used increment
|
69
|
+
date-time-in-the-name for every processed file
|
54
70
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
`phls filename|phgettags -f` OR
|
59
|
-
`exiftool -s filename`
|
71
|
+
-m DT --manual_date=DT Force program to use given date-time to rename files.
|
72
|
+
DT should comply with phtools standard. Example:
|
73
|
+
'20171029-204805'
|
60
74
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
will get DELTA seconds older.
|
75
|
+
-H HEADER --header=HEADER In manual_date mode adds HEADER to the begining
|
76
|
+
of the original basename.
|
77
|
+
In clean mode removes HEADER from the beginning of
|
78
|
+
the original basename.
|
66
79
|
|
67
|
-
|
80
|
+
-c --clean Rename file back to it's original name
|
68
81
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
DOCOPT
|
82
|
+
-D --debug Turn on debugging (verbose) mode
|
83
|
+
-h --help Show this screen.
|
84
|
+
-v --version Show version.
|
85
|
+
DOCOPT
|
73
86
|
|
74
87
|
PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
|
75
88
|
end
|
data/exe/phtools
CHANGED
data/lib/phls.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
require 'phtools/runner'
|
@@ -14,13 +15,14 @@ module PhTools
|
|
14
15
|
def run!
|
15
16
|
@dirs_to_scan.each do |dir|
|
16
17
|
fmask = File.join(dir, @options_cli['--recursive'] ? '**' : '', "{#{@filemasks * ','}}")
|
17
|
-
Dir.glob(fmask, File::FNM_CASEFOLD)
|
18
|
+
files = Dir.glob(fmask, File::FNM_CASEFOLD)
|
19
|
+
files_sorted = files.sort_by(&:downcase)
|
20
|
+
files_sorted.each { |f| output_file(PhFile.new(f)) if File.file?(f) }
|
18
21
|
end
|
19
|
-
|
20
22
|
rescue SignalException
|
21
23
|
PhTools.puts_error 'EXIT on user interrupt Ctrl-C'
|
22
24
|
exit 1
|
23
|
-
rescue => e
|
25
|
+
rescue StandardError => e
|
24
26
|
PhTools.puts_error "FATAL: #{e.message}", e
|
25
27
|
exit 1
|
26
28
|
end
|
data/lib/phrename.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
require 'date'
|
@@ -16,14 +17,27 @@ module PhTools
|
|
16
17
|
private
|
17
18
|
|
18
19
|
def validate_options
|
19
|
-
if @options_cli['--
|
20
|
+
if @options_cli['--manual_date']
|
21
|
+
@mode = :manual_rename
|
22
|
+
@manual_date = PhFile.get_date_time(@options_cli['--manual_date'])
|
23
|
+
fail PhTools::Error, '--manual_date value is incorrect' if @manual_date == PhFile::ZERO_DATE
|
24
|
+
@author = @options_cli['--author'].upcase
|
25
|
+
ok, msg = PhFile.validate_author(@author)
|
26
|
+
fail PhTools::Error, msg unless ok
|
27
|
+
@shift_seconds = @options_cli['--shift_time'].to_i
|
28
|
+
@header = @options_cli['--header'].to_s.strip
|
29
|
+
|
30
|
+
elsif @options_cli['--author']
|
20
31
|
@mode = :rename
|
21
32
|
@author = @options_cli['--author'].upcase
|
22
33
|
ok, msg = PhFile.validate_author(@author)
|
23
34
|
fail PhTools::Error, msg unless ok
|
24
35
|
@user_tag_date = @options_cli['--tag_date'] || ''
|
36
|
+
|
25
37
|
elsif @options_cli['--clean']
|
26
38
|
@mode = :clean
|
39
|
+
@header = @options_cli['--header'].to_s.strip
|
40
|
+
|
27
41
|
elsif @options_cli['--shift_time']
|
28
42
|
@mode = :shift_time
|
29
43
|
@shift_seconds = @options_cli['--shift_time'].to_i
|
@@ -39,7 +53,7 @@ module PhTools
|
|
39
53
|
if phfile_out.basename_is_standard? && @user_tag_date.empty?
|
40
54
|
# change only author, keeping date-time safe
|
41
55
|
phfile_out.standardize!(author: @author)
|
42
|
-
info_msg = "'#{phfile.basename + phfile.extname}' already standard name. Keeping date-time
|
56
|
+
info_msg = "'#{phfile.basename + phfile.extname}' already standard name. Keeping date-time-in-name unchanged"
|
43
57
|
else # full rename
|
44
58
|
begin
|
45
59
|
tags = MiniExiftool.new(phfile.filename,
|
@@ -52,45 +66,45 @@ module PhTools
|
|
52
66
|
if @user_tag_date.empty?
|
53
67
|
# searching for DateTime stamp value in the tags using priority:
|
54
68
|
# EXIF:DateTimeOriginal -> IPTC:DateCreated + IPTC:TimeCreated -> XMP:DateCreated -> EXIF:CreateDate -> XMP:CreateDate -> IPTC:DigitalCreationDate + IPTC:DigitalCreationTime -> FileModifyDate
|
55
|
-
if !tags.date_time_original.nil? && tags.date_time_original.
|
69
|
+
if !tags.date_time_original.nil? && tags.date_time_original.is_a?(DateTime)
|
56
70
|
# EXIF:DateTimeOriginal or IPTC:DateCreated + IPTC:TimeCreated
|
57
71
|
dto = tags.date_time_original
|
58
|
-
tag_used =
|
72
|
+
tag_used = 'DateTimeOriginal'
|
59
73
|
|
60
|
-
elsif !tags.date_created.nil? && tags.date_created.
|
74
|
+
elsif !tags.date_created.nil? && tags.date_created.is_a?(DateTime)
|
61
75
|
# XMP:DateCreated
|
62
76
|
dto = tags.date_created
|
63
|
-
tag_used =
|
77
|
+
tag_used = 'DateCreated'
|
64
78
|
|
65
|
-
elsif !tags.create_date.nil? && tags.create_date.
|
79
|
+
elsif !tags.create_date.nil? && tags.create_date.is_a?(DateTime)
|
66
80
|
# EXIF:CreateDate or XMP:CreateDate or! QuickTime:CreateDate
|
67
81
|
dto = tags.create_date
|
68
|
-
tag_used =
|
82
|
+
tag_used = 'CreateDate'
|
69
83
|
|
70
84
|
elsif !tags.digital_creation_date.nil? &&
|
71
85
|
!tags.digital_creation_time.nil? &&
|
72
|
-
tags.digital_creation_date.
|
73
|
-
tags.digital_creation_time.
|
86
|
+
tags.digital_creation_date.is_a?(String) &&
|
87
|
+
tags.digital_creation_time.is_a?(String)
|
74
88
|
# IPTC:DigitalCreationDate + IPTC:DigitalCreationTime
|
75
|
-
dcdt = tags.digital_creation_date +
|
89
|
+
dcdt = tags.digital_creation_date + ' ' + tags.digital_creation_time
|
76
90
|
begin
|
77
91
|
s = dcdt.sub(/^(\d+):(\d+):/, '\1-\2-')
|
78
92
|
dto = DateTime.parse(s)
|
79
93
|
rescue ArgumentError
|
80
94
|
dto = PhFile::ZERO_DATE
|
81
95
|
end
|
82
|
-
tag_used =
|
96
|
+
tag_used = 'DigitalCreationDate + DigitalCreationTime'
|
83
97
|
|
84
98
|
else
|
85
99
|
# FileModifyDate
|
86
100
|
dto = File.mtime(phfile.filename).to_datetime
|
87
|
-
tag_used =
|
101
|
+
tag_used = 'FileModifyDate'
|
88
102
|
end
|
89
103
|
|
90
104
|
else
|
91
105
|
# tag is set by the user
|
92
106
|
fail PhTools::Error, "tag #{@user_tag_date} is not found in a file" unless tags[@user_tag_date]
|
93
|
-
fail PhTools::Error, "tag #{@user_tag_date} is not a DateTime type" unless tags[@user_tag_date].
|
107
|
+
fail PhTools::Error, "tag #{@user_tag_date} is not a DateTime type" unless tags[@user_tag_date].is_a?(DateTime)
|
94
108
|
dto = tags[@user_tag_date] || PhFile::ZERO_DATE
|
95
109
|
tag_used = "#{@user_tag_date}"
|
96
110
|
end
|
@@ -99,18 +113,27 @@ module PhTools
|
|
99
113
|
end
|
100
114
|
|
101
115
|
when :clean
|
102
|
-
phfile_out.cleanse!
|
116
|
+
phfile_out.cleanse!(basename_clean: phfile_out.basename_clean.sub(/^#{@header}/, ''))
|
103
117
|
|
104
118
|
when :shift_time
|
105
119
|
fail PhTools::Error, 'non-standard file name' unless phfile_out.basename_is_standard?
|
106
120
|
phfile_out.standardize!(date_time: phfile_out.date_time + @shift_seconds * (1.0 / 86_400))
|
121
|
+
|
122
|
+
when :manual_rename
|
123
|
+
if phfile_out.basename_is_standard?
|
124
|
+
# keeping date-time safe
|
125
|
+
info_msg = "'#{phfile.basename + phfile.extname}' already standard name. Keeping date-time-in-name unchanged"
|
126
|
+
else # renaming
|
127
|
+
basename_clean = (@header.empty? ? '' : @header) + phfile_out.basename_clean
|
128
|
+
phfile_out.standardize!(date_time: @manual_date, author: @author, basename_clean: basename_clean)
|
129
|
+
@manual_date += @shift_seconds * (1.0 / 86_400)
|
130
|
+
end
|
107
131
|
end
|
108
132
|
|
109
133
|
FileUtils.mv(phfile.filename, phfile_out.filename, verbose: PhTools.debug) unless phfile == phfile_out
|
110
134
|
PhTools.puts_error info_msg unless info_msg.empty?
|
111
135
|
phfile_out
|
112
|
-
|
113
|
-
rescue => e
|
136
|
+
rescue StandardError => e
|
114
137
|
raise PhTools::Error, 'file renaming - ' + e.message
|
115
138
|
end
|
116
139
|
end
|
data/lib/phtools/ph_file.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
require 'phtools/error'
|
@@ -9,11 +10,11 @@ require 'fileutils'
|
|
9
10
|
|
10
11
|
module PhTools
|
11
12
|
# media type constants
|
12
|
-
FILE_TYPE_IMAGE_NORMAL = %w
|
13
|
-
FILE_TYPE_IMAGE_RAW = %w
|
13
|
+
FILE_TYPE_IMAGE_NORMAL = %w[jpg jpeg tif tiff png].freeze
|
14
|
+
FILE_TYPE_IMAGE_RAW = %w[orf arw dng].freeze
|
14
15
|
FILE_TYPE_IMAGE = FILE_TYPE_IMAGE_NORMAL + FILE_TYPE_IMAGE_RAW
|
15
|
-
FILE_TYPE_VIDEO = %w
|
16
|
-
FILE_TYPE_AUDIO = %w
|
16
|
+
FILE_TYPE_VIDEO = %w[avi mp4 mpg mts dv mov mkv m2t m2ts 3gp].freeze
|
17
|
+
FILE_TYPE_AUDIO = %w[wav].freeze
|
17
18
|
|
18
19
|
# phtools file name operations
|
19
20
|
class PhFile
|
@@ -49,6 +50,13 @@ module PhTools
|
|
49
50
|
[true, '']
|
50
51
|
end
|
51
52
|
|
53
|
+
def self.get_date_time(date_string)
|
54
|
+
/^(?<date>\d{8})-(?<time>\d{6})/ =~ date_string
|
55
|
+
DateTime.parse("#{Regexp.last_match(:date)}T#{Regexp.last_match(:time)}")
|
56
|
+
rescue ArgumentError
|
57
|
+
PhFile::ZERO_DATE
|
58
|
+
end
|
59
|
+
|
52
60
|
attr_reader :filename, :dirname, :extname, :type, :basename, :basename_part,
|
53
61
|
:basename_clean, :date_time, :author
|
54
62
|
|
@@ -181,7 +189,6 @@ module PhTools
|
|
181
189
|
|
182
190
|
return ZERO_DATE if strptime_string.empty?
|
183
191
|
DateTime.strptime(strptime_string, strptime_template)
|
184
|
-
|
185
192
|
rescue ArgumentError
|
186
193
|
return ZERO_DATE
|
187
194
|
end
|
data/lib/phtools/runner.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
# encoding: UTF-8
|
4
|
+
|
4
5
|
# (c) ANB Andrew Bizyaev
|
5
6
|
|
6
7
|
require 'phtools/utils/ruby_version.rb'
|
@@ -28,11 +29,10 @@ module PhTools
|
|
28
29
|
PhTools.debug = true if @options_cli['--debug']
|
29
30
|
|
30
31
|
validate_options
|
31
|
-
|
32
32
|
rescue Docopt::Exit => e
|
33
33
|
STDERR.puts e.message
|
34
34
|
exit 1
|
35
|
-
rescue => e
|
35
|
+
rescue StandardError => e
|
36
36
|
PhTools.puts_error "FATAL: #{e.message}", e
|
37
37
|
exit 1
|
38
38
|
ensure
|
@@ -59,29 +59,25 @@ module PhTools
|
|
59
59
|
end
|
60
60
|
|
61
61
|
process_after
|
62
|
-
|
63
62
|
rescue SignalException
|
64
63
|
PhTools.puts_error 'EXIT on user interrupt Ctrl-C'
|
65
64
|
exit 1
|
66
|
-
rescue => e
|
65
|
+
rescue StandardError => e
|
67
66
|
PhTools.puts_error "FATAL: #{e.message}", e
|
68
67
|
exit 1
|
69
68
|
end
|
70
69
|
|
71
70
|
private
|
72
71
|
|
73
|
-
def validate_options
|
74
|
-
end
|
72
|
+
def validate_options; end
|
75
73
|
|
76
|
-
def process_before
|
77
|
-
end
|
74
|
+
def process_before; end
|
78
75
|
|
79
76
|
def process_file(file)
|
80
77
|
file
|
81
78
|
end
|
82
79
|
|
83
|
-
def process_after
|
84
|
-
end
|
80
|
+
def process_after; end
|
85
81
|
|
86
82
|
def context
|
87
83
|
instance_variables.map do |item|
|
@@ -1,13 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
4
|
+
|
3
5
|
# (c) ANB Andrew Bizyaev
|
4
6
|
|
5
|
-
RUBY_VERSION_WANTED = '2.
|
7
|
+
RUBY_VERSION_WANTED = '2.4.0'
|
6
8
|
|
7
9
|
begin
|
8
10
|
fail "Ruby version must be >= #{RUBY_VERSION_WANTED}" if
|
9
11
|
RUBY_VERSION < RUBY_VERSION_WANTED
|
10
|
-
rescue => e
|
12
|
+
rescue StandardError => e
|
11
13
|
STDERR.puts e.message
|
12
14
|
exit 1
|
13
15
|
end
|
data/lib/phtools/version.rb
CHANGED
data/phtools.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'phtools/version'
|
@@ -8,13 +7,12 @@ Gem::Specification.new do |spec|
|
|
8
7
|
|
9
8
|
spec.name = 'phtools'
|
10
9
|
spec.version = PhTools::VERSION
|
11
|
-
# spec.date = '2016-08-23'
|
12
10
|
spec.authors = ["Andrew Bizyaev"]
|
13
11
|
spec.email = ["andrew.bizyaev@gmail.com"]
|
14
12
|
spec.license = 'MIT'
|
15
13
|
|
16
|
-
spec.summary = %q
|
17
|
-
spec.description = %q
|
14
|
+
spec.summary = %q(A set of usefull tools to manipulate photo-video files.)
|
15
|
+
spec.description = %q(A bundle of small CLI tools for arranging, renaming, tagging of the photo and video files. Helps to keep your photo-video assets in order.)
|
18
16
|
spec.homepage = "https://github.com/AndrewBiz/phtools.git"
|
19
17
|
|
20
18
|
spec.requirements = %q{ExifTool by Phil Harvey (http://www.sno.phy.queensu.ca/~phil/exiftool/)}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phtools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Bizyaev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -344,7 +344,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
344
344
|
requirements:
|
345
345
|
- ExifTool by Phil Harvey (http://www.sno.phy.queensu.ca/~phil/exiftool/)
|
346
346
|
rubyforge_project:
|
347
|
-
rubygems_version: 2.6.
|
347
|
+
rubygems_version: 2.6.13
|
348
348
|
signing_key:
|
349
349
|
specification_version: 4
|
350
350
|
summary: A set of usefull tools to manipulate photo-video files.
|