phtools 0.8.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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