phtools 0.8.1 → 0.10.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/TODO.md +4 -3
  3. data/exe/phfixdto +42 -0
  4. data/exe/phfixfmd +1 -1
  5. data/exe/phgettags +39 -0
  6. data/exe/phls +9 -5
  7. data/exe/phrename +1 -1
  8. data/lib/phfixdto.rb +62 -0
  9. data/lib/phfixfmd.rb +1 -2
  10. data/lib/phgettags.rb +58 -0
  11. data/lib/phtools/exif_tagger/error.rb +11 -0
  12. data/lib/phtools/exif_tagger/tag_collection.rb +103 -0
  13. data/lib/phtools/exif_tagger/tag_writer.rb +79 -0
  14. data/lib/phtools/exif_tagger/tags/_tag.rb +111 -0
  15. data/lib/phtools/exif_tagger/tags/_tag_date.rb +45 -0
  16. data/lib/phtools/exif_tagger/tags/city.rb +39 -0
  17. data/lib/phtools/exif_tagger/tags/coded_character_set.rb +38 -0
  18. data/lib/phtools/exif_tagger/tags/collections.rb +45 -0
  19. data/lib/phtools/exif_tagger/tags/copyright.rb +39 -0
  20. data/lib/phtools/exif_tagger/tags/country.rb +40 -0
  21. data/lib/phtools/exif_tagger/tags/country_code.rb +38 -0
  22. data/lib/phtools/exif_tagger/tags/create_date.rb +32 -0
  23. data/lib/phtools/exif_tagger/tags/creator.rb +44 -0
  24. data/lib/phtools/exif_tagger/tags/date_time_original.rb +32 -0
  25. data/lib/phtools/exif_tagger/tags/gps_created.rb +78 -0
  26. data/lib/phtools/exif_tagger/tags/image_unique_id.rb +47 -0
  27. data/lib/phtools/exif_tagger/tags/keywords.rb +49 -0
  28. data/lib/phtools/exif_tagger/tags/location.rb +40 -0
  29. data/lib/phtools/exif_tagger/tags/modify_date.rb +26 -0
  30. data/lib/phtools/exif_tagger/tags/state.rb +40 -0
  31. data/lib/phtools/exif_tagger/tags/world_region.rb +38 -0
  32. data/lib/phtools/exif_tagger/tags.rb +11 -0
  33. data/lib/phtools/exif_tagger.rb +8 -0
  34. data/lib/phtools/version.rb +1 -1
  35. data/lib/phtools.rb +4 -4
  36. metadata +31 -4
  37. data/lib/phfixdate.rb +0 -13
  38. data/lib/phmtags.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbc8c46f63d80e6beda76258cf6da8f1311bd836
4
- data.tar.gz: 58ea09d9d25e550e87483747279171ce8b20e587
3
+ metadata.gz: 11a9513d5b974ef96b53c7d9f7b4a30299fecb37
4
+ data.tar.gz: d5156efe4cb97fd0c352168c9a8be41db697eb85
5
5
  SHA512:
6
- metadata.gz: e04354409ef45c612b47cf1b25dd9edf25fcba3948eb8e25e74349350831892885c44ce4b64d795e742c1fc263879b4e3cd5135ff7291e53a9074cb83f4aee08
7
- data.tar.gz: 62e00150f730d9905ede7f0c78c7ef6a46c2bbbdbfefbe3300e0b35c6083946760e4ffd4596a44c1553f187c7c75b7c5da7b4ccd0c21b8366811b5d13bc4a671
6
+ metadata.gz: 95b747d7110174f61b325c8cdd58ff6b79d21ca3ae494ea96c9bc0bdc1c6c43ba8621d9d81f0d297ee5b67a74d9486d38ea5405f5df4c1723bc5c2b26b14948b
7
+ data.tar.gz: 15c18ab1c5cc87c2e98f8008b0768452efc2db051daae2054ed01fcfc3d91785055c89a58643b7cd82de89bb07eb30abf0043b991a29d7fc278e7d0801db3f00
data/TODO.md CHANGED
@@ -23,14 +23,15 @@
23
23
  - [ ] phrename: make new usage mode: `phrename -t TAG`. Useful if user wants to re-set date-time using TAG keeping author-nickname unchanged
24
24
 
25
25
  ### phgettags
26
- - [ ] create phgettags (based on ftmtags)
26
+ - [x] create phgettags (based on ftmtags)
27
27
 
28
28
  ### phfixfmd
29
29
  - [x] create phfixfmd - fix FileModifyDate to get equal to date-time-in-the-name
30
30
 
31
31
  ### phfixdto
32
- - [ ] create phfixdto - fix MWG:DateTimeOriginal = date-time-in-name
33
- - [ ] phfixdto: make -N --no_run option = no running exiftool script, only preparation
32
+ - [x] create phfixdto - fix MWG:DateTimeOriginal (DTO) := date-time-in-name
33
+ - [x] phfixdto: make -N --no_run option = no running exiftool script, only preparation
34
+ - [ ] phfixdto: smartly check if CreateDate set (including MWG subfields). If any - then update CreateDate
34
35
 
35
36
  ### phevent
36
37
  - [ ] create phevent (based on ftevent)
data/exe/phfixdto ADDED
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ module PhTools
6
+ tool_name = File.basename(__FILE__)
7
+ require "#{tool_name}"
8
+
9
+ file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
10
+ usage = <<DOCOPT
11
+ ***************************************************
12
+ phtools - *Keep Your Photos In Order* (c) ANB
13
+ ***************************************************
14
+ #{tool_name} updates the input file's DateTimeOriginal (CreateDate) tags with
15
+ the date-time encoded in the filename (date-time-in-the-name). The file should
16
+ be renamed to phtools Standard Name before using this command (use phrename for
17
+ this).
18
+ This program uses external utility ExifTool created by Phil Harvey
19
+ (http://www.sno.phy.queensu.ca/~phil/exiftool/).
20
+ #{tool_name} acts as a 'sink' program meaning it expects the input files
21
+ to be passed to STDIN, does its job on the files and produces no useful
22
+ (for other pipe-optimized programs) output.
23
+ In other words this command is intended to be used with other programs
24
+ connected via input pipes as a last command in the pipe chain, e.g.:
25
+ phls | phrename - a anb | #{tool_name}
26
+
27
+ Usage:
28
+ #{tool_name} [-N] [-D]
29
+ #{tool_name} -h | --help
30
+ #{tool_name} -v | --version
31
+
32
+ Options:
33
+ -N --no_run Dry-run mode means no run exiftool command, only generate script
34
+ file 'exif_tagger_dto.txt'. User can check the script and
35
+ manually run the command: `exiftool -@ exif_tagger_dto.txt`
36
+ -D --debug Turn on debugging (verbose) mode
37
+ -h --help Show this screen.
38
+ -v --version Show version.
39
+ DOCOPT
40
+
41
+ PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
42
+ end
data/exe/phfixfmd CHANGED
@@ -11,7 +11,7 @@ module PhTools
11
11
  ***************************************************
12
12
  phtools - *Keep Your Photos In Order* (c) ANB
13
13
  ***************************************************
14
- #{tool_name} changes an input file modify-date according to the date encoded
14
+ #{tool_name} changes an input file's modify-date according to the date encoded
15
15
  in the filename (date-time-in-the-name). Therefore the file should be renamed
16
16
  to phtools Standard Name before using this command (use phrename for this).
17
17
  #{tool_name} acts as a 'filter' program meaning it expects the input files
data/exe/phgettags ADDED
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ module PhTools
6
+ tool_name = File.basename(__FILE__)
7
+ require "#{tool_name}"
8
+
9
+ file_type = FILE_TYPE_IMAGE + FILE_TYPE_VIDEO + FILE_TYPE_AUDIO
10
+ usage = <<DOCOPT
11
+ ***************************************************
12
+ phtools - *Keep Your Photos In Order* (c) ANB
13
+ ***************************************************
14
+ #{tool_name} extracts the list of tags stored inside the given file.
15
+
16
+ #{tool_name} acts as a 'sink' program meaning it expects the input files
17
+ to be passed to STDIN, does its job on the input files and produces no useful
18
+ (for other pipe-optimized programs) output.
19
+ In other words this command is intended to be used with other programs
20
+ connected via input pipes as a last command in the pipe chain, e.g.:
21
+ phls | #{tool_name}
22
+
23
+ This program uses external utility ExifTool created by Phil Harvey
24
+ (http://www.sno.phy.queensu.ca/~phil/exiftool/).
25
+
26
+ Usage:
27
+ #{tool_name} [-f] [-D]
28
+ #{tool_name} -h | --help
29
+ #{tool_name} -v | --version
30
+
31
+ Options:
32
+ -f --full_dump Print all tags
33
+ -D --debug Turn on debugging (verbose) mode
34
+ -h --help Show this screen.
35
+ -v --version Show version.
36
+ DOCOPT
37
+
38
+ PhTools.const_get(tool_name.capitalize).new(usage, file_type).run!
39
+ end
data/exe/phls CHANGED
@@ -11,16 +11,20 @@ module PhTools
11
11
  ***************************************************
12
12
  phtools - *Keep Your Photos In Order* (c) ANB
13
13
  ***************************************************
14
- #{tool_name} scans given directories and generates list of files to standard output.
15
- In short it acts like a smart 'ls' command (or 'dir' in Windows).
14
+ #{tool_name} scans given directories and generates list of files to standard
15
+ output. In short it acts like a smart 'ls' command (or 'dir' in Windows).
16
16
  Set DIRs to be scanned as a parameters. If no DIRs are set - current dir (.)
17
17
  will be scanned. Set FILEMASKs as a parameters - and only files matching the
18
- masks will be processed. If no FILEMASK is set *.* will be used by-default.
18
+ masks will be processed. If no FILEMASK is set '*.*' will be used by-default.
19
19
  To avoid unnessesary mask extraction by OS - put it in ''.
20
20
  Note, #{tool_name} works only with phtools-friendly file types: #{file_type * ','}
21
- #{tool_name} is a starting point for all other phtools to be connected via pipes.
22
21
 
23
- Example: #{tool_name} abc '*aaa*' | phrename -a anb => scans 'abc' folder and
22
+ #{tool_name} acts as a 'source' program meaning it does not require any input
23
+ from STDIN, it generates list of files based on input parameters and send it
24
+ to STDOUT.
25
+ In other words this command is intended to be used with other programs
26
+ connected via pipes as a 1st command in the pipe chain, e.g.:
27
+ #{tool_name} abc '*aaa*' | phrename -a anb => scans 'abc' folder and
24
28
  sends all found phtools friendly files filtered with *aaa* to phrename command.
25
29
 
26
30
  Usage:
data/exe/phrename CHANGED
@@ -54,7 +54,7 @@ Options:
54
54
  -t TAG --tag_date=TAG Force program to use TAG as a Date-Time creation
55
55
  info instead of standard phtools tags.
56
56
  You can retreive all existing tags using command:
57
- `phls filename|phmtags -f` OR
57
+ `phls filename|phgettags -f` OR
58
58
  `exiftool -s filename`
59
59
 
60
60
  -s DELTA --shift_time=DELTA DELTA (in seconds) will be added to Date-Time value
data/lib/phfixdto.rb ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ require 'mini_exiftool'
6
+ require 'phtools/runner'
7
+ require 'phtools/exif_tagger'
8
+
9
+ module PhTools
10
+ # phfixdto logic
11
+ class Phfixdto < Runner
12
+ def self.about
13
+ 'fixes DateTimeOriginal tag to be equal to date-time-in-the-name'
14
+ end
15
+
16
+ private
17
+
18
+ def process_before
19
+ @writer = ExifTagger::TagWriter.new(
20
+ script_name: 'exif_tagger_dto.txt',
21
+ memo: "#{DateTime.now}: Script generated by #{@tool_name} version #{PhTools::VERSION})",
22
+ output: STDERR)
23
+ end
24
+
25
+ def process_file(phfile)
26
+ fail PhTools::Error, 'wrong date-time-in-the-name' unless phfile.date_time_ok?
27
+
28
+ STDERR.puts %( ...#{phfile}...)
29
+ begin
30
+ @tags_original = MiniExiftool.new(phfile.filename,
31
+ replace_invalid_chars: true,
32
+ composite: true,
33
+ timestamps: DateTime)
34
+ rescue
35
+ raise PhTools::Error, "EXIF tags reading - #{e.message}"
36
+ end
37
+
38
+ @tags_to_write = ExifTagger::TagCollection.new
39
+
40
+ @tags_to_write[:date_time_original] = phfile.date_time_to_time
41
+ @tags_to_write.item(:date_time_original).force_write = true
42
+
43
+ unless @tags_original[:create_date].nil?
44
+ @tags_to_write[:create_date] = phfile.date_time_to_time
45
+ @tags_to_write.item(:create_date).force_write = true
46
+ end
47
+ @tags_to_write.check_for_warnings(original_values: @tags_original)
48
+ fail PhTools::Error, @tags_to_write.error_message unless @tags_to_write.valid?
49
+
50
+ @writer.add_to_script(phfile: phfile, tags: @tags_to_write)
51
+
52
+ return ''
53
+
54
+ rescue => e
55
+ raise PhTools::Error, e.message
56
+ end
57
+
58
+ def process_after
59
+ @writer.run! unless @options_cli['--no_run']
60
+ end
61
+ end
62
+ end
data/lib/phfixfmd.rb CHANGED
@@ -14,8 +14,7 @@ module PhTools
14
14
  private
15
15
 
16
16
  def process_file(phfile)
17
- fail PhTools::Error, 'wrong date-time in the name' unless
18
- phfile.date_time_ok?
17
+ fail PhTools::Error, 'wrong date-time-in-the-name' unless phfile.date_time_ok?
19
18
  begin
20
19
  File.utime(Time.now, phfile.date_time_to_time, phfile.filename)
21
20
  rescue
data/lib/phgettags.rb ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ require 'phtools/runner'
6
+ require 'mini_exiftool'
7
+ require 'phtools/exif_tagger'
8
+
9
+ module PhTools
10
+ class Phgettags < Runner
11
+
12
+ def self.about
13
+ "extracts the tags stored inside the file"
14
+ end
15
+
16
+ private
17
+
18
+ def process_file(phfile)
19
+ begin
20
+ tags = MiniExiftool.new(phfile.filename,
21
+ numerical: false,
22
+ coord_format: '%d %d %.4f',
23
+ replace_invalid_chars: true,
24
+ composite: true,
25
+ timestamps: DateTime)
26
+ rescue
27
+ raise PhTools::Error, "EXIF tags reading - #{e.message}"
28
+ end
29
+
30
+ puts "******** FILE #{phfile} ********"
31
+
32
+ if not @options_cli['--full_dump']
33
+ puts format('%-29s %s', "FileModifyDate", "#{tags.FileModifyDate}")
34
+ ExifTagger::TAGS_SUPPORTED.each do |tag|
35
+ puts "#{tag.to_s.camelize}"
36
+ ExifTagger::Tag.const_get(tag.to_s.camelize).const_get('EXIFTOOL_TAGS').each do |t|
37
+ v = tags[t]
38
+ v = 'EMPTY' if v.respond_to?(:empty?) && v.empty?
39
+ if v.nil?
40
+ puts format(' %-27s %s', t, 'NIL')
41
+ else
42
+ puts format(' %-27s %-10s %s', t, "(#{v.class})", v)
43
+ end
44
+ end
45
+ end
46
+ else #full_dump
47
+ tags.to_hash.each do |t,v|
48
+ puts format('%-29s %-10s %s', t, "(#{v.class})", v)
49
+ end
50
+ end
51
+
52
+ return ''
53
+
54
+ rescue => e
55
+ raise PhTools::Error, "exif tags operating: #{e.message}"
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ module ExifTagger
6
+ class Error < StandardError; end
7
+ class UnknownTag < Error; end
8
+ class WriteTag < Error; end
9
+ class CreatorsDirectory < Error; end
10
+ class PlacesDirectory < Error; end
11
+ end
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ module ExifTagger
6
+ # EXIF tags collection
7
+ class TagCollection
8
+ include Enumerable
9
+
10
+ def initialize(init_values = nil)
11
+ @collection = []
12
+ return if init_values.nil?
13
+ case
14
+ when init_values.is_a?(Hash)
15
+ init_values.each do |k, v|
16
+ self[k] = v
17
+ end
18
+ when init_values.is_a?(ExifTagger::TagCollection)
19
+ init_values.each do |item|
20
+ self[item.tag_id] = item.value
21
+ end
22
+ end
23
+ end
24
+
25
+ def each(&block)
26
+ @collection.each(&block)
27
+ end
28
+
29
+ def to_s
30
+ str = ''
31
+ @collection.each { |i| str << i.to_s }
32
+ str
33
+ end
34
+
35
+ def []=(tag, value)
36
+ return if value.nil?
37
+ delete(tag)
38
+ @collection << produce_tag(tag, value.dup)
39
+ end
40
+
41
+ def [](tag)
42
+ ind = @collection.find_index(tag)
43
+ ind.nil? ? nil : @collection[ind].value
44
+ end
45
+
46
+ def item(tag)
47
+ ind = @collection.find_index(tag)
48
+ ind.nil? ? nil : @collection[ind]
49
+ end
50
+
51
+ def delete(tag)
52
+ @collection.delete(tag)
53
+ end
54
+
55
+ def valid?
56
+ ok = true
57
+ @collection.each { |i| ok &&= i.valid? }
58
+ ok
59
+ end
60
+
61
+ def with_warnings?
62
+ warn = false
63
+ @collection.each { |i| warn ||= i.warnings.empty? }
64
+ warn
65
+ end
66
+
67
+ def check_for_warnings(original_values: {})
68
+ @collection.each do |i|
69
+ i.check_for_warnings(original_values: original_values)
70
+ end
71
+ end
72
+
73
+ def error_message
74
+ str = ''
75
+ unless valid?
76
+ str = "Tags are NOT VALID:\n"
77
+ @collection.each do |item|
78
+ item.errors.each { |e| str << ' ' + e + "\n" }
79
+ end
80
+ end
81
+ str
82
+ end
83
+
84
+ def warning_message
85
+ str = ''
86
+ if with_warnings?
87
+ @collection.each do |item|
88
+ item.warnings.each { |e| str << ' WARNING: ' + e + "\n" }
89
+ end
90
+ end
91
+ str
92
+ end
93
+
94
+ private
95
+
96
+ def produce_tag(tag, value)
97
+ tag_class = ExifTagger::Tag.const_get(tag.to_s.camelize)
98
+ tag_class.new(value)
99
+ rescue => e
100
+ raise ExifTagger::UnknownTag, "Tag #{tag} - #{e.message}"
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ require 'date'
6
+
7
+ # Exif tagger
8
+ module ExifTagger
9
+ # batch EXIF tags setter
10
+ class TagWriter
11
+ DEFAULT_OPTIONS = %w(-v0 -FileModifyDate<DateTimeOriginal -overwrite_original -ignoreMinorErrors)
12
+ attr_reader :script_name, :added_files_count
13
+
14
+ def initialize(script_name: 'exif_tagger.txt',
15
+ memo: 'Generated by phtools',
16
+ output: STDOUT, err: STDERR)
17
+ @script_name = script_name
18
+ create_script(memo)
19
+ @added_files_count = 0
20
+ @output = output
21
+ @err = err
22
+ @output.puts "*** Preparing exiftool script '#{@script_name}' ..."
23
+ end
24
+
25
+ def add_to_script(phfile: '', tags: {}, options: DEFAULT_OPTIONS)
26
+ @script.puts "# **(#{@added_files_count + 1})** Processing file: #{phfile} *****"
27
+ # tags
28
+ tags.each do |k|
29
+ @script.puts tags.item(k).to_write_script
30
+ end
31
+ # file to be altered
32
+ @script.puts %Q{#{phfile}}
33
+ # General options
34
+ options.each { |o| @script.puts "#{o}" }
35
+ @script.puts %Q{-execute}
36
+ @script.puts
37
+ @added_files_count += 1
38
+
39
+ rescue => e
40
+ raise WriteTag, "adding item to exiftool script - #{e.message}"
41
+ end
42
+
43
+ def close_script
44
+ @script.close
45
+ @output.puts "*** Finished preparation of the script '#{script_name}'"
46
+ rescue => e
47
+ raise WriteTag, "closing exiftool script - #{e.message}"
48
+ end
49
+
50
+ def command
51
+ "exiftool -@ #{@script_name}"
52
+ end
53
+
54
+ def run!
55
+ close_script
56
+ if @added_files_count > 0
57
+ @output.puts "*** Running #{command} ..."
58
+ ok = system(command, out: @output, err: @err)
59
+ fail if ok.nil?
60
+ @output.puts "*** Finished #{command}"
61
+ else
62
+ @output.puts "*** Nothing to update, skip running #{command} ..."
63
+ end
64
+ rescue
65
+ raise WriteTag, "running #{command}"
66
+ end
67
+
68
+ private
69
+
70
+ def create_script(memo)
71
+ @script = File.open(@script_name, 'w+:utf-8')
72
+ @script.puts '# exiftool script for batch tag operations'
73
+ @script.puts "# #{memo}"
74
+ @script.puts "# usage: exiftool -@ #{@script_name}"
75
+ rescue => e
76
+ raise ExifTagger::WriteTag, "creating exiftool script - #{e.message}"
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ require 'active_support/core_ext'
6
+
7
+ module ExifTagger
8
+ module Tag
9
+ # Parent class for all tags
10
+ class Tag
11
+ include Comparable
12
+
13
+ EXIFTOOL_TAGS = []
14
+ attr_reader :errors, :value, :value_invalid, :warnings, :write_script_lines
15
+ attr_accessor :info, :force_write
16
+
17
+ def initialize(value_norm = '')
18
+ @value = value_norm
19
+ @errors = []
20
+ @value_invalid = []
21
+ @warnings = []
22
+ @write_script_lines = []
23
+ @info = ''
24
+ @force_write = false
25
+ validate
26
+ @value.freeze
27
+ @errors.freeze
28
+ @value_invalid.freeze
29
+ @warnings.freeze
30
+ end
31
+
32
+ def tag_id
33
+ self.class.to_s.demodulize.underscore.to_sym
34
+ end
35
+
36
+ def tag_name
37
+ self.class.to_s.demodulize
38
+ end
39
+
40
+ def <=>(other)
41
+ if other.respond_to? :tag_id
42
+ tag_id <=> other.tag_id
43
+ else
44
+ tag_id <=> other.to_s.to_sym
45
+ end
46
+ end
47
+
48
+ def to_s
49
+ "#{tag_id} = #{@value}"
50
+ end
51
+
52
+ def valid?
53
+ @errors.empty?
54
+ end
55
+
56
+ def check_for_warnings(original_values: {})
57
+ @warnings = []
58
+ self.class::EXIFTOOL_TAGS.each do |tag|
59
+ v = original_values[tag]
60
+ unless v.nil?
61
+ case
62
+ when v.kind_of?(String)
63
+ @warnings << "#{tag_name} has original value: #{tag}='#{v}'" unless v.empty?
64
+ when v.kind_of?(Array)
65
+ @warnings << "#{tag_name} has original value: #{tag}=#{v}" unless v.join.empty?
66
+ else
67
+ @warnings << "#{tag_name} has original value: #{tag}=#{v}"
68
+ end
69
+ end
70
+ end
71
+ @warnings.freeze
72
+ end
73
+
74
+ def to_write_script
75
+ str = ''
76
+ generate_write_script_lines
77
+ unless @write_script_lines.empty?
78
+ str << print_info
79
+ str << print_warnings
80
+ str << print_lines
81
+ end
82
+ str
83
+ end
84
+
85
+ private
86
+
87
+ def print_info
88
+ @info.empty? ? '' : "# INFO: #{@info}\n"
89
+ end
90
+
91
+ def print_warnings
92
+ str = ''
93
+ @warnings.each do |w|
94
+ str << "# WARNING: #{w}\n"
95
+ end
96
+ str
97
+ end
98
+
99
+ def print_lines
100
+ str = ''
101
+ @write_script_lines.each do |l|
102
+ unless @warnings.empty?
103
+ str << '# ' unless @force_write
104
+ end
105
+ str << "#{l}\n"
106
+ end
107
+ str
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ require_relative '_tag'
6
+ require 'date'
7
+
8
+ module ExifTagger
9
+ module Tag
10
+ class TagDate < Tag
11
+ MAX_BYTESIZE = 32 # no limit set in EXIF spec for Date
12
+
13
+ private
14
+
15
+ def validate
16
+ case
17
+ when @value.kind_of?(String)
18
+ bsize = @value.bytesize
19
+ if bsize > MAX_BYTESIZE
20
+ @errors << %(#{tag_name}: '#{@value}' ) +
21
+ %(is #{bsize - MAX_BYTESIZE} bytes longer than allowed #{MAX_BYTESIZE})
22
+ @value_invalid << @value
23
+ @value = ''
24
+ end
25
+ when @value.kind_of?(DateTime)
26
+ if @value == DateTime.new(0)
27
+ @errors << %(#{tag_name}: '#{@value}' zero Date)
28
+ @value_invalid << @value
29
+ @value = ''
30
+ end
31
+ when @value.kind_of?(Time)
32
+ if @value == Time.new(0)
33
+ @errors << %(#{tag_name}: '#{@value}' zero Date)
34
+ @value_invalid << @value
35
+ @value = ''
36
+ end
37
+ else
38
+ @errors << %(#{tag_name}: '#{@value}' is of wrong type (#{@value.class}))
39
+ @value_invalid << @value
40
+ @value = ''
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+ # (c) ANB Andrew Bizyaev
4
+
5
+ require_relative '_tag'
6
+
7
+ module ExifTagger
8
+ module Tag
9
+ # MWG:City, String[0,32]
10
+ # = IPTC:City XMP-photoshop:City XMP-iptcExt:LocationShownCity
11
+ class City < Tag
12
+ MAX_BYTESIZE = 32
13
+ EXIFTOOL_TAGS = %w(City LocationShownCity)
14
+
15
+ def initialize(value_raw = '')
16
+ super(value_raw.to_s)
17
+ end
18
+
19
+ private
20
+
21
+ def validate
22
+ bsize = @value.bytesize
23
+ if bsize > MAX_BYTESIZE
24
+ @errors << %(#{tag_name}: '#{@value}' ) +
25
+ %(is #{bsize - MAX_BYTESIZE} bytes longer than allowed #{MAX_BYTESIZE})
26
+ @value_invalid << @value
27
+ @value = ''
28
+ end
29
+ end
30
+
31
+ def generate_write_script_lines
32
+ @write_script_lines = []
33
+ unless @value.empty?
34
+ @write_script_lines << %Q(-MWG:City=#{@value})
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end