phtools 0.11.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|