phtools 0.10.0 → 0.11.1
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 +43 -0
- data/.rubocop_todo.yml +373 -0
- data/Guardfile +6 -3
- data/History.md +4 -0
- data/TODO.md +2 -0
- data/exe/phbackup +2 -1
- data/exe/phfixdto +2 -1
- data/exe/phfixfmd +2 -1
- data/exe/phgettags +2 -1
- data/exe/phls +2 -1
- data/exe/phmove +6 -3
- data/exe/phrename +2 -1
- data/exe/phtools +3 -1
- data/lib/phbackup.rb +2 -2
- data/lib/phevent.rb +2 -1
- data/lib/phfixdto.rb +4 -3
- data/lib/phfixfmd.rb +2 -2
- data/lib/phgettags.rb +7 -7
- data/lib/phls.rb +5 -6
- data/lib/phmove.rb +12 -21
- data/lib/phrename.rb +7 -6
- data/lib/phtagset.rb +2 -1
- data/lib/phtools/error.rb +2 -1
- data/lib/phtools/exif_tagger/error.rb +1 -0
- data/lib/phtools/exif_tagger/tag_collection.rb +17 -14
- data/lib/phtools/exif_tagger/tag_writer.rb +8 -7
- data/lib/phtools/exif_tagger/tags/_tag.rb +92 -37
- data/lib/phtools/exif_tagger/tags/_tag_array_of_strings.rb +35 -0
- data/lib/phtools/exif_tagger/tags/_tag_date.rb +25 -27
- data/lib/phtools/exif_tagger/tags/_tag_hash_of_strings.rb +39 -0
- data/lib/phtools/exif_tagger/tags/_tag_string.rb +32 -0
- data/lib/phtools/exif_tagger/tags/city.rb +7 -21
- data/lib/phtools/exif_tagger/tags/coded_character_set.rb +6 -21
- data/lib/phtools/exif_tagger/tags/collections.rb +20 -26
- data/lib/phtools/exif_tagger/tags/copyright.rb +6 -22
- data/lib/phtools/exif_tagger/tags/country.rb +6 -23
- data/lib/phtools/exif_tagger/tags/country_code.rb +5 -21
- data/lib/phtools/exif_tagger/tags/create_date.rb +17 -13
- data/lib/phtools/exif_tagger/tags/creator.rb +14 -25
- data/lib/phtools/exif_tagger/tags/date_time_original.rb +18 -13
- data/lib/phtools/exif_tagger/tags/gps_created.rb +21 -44
- data/lib/phtools/exif_tagger/tags/image_unique_id.rb +12 -27
- data/lib/phtools/exif_tagger/tags/keywords.rb +15 -27
- data/lib/phtools/exif_tagger/tags/location.rb +6 -23
- data/lib/phtools/exif_tagger/tags/modify_date.rb +8 -8
- data/lib/phtools/exif_tagger/tags/state.rb +6 -23
- data/lib/phtools/exif_tagger/tags/world_region.rb +6 -22
- data/lib/phtools/exif_tagger/tags.rb +2 -1
- data/lib/phtools/exif_tagger.rb +1 -0
- data/lib/phtools/ph_file.rb +35 -14
- data/lib/phtools/runner.rb +4 -4
- data/lib/phtools/utils.rb +1 -0
- data/lib/phtools/version.rb +2 -1
- data/lib/phtools.rb +11 -9
- metadata +7 -2
data/lib/phfixfmd.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -6,9 +7,8 @@ require 'phtools/runner'
|
|
6
7
|
|
7
8
|
module PhTools
|
8
9
|
class Phfixfmd < Runner
|
9
|
-
|
10
10
|
def self.about
|
11
|
-
|
11
|
+
'fixes FileModifyDate to be equal to date-time-in-the-name'
|
12
12
|
end
|
13
13
|
|
14
14
|
private
|
data/lib/phgettags.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -8,9 +9,8 @@ require 'phtools/exif_tagger'
|
|
8
9
|
|
9
10
|
module PhTools
|
10
11
|
class Phgettags < Runner
|
11
|
-
|
12
12
|
def self.about
|
13
|
-
|
13
|
+
'extracts the tags stored inside the file'
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -29,10 +29,10 @@ module PhTools
|
|
29
29
|
|
30
30
|
puts "******** FILE #{phfile} ********"
|
31
31
|
|
32
|
-
if
|
33
|
-
puts format('%-29s %s',
|
32
|
+
if !@options_cli['--full_dump']
|
33
|
+
puts format('%-29s %s', 'FileModifyDate', tags.FileModifyDate.to_s)
|
34
34
|
ExifTagger::TAGS_SUPPORTED.each do |tag|
|
35
|
-
puts
|
35
|
+
puts tag.to_s.camelize
|
36
36
|
ExifTagger::Tag.const_get(tag.to_s.camelize).const_get('EXIFTOOL_TAGS').each do |t|
|
37
37
|
v = tags[t]
|
38
38
|
v = 'EMPTY' if v.respond_to?(:empty?) && v.empty?
|
@@ -43,8 +43,8 @@ module PhTools
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
|
-
else #full_dump
|
47
|
-
tags.to_hash.each do |t,v|
|
46
|
+
else # full_dump
|
47
|
+
tags.to_hash.each do |t, v|
|
48
48
|
puts format('%-29s %-10s %s', t, "(#{v.class})", v)
|
49
49
|
end
|
50
50
|
end
|
data/lib/phls.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
5
6
|
require 'phtools/runner'
|
6
7
|
|
7
8
|
module PhTools
|
8
|
-
# list generation
|
9
9
|
class Phls < Runner
|
10
10
|
def self.about
|
11
|
-
%
|
11
|
+
%(generates list of phtools friendly files)
|
12
12
|
end
|
13
13
|
|
14
14
|
def run!
|
15
15
|
@dirs_to_scan.each do |dir|
|
16
16
|
fmask = File.join(dir, @options_cli['--recursive'] ? '**' : '', "{#{@filemasks * ','}}")
|
17
|
-
Dir.glob(fmask, File::FNM_CASEFOLD).each { |f| output_file(f) if File.file?(f) }
|
17
|
+
Dir.glob(fmask, File::FNM_CASEFOLD).each { |f| output_file(PhFile.new(f)) if File.file?(f) }
|
18
18
|
end
|
19
19
|
|
20
20
|
rescue SignalException
|
@@ -37,9 +37,8 @@ module PhTools
|
|
37
37
|
@filemasks = ['*.*'] if @filemasks.empty?
|
38
38
|
end
|
39
39
|
|
40
|
-
def output_file(
|
41
|
-
|
42
|
-
@os.output(File.join(File.dirname(file), File.basename(file))) if @file_type.include?(ftype)
|
40
|
+
def output_file(phfile)
|
41
|
+
@os.output(phfile) if @file_type.include?(phfile.type)
|
43
42
|
end
|
44
43
|
end
|
45
44
|
end
|
data/lib/phmove.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -7,13 +8,13 @@ require 'phtools/runner'
|
|
7
8
|
module PhTools
|
8
9
|
class Phmove < Runner
|
9
10
|
def self.about
|
10
|
-
|
11
|
+
'moves input files to target folder'
|
11
12
|
end
|
12
13
|
|
13
14
|
private
|
14
15
|
|
15
16
|
def validate_options
|
16
|
-
@target_folder = @options_cli['TARGET_FOLDER']
|
17
|
+
@target_folder = @options_cli['TARGET_FOLDER'] || '.'
|
17
18
|
@arrange = @options_cli['--arrange']
|
18
19
|
if @arrange
|
19
20
|
@raw_folder = File.join(@target_folder, 'RAW')
|
@@ -39,34 +40,24 @@ module PhTools
|
|
39
40
|
|
40
41
|
def process_file(phfile)
|
41
42
|
phfile_out = phfile.clone
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
when FILE_TYPE_IMAGE_RAW.include?(file_type)
|
47
|
-
phfile_out.dirname = @raw_folder
|
48
|
-
when FILE_TYPE_VIDEO.include?(file_type)
|
49
|
-
phfile_out.dirname = @video_folder
|
50
|
-
when FILE_TYPE_AUDIO.include?(file_type)
|
51
|
-
phfile_out.dirname = @target_folder
|
52
|
-
end
|
43
|
+
phfile_out.dirname = @target_folder if phfile_out.image_normal?
|
44
|
+
phfile_out.dirname = @raw_folder if phfile_out.image_raw?
|
45
|
+
phfile_out.dirname = @video_folder if phfile_out.video?
|
46
|
+
phfile_out.dirname = @target_folder if phfile_out.audio?
|
53
47
|
|
54
48
|
FileUtils.mv(phfile.filename, phfile_out.filename, verbose: PhTools.debug) unless phfile == phfile_out
|
55
49
|
phfile_out
|
50
|
+
|
56
51
|
rescue SystemCallError => e
|
57
52
|
raise PhTools::Error, 'file moving - ' + e.message
|
58
53
|
end
|
59
54
|
|
60
55
|
def process_after
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
Dir.delete @video_folder if (Dir.exist?(@video_folder) and
|
65
|
-
Utils.dir_empty?(@video_folder))
|
66
|
-
end
|
56
|
+
return unless @arrange
|
57
|
+
Dir.delete @raw_folder if Dir.exist?(@raw_folder) && Utils.dir_empty?(@raw_folder)
|
58
|
+
Dir.delete @video_folder if Dir.exist?(@video_folder) && Utils.dir_empty?(@video_folder)
|
67
59
|
rescue
|
68
|
-
|
60
|
+
raise PhTools::Error, 'Unable to delete dir'
|
69
61
|
end
|
70
|
-
|
71
62
|
end
|
72
63
|
end
|
data/lib/phrename.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -9,7 +10,7 @@ require 'phtools/runner'
|
|
9
10
|
module PhTools
|
10
11
|
class Phrename < Runner
|
11
12
|
def self.about
|
12
|
-
|
13
|
+
'renames input files to phtools standard'
|
13
14
|
end
|
14
15
|
|
15
16
|
private
|
@@ -35,11 +36,11 @@ module PhTools
|
|
35
36
|
info_msg = ''
|
36
37
|
case @mode
|
37
38
|
when :rename
|
38
|
-
if phfile_out.basename_is_standard?
|
39
|
+
if phfile_out.basename_is_standard? && @user_tag_date.empty?
|
39
40
|
# change only author, keeping date-time safe
|
40
41
|
phfile_out.standardize!(author: @author)
|
41
|
-
info_msg = "'#{phfile.basename+phfile.extname}' already standard name. Keeping date-time part unchanged"
|
42
|
-
else #full rename
|
42
|
+
info_msg = "'#{phfile.basename + phfile.extname}' already standard name. Keeping date-time part unchanged"
|
43
|
+
else # full rename
|
43
44
|
begin
|
44
45
|
tags = MiniExiftool.new(phfile.filename,
|
45
46
|
replace_invalid_chars: true,
|
@@ -94,7 +95,7 @@ module PhTools
|
|
94
95
|
tag_used = "#{@user_tag_date}"
|
95
96
|
end
|
96
97
|
phfile_out.standardize!(date_time: dto, author: @author)
|
97
|
-
info_msg = "'#{phfile.basename+phfile.extname}' using tag '#{tag_used}' for date-time"
|
98
|
+
info_msg = "'#{phfile.basename + phfile.extname}' using tag '#{tag_used}' for date-time"
|
98
99
|
end
|
99
100
|
|
100
101
|
when :clean
|
@@ -102,7 +103,7 @@ module PhTools
|
|
102
103
|
|
103
104
|
when :shift_time
|
104
105
|
fail PhTools::Error, 'non-standard file name' unless phfile_out.basename_is_standard?
|
105
|
-
phfile_out.standardize!(date_time: phfile_out.date_time + @shift_seconds*(1.0/
|
106
|
+
phfile_out.standardize!(date_time: phfile_out.date_time + @shift_seconds * (1.0 / 86_400))
|
106
107
|
end
|
107
108
|
|
108
109
|
FileUtils.mv(phfile.filename, phfile_out.filename, verbose: PhTools.debug) unless phfile == phfile_out
|
data/lib/phtagset.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -7,7 +8,7 @@ require 'phtools/runner'
|
|
7
8
|
module PhTools
|
8
9
|
class Phtagset < Runner
|
9
10
|
def self.about
|
10
|
-
|
11
|
+
'!UNDER CONSTRUCTION!'
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
data/lib/phtools/error.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -18,7 +19,7 @@ module PhTools
|
|
18
19
|
e.backtrace.each do |b|
|
19
20
|
STDERR.puts "#{prefix}: CAUSE#{level} BACKTRACE: #{b}"
|
20
21
|
end
|
21
|
-
drill_down_error(e.cause, level+1, prefix)
|
22
|
+
drill_down_error(e.cause, level + 1, prefix)
|
22
23
|
end
|
23
24
|
|
24
25
|
def self.puts_error(msg, e = nil)
|
@@ -1,7 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
6
|
+
require 'mini_exiftool'
|
7
|
+
|
5
8
|
module ExifTagger
|
6
9
|
# EXIF tags collection
|
7
10
|
class TagCollection
|
@@ -10,15 +13,15 @@ module ExifTagger
|
|
10
13
|
def initialize(init_values = nil)
|
11
14
|
@collection = []
|
12
15
|
return if init_values.nil?
|
13
|
-
|
14
|
-
|
15
|
-
init_values.each
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
|
17
|
+
if init_values.is_a?(Hash)
|
18
|
+
init_values.each { |k, v| self[k] = v }
|
19
|
+
|
20
|
+
elsif init_values.is_a?(ExifTagger::TagCollection)
|
21
|
+
init_values.each { |item| self[item.tag_id] = item.value }
|
22
|
+
|
23
|
+
elsif init_values.is_a?(MiniExiftool)
|
24
|
+
TAGS_SUPPORTED.each { |tag| self[tag] = init_values }
|
22
25
|
end
|
23
26
|
end
|
24
27
|
|
@@ -27,7 +30,7 @@ module ExifTagger
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def to_s
|
30
|
-
str = ''
|
33
|
+
str = +''
|
31
34
|
@collection.each { |i| str << i.to_s }
|
32
35
|
str
|
33
36
|
end
|
@@ -35,7 +38,7 @@ module ExifTagger
|
|
35
38
|
def []=(tag, value)
|
36
39
|
return if value.nil?
|
37
40
|
delete(tag)
|
38
|
-
@collection << produce_tag(tag, value
|
41
|
+
@collection << produce_tag(tag, value)
|
39
42
|
end
|
40
43
|
|
41
44
|
def [](tag)
|
@@ -73,7 +76,7 @@ module ExifTagger
|
|
73
76
|
def error_message
|
74
77
|
str = ''
|
75
78
|
unless valid?
|
76
|
-
str = "Tags are NOT VALID:\n"
|
79
|
+
str = +"Tags are NOT VALID:\n"
|
77
80
|
@collection.each do |item|
|
78
81
|
item.errors.each { |e| str << ' ' + e + "\n" }
|
79
82
|
end
|
@@ -82,7 +85,7 @@ module ExifTagger
|
|
82
85
|
end
|
83
86
|
|
84
87
|
def warning_message
|
85
|
-
str = ''
|
88
|
+
str = +''
|
86
89
|
if with_warnings?
|
87
90
|
@collection.each do |item|
|
88
91
|
item.warnings.each { |e| str << ' WARNING: ' + e + "\n" }
|
@@ -97,7 +100,7 @@ module ExifTagger
|
|
97
100
|
tag_class = ExifTagger::Tag.const_get(tag.to_s.camelize)
|
98
101
|
tag_class.new(value)
|
99
102
|
rescue => e
|
100
|
-
raise ExifTagger::UnknownTag, "Tag #{tag} - #{e.message}"
|
103
|
+
raise ExifTagger::UnknownTag, "Tag #{tag.to_s.camelize}, value '#{value}' - #{e.message}"
|
101
104
|
end
|
102
105
|
end
|
103
106
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -8,7 +9,7 @@ require 'date'
|
|
8
9
|
module ExifTagger
|
9
10
|
# batch EXIF tags setter
|
10
11
|
class TagWriter
|
11
|
-
DEFAULT_OPTIONS = %w(-v0 -FileModifyDate<DateTimeOriginal -overwrite_original -ignoreMinorErrors)
|
12
|
+
DEFAULT_OPTIONS = %w(-v0 -FileModifyDate<DateTimeOriginal -overwrite_original -ignoreMinorErrors).freeze
|
12
13
|
attr_reader :script_name, :added_files_count
|
13
14
|
|
14
15
|
def initialize(script_name: 'exif_tagger.txt',
|
@@ -22,17 +23,17 @@ module ExifTagger
|
|
22
23
|
@output.puts "*** Preparing exiftool script '#{@script_name}' ..."
|
23
24
|
end
|
24
25
|
|
25
|
-
def add_to_script(
|
26
|
-
@script.puts "# **(#{@added_files_count + 1})** Processing file: #{
|
26
|
+
def add_to_script(filename: '', tags: {}, options: DEFAULT_OPTIONS)
|
27
|
+
@script.puts "# **(#{@added_files_count + 1})** Processing file: #{filename} *****"
|
27
28
|
# tags
|
28
29
|
tags.each do |k|
|
29
30
|
@script.puts tags.item(k).to_write_script
|
30
31
|
end
|
31
32
|
# file to be altered
|
32
|
-
@script.puts
|
33
|
+
@script.puts filename
|
33
34
|
# General options
|
34
|
-
options.each { |o| @script.puts
|
35
|
-
@script.puts %
|
35
|
+
options.each { |o| @script.puts o }
|
36
|
+
@script.puts %(-execute)
|
36
37
|
@script.puts
|
37
38
|
@added_files_count += 1
|
38
39
|
|
@@ -53,7 +54,7 @@ module ExifTagger
|
|
53
54
|
|
54
55
|
def run!
|
55
56
|
close_script
|
56
|
-
if @added_files_count
|
57
|
+
if @added_files_count.positive?
|
57
58
|
@output.puts "*** Running #{command} ..."
|
58
59
|
ok = system(command, out: @output, err: @err)
|
59
60
|
fail if ok.nil?
|
@@ -1,8 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
5
6
|
require 'active_support/core_ext'
|
7
|
+
require 'mini_exiftool'
|
6
8
|
|
7
9
|
module ExifTagger
|
8
10
|
module Tag
|
@@ -10,23 +12,38 @@ module ExifTagger
|
|
10
12
|
class Tag
|
11
13
|
include Comparable
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
EMPTY = ''
|
16
|
+
EMPTY_DATE = '0000-01-01 00:00:00'
|
17
|
+
EXIFTOOL_TAGS = [].freeze
|
18
|
+
MAX_BYTESIZE = 32
|
19
|
+
|
20
|
+
attr_reader :errors, :value, :raw_values, :value_invalid, :warnings, :write_script_lines
|
21
|
+
attr_reader :previous
|
15
22
|
attr_accessor :info, :force_write
|
16
23
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
def self.empty?(value)
|
25
|
+
return true if value.nil?
|
26
|
+
return value.empty? if value.is_a?(String)
|
27
|
+
return value.join.empty? if value.is_a?(Array)
|
28
|
+
return value.values.join.empty? if value.is_a?(Hash)
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(value = '', previous = nil)
|
33
|
+
@raw_values = {}
|
34
|
+
if value.class == MiniExiftool
|
35
|
+
init_raw_values(value)
|
36
|
+
@value = normalize(get_from_raw)
|
37
|
+
else
|
38
|
+
@value = normalize(value)
|
39
|
+
end
|
40
|
+
@previous = (previous.is_a?(self.class) ? previous : nil)
|
23
41
|
@info = ''
|
24
42
|
@force_write = false
|
43
|
+
|
25
44
|
validate
|
26
|
-
|
27
|
-
|
28
|
-
@value_invalid.freeze
|
29
|
-
@warnings.freeze
|
45
|
+
validate_vs_previous
|
46
|
+
freeze_values
|
30
47
|
end
|
31
48
|
|
32
49
|
def tag_id
|
@@ -38,14 +55,12 @@ module ExifTagger
|
|
38
55
|
end
|
39
56
|
|
40
57
|
def <=>(other)
|
41
|
-
if other.respond_to?
|
42
|
-
|
43
|
-
else
|
44
|
-
tag_id <=> other.to_s.to_sym
|
45
|
-
end
|
58
|
+
return tag_id <=> other.tag_id if other.respond_to?(:tag_id)
|
59
|
+
tag_id <=> other.to_s.to_sym
|
46
60
|
end
|
47
61
|
|
48
62
|
def to_s
|
63
|
+
return "#{tag_id} is EMPTY" if Tag.empty?(@value)
|
49
64
|
"#{tag_id} = #{@value}"
|
50
65
|
end
|
51
66
|
|
@@ -53,6 +68,7 @@ module ExifTagger
|
|
53
68
|
@errors.empty?
|
54
69
|
end
|
55
70
|
|
71
|
+
# TODO: remove deprecated method
|
56
72
|
def check_for_warnings(original_values: {})
|
57
73
|
@warnings = []
|
58
74
|
self.class::EXIFTOOL_TAGS.each do |tag|
|
@@ -72,39 +88,78 @@ module ExifTagger
|
|
72
88
|
end
|
73
89
|
|
74
90
|
def to_write_script
|
75
|
-
str = ''
|
76
|
-
|
91
|
+
str = +''
|
92
|
+
@write_script_lines = []
|
93
|
+
generate_write_script_lines unless Tag.empty?(@value)
|
77
94
|
unless @write_script_lines.empty?
|
78
|
-
str <<
|
79
|
-
|
80
|
-
|
95
|
+
str << (info.empty? ? '' : "# INFO: #{@info}\n")
|
96
|
+
@warnings.each do |w|
|
97
|
+
str << "# WARNING: #{w}\n"
|
98
|
+
end
|
99
|
+
@write_script_lines.each do |l|
|
100
|
+
unless @warnings.empty?
|
101
|
+
str << '# ' unless @force_write
|
102
|
+
end
|
103
|
+
str << "#{l}\n"
|
104
|
+
end
|
81
105
|
end
|
82
106
|
str
|
83
107
|
end
|
84
108
|
|
85
109
|
private
|
86
110
|
|
87
|
-
def
|
88
|
-
|
111
|
+
def normalize(value)
|
112
|
+
return EMPTY if value.nil?
|
113
|
+
return EMPTY if value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
114
|
+
if value.is_a?(String)
|
115
|
+
return EMPTY if value.strip.empty?
|
116
|
+
elsif value.is_a?(Array)
|
117
|
+
return value.flatten.map { |i| normalize(i.to_s) }
|
118
|
+
elsif value.is_a?(Hash)
|
119
|
+
return value.map { |k, v| [k, normalize(v.to_s)] }.to_h
|
120
|
+
elsif value.is_a?(DateTime)
|
121
|
+
return EMPTY if value.strftime('%F %T') == EMPTY_DATE
|
122
|
+
elsif value.is_a?(Time)
|
123
|
+
return normalize(value.to_datetime)
|
124
|
+
end
|
125
|
+
value
|
89
126
|
end
|
90
127
|
|
91
|
-
def
|
92
|
-
|
93
|
-
|
94
|
-
str << "# WARNING: #{w}\n"
|
128
|
+
def init_raw_values(raw)
|
129
|
+
self.class::EXIFTOOL_TAGS.each do |tag|
|
130
|
+
@raw_values[tag] = normalize(raw[tag])
|
95
131
|
end
|
96
|
-
str
|
97
132
|
end
|
98
133
|
|
99
|
-
def
|
100
|
-
|
101
|
-
@
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
134
|
+
def validate
|
135
|
+
@errors = []
|
136
|
+
@value_invalid = []
|
137
|
+
return if Tag.empty?(@value)
|
138
|
+
validate_type
|
139
|
+
end
|
140
|
+
|
141
|
+
def validate_string_size(value)
|
142
|
+
bsize = value.bytesize
|
143
|
+
return true if bsize <= self.class::MAX_BYTESIZE
|
144
|
+
@errors << %(#{tag_name}: '#{value}' is #{bsize - self.class::MAX_BYTESIZE} bytes longer than allowed #{self.class::MAX_BYTESIZE})
|
145
|
+
false
|
146
|
+
end
|
147
|
+
|
148
|
+
def validate_vs_previous
|
149
|
+
@warnings = []
|
150
|
+
return if @previous.nil?
|
151
|
+
@previous.raw_values.each do |tag, val|
|
152
|
+
@warnings << "#{tag_name} has original value: #{tag}='#{val}'" unless Tag.empty?(val)
|
106
153
|
end
|
107
|
-
|
154
|
+
@warnings.freeze
|
155
|
+
end
|
156
|
+
|
157
|
+
def freeze_values
|
158
|
+
@value.freeze
|
159
|
+
@raw_values.freeze
|
160
|
+
@errors.freeze
|
161
|
+
@value_invalid.freeze
|
162
|
+
@warnings.freeze
|
108
163
|
end
|
109
164
|
end
|
110
165
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# encoding: UTF-8
|
4
|
+
# (c) ANB Andrew Bizyaev
|
5
|
+
|
6
|
+
require_relative '_tag'
|
7
|
+
|
8
|
+
module ExifTagger
|
9
|
+
module Tag
|
10
|
+
class TagArrayOfStrings < Tag
|
11
|
+
private
|
12
|
+
|
13
|
+
def get_from_raw
|
14
|
+
@raw_values.each_value do |v|
|
15
|
+
v = v.split('; ') if v.is_a?(String)
|
16
|
+
return v unless Tag.empty?(v)
|
17
|
+
end
|
18
|
+
EMPTY
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate_type
|
22
|
+
if @value.is_a?(Array)
|
23
|
+
@value.each do |val|
|
24
|
+
@value_invalid << val unless validate_string_size(val)
|
25
|
+
end
|
26
|
+
@value -= @value_invalid
|
27
|
+
else
|
28
|
+
@errors << %(#{tag_name}: '#{@value}' is a wrong type \(#{@value.class}\))
|
29
|
+
@value_invalid << @value
|
30
|
+
@value = EMPTY
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
# encoding: UTF-8
|
3
4
|
# (c) ANB Andrew Bizyaev
|
4
5
|
|
@@ -8,37 +9,34 @@ require 'date'
|
|
8
9
|
module ExifTagger
|
9
10
|
module Tag
|
10
11
|
class TagDate < Tag
|
11
|
-
MAX_BYTESIZE = 32 # no limit set in EXIF spec for Date
|
12
|
-
|
13
12
|
private
|
14
13
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@value = ''
|
36
|
-
end
|
14
|
+
def get_from_raw
|
15
|
+
@raw_values.each_value do |value|
|
16
|
+
return value unless Tag.empty?(value)
|
17
|
+
end
|
18
|
+
EMPTY
|
19
|
+
end
|
20
|
+
|
21
|
+
def make_date_from(tag_date = '', tag_time = '')
|
22
|
+
dcdt = %(#{tag_date} #{tag_time})
|
23
|
+
DateTime.parse(dcdt.sub(/^(\d+):(\d+):/, '\1-\2-'))
|
24
|
+
rescue ArgumentError
|
25
|
+
EMPTY
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_type
|
29
|
+
if @value.is_a?(String)
|
30
|
+
validate_string_size(@value)
|
31
|
+
|
32
|
+
elsif @value.is_a?(DateTime)
|
33
|
+
|
37
34
|
else
|
38
|
-
@errors << %(#{tag_name}: '#{@value}' is
|
39
|
-
@value_invalid << @value
|
40
|
-
@value = ''
|
35
|
+
@errors << %(#{tag_name}: '#{@value}' is a wrong type \(#{@value.class}\))
|
41
36
|
end
|
37
|
+
return if @errors.empty?
|
38
|
+
@value_invalid << @value
|
39
|
+
@value = EMPTY
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|