exiftool 1.2.1 → 1.2.2
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 +5 -5
- data/lib/exiftool.rb +32 -25
- data/lib/exiftool/field_parser.rb +29 -25
- data/lib/exiftool/result.rb +3 -0
- data/lib/exiftool/version.rb +3 -1
- metadata +57 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8e9801146be9164bb998b8ef8cd5bbc1c74d280e7f78200429296c1dde2a56b9
|
4
|
+
data.tar.gz: 7905c172857802486f3f9525233a7e20bfce8c6adee7f53e49f6ce49d57e0822
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1988ab26fb045372c7362f62a07b32353d8e6b5acfd41b963f3b281b357d02d9b24bba234844f9ee9d2b2bf73e655dd95ddd58b5d24f15f7f0a2583a531156e8
|
7
|
+
data.tar.gz: a393570684163893fab56518ab1dfa6be33a6dd124b7ec914e6b95b4465571ab69393935f22c18510eea7e8009ef5887b5b1c5f1a351fbe205dff08fc2144ab3
|
data/lib/exiftool.rb
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
require 'shellwords'
|
3
5
|
require 'exiftool/result'
|
4
6
|
require 'forwardable'
|
5
7
|
|
8
|
+
# Exiftool Class
|
6
9
|
class Exiftool
|
7
|
-
class NoSuchFile < StandardError
|
8
|
-
class NotAFile < StandardError
|
9
|
-
class ExiftoolNotInstalled < StandardError
|
10
|
-
class NoDefaultResultWithMultiget < StandardError
|
10
|
+
class NoSuchFile < StandardError; end
|
11
|
+
class NotAFile < StandardError; end
|
12
|
+
class ExiftoolNotInstalled < StandardError; end
|
13
|
+
class NoDefaultResultWithMultiget < StandardError; end
|
11
14
|
|
12
|
-
|
13
|
-
|
15
|
+
class << self
|
16
|
+
attr_writer :command
|
14
17
|
end
|
15
18
|
|
16
19
|
def self.command
|
@@ -18,7 +21,7 @@ class Exiftool
|
|
18
21
|
end
|
19
22
|
|
20
23
|
def self.exiftool_installed?
|
21
|
-
exiftool_version.to_f
|
24
|
+
exiftool_version.to_f.positive?
|
22
25
|
end
|
23
26
|
|
24
27
|
# This is a string, not a float, to handle versions like "9.40" properly.
|
@@ -28,7 +31,9 @@ class Exiftool
|
|
28
31
|
|
29
32
|
def self.expand_path(filename)
|
30
33
|
raise(NoSuchFile, filename) unless File.exist?(filename)
|
34
|
+
|
31
35
|
raise(NotAFile, filename) unless File.file?(filename)
|
36
|
+
|
32
37
|
File.expand_path(filename)
|
33
38
|
end
|
34
39
|
|
@@ -38,28 +43,29 @@ class Exiftool
|
|
38
43
|
|
39
44
|
def initialize(filenames, exiftool_opts = '')
|
40
45
|
@file2result = {}
|
41
|
-
filenames = [filenames] if
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
46
|
+
filenames = [filenames] if filenames.is_a?(String) || filenames.is_a?(Pathname)
|
47
|
+
return if filenames.empty?
|
48
|
+
|
49
|
+
escaped_filenames = filenames.map do |f|
|
50
|
+
Shellwords.escape(self.class.expand_path(f.to_s))
|
51
|
+
end.join(' ')
|
52
|
+
# I'd like to use -dateformat, but it doesn't support timezone offsets properly,
|
53
|
+
# nor sub-second timestamps.
|
54
|
+
cmd = "#{self.class.command} #{exiftool_opts} -j -coordFormat \"%.8f\" #{escaped_filenames} 2> /dev/null"
|
55
|
+
json = `#{cmd}`.chomp
|
56
|
+
raise ExiftoolNotInstalled if json == ''
|
57
|
+
|
58
|
+
JSON.parse(json).each do |raw|
|
59
|
+
result = Result.new(raw)
|
60
|
+
@file2result[result.source_file] = result
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
58
|
-
def results(include_results_with_errors
|
64
|
+
def results(include_results_with_errors: false)
|
59
65
|
if include_results_with_errors
|
60
66
|
@file2result.values
|
61
67
|
else
|
62
|
-
@file2result.values.
|
68
|
+
@file2result.values.reject(&:errors?)
|
63
69
|
end
|
64
70
|
end
|
65
71
|
|
@@ -68,17 +74,18 @@ class Exiftool
|
|
68
74
|
end
|
69
75
|
|
70
76
|
def files_with_results
|
71
|
-
results.map
|
77
|
+
results.map(&:source_file)
|
72
78
|
end
|
73
79
|
|
74
80
|
def errors?
|
75
|
-
@file2result.values.any?
|
81
|
+
@file2result.values.any?(&:errors?)
|
76
82
|
end
|
77
83
|
|
78
84
|
private
|
79
85
|
|
80
86
|
def first_result
|
81
87
|
raise(NoDefaultResultWithMultiget, 'use #result_for when multiple filenames are used') if @file2result.size > 1
|
88
|
+
|
82
89
|
@file2result.values.first
|
83
90
|
end
|
84
91
|
end
|
@@ -1,13 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'time'
|
2
|
-
require 'rational'
|
3
4
|
|
4
5
|
class Exiftool
|
6
|
+
# Exiftool FiledParser Class
|
5
7
|
class FieldParser
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
ZERO_DATE_RE = /\A[+:0 ]+\z/
|
8
|
+
WORD_BOUNDARY_RES = [/([A-Z\d]+)([A-Z][a-z])/, /([a-z\d])([A-Z])/].freeze
|
9
|
+
FRACTION_RE = %r{^(\d+)/(\d+)$}.freeze
|
10
|
+
YMD_RE = /\A(\d{4}):(\d{2}):(\d{2})\b/.freeze
|
11
|
+
ZERO_DATE_RE = /\A[+:0 ]+\z/.freeze
|
11
12
|
|
12
13
|
attr_reader :key, :display_key, :sym_key, :raw_value
|
13
14
|
|
@@ -20,26 +21,28 @@ class Exiftool
|
|
20
21
|
|
21
22
|
def value
|
22
23
|
@value ||= if lat_long?
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
24
|
+
as_lat_long
|
25
|
+
elsif date?
|
26
|
+
as_date
|
27
|
+
elsif fraction?
|
28
|
+
as_fraction
|
29
|
+
else
|
30
|
+
raw_value
|
31
|
+
end
|
31
32
|
rescue StandardError => e
|
33
|
+
# :nocov:
|
32
34
|
"Warning: Parsing '#{raw_value}' for attribute '#{key}' raised #{e.message}"
|
35
|
+
# :nocov:
|
33
36
|
end
|
34
37
|
|
35
38
|
def civil_date
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
return unless date? && !zero_date?
|
40
|
+
|
41
|
+
ymd = raw_value.scan(YMD_RE).first
|
42
|
+
return unless ymd
|
43
|
+
|
44
|
+
ymd_a = ymd.map(&:to_i)
|
45
|
+
Date.civil(*ymd_a) if Date.valid_civil?(*ymd_a)
|
43
46
|
end
|
44
47
|
|
45
48
|
private
|
@@ -50,10 +53,11 @@ class Exiftool
|
|
50
53
|
|
51
54
|
def as_lat_long
|
52
55
|
return raw_value if raw_value.is_a?(Numeric)
|
56
|
+
|
53
57
|
value, direction = raw_value.split(' ')
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
return unless value =~ /\A\d+\.?\d*\z/
|
59
|
+
|
60
|
+
value.to_f * (%w[S W].include?(direction) ? -1 : 1)
|
57
61
|
end
|
58
62
|
|
59
63
|
def date?
|
@@ -82,7 +86,7 @@ class Exiftool
|
|
82
86
|
|
83
87
|
def as_fraction
|
84
88
|
scan = raw_value.scan(FRACTION_RE).first
|
85
|
-
Rational(*scan.map
|
89
|
+
Rational(*scan.map(&:to_i)) unless scan.nil?
|
86
90
|
end
|
87
91
|
end
|
88
92
|
end
|
data/lib/exiftool/result.rb
CHANGED
data/lib/exiftool/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exiftool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew McEachen
|
8
|
+
- Sergey Morozov
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2020-10-06 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: json
|
@@ -25,7 +26,7 @@ dependencies:
|
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '0'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
29
|
+
name: bundler
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
30
31
|
requirements:
|
31
32
|
- - ">="
|
@@ -39,7 +40,7 @@ dependencies:
|
|
39
40
|
- !ruby/object:Gem::Version
|
40
41
|
version: '0'
|
41
42
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
43
|
+
name: minitest
|
43
44
|
requirement: !ruby/object:Gem::Requirement
|
44
45
|
requirements:
|
45
46
|
- - ">="
|
@@ -53,7 +54,7 @@ dependencies:
|
|
53
54
|
- !ruby/object:Gem::Version
|
54
55
|
version: '0'
|
55
56
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
57
|
+
name: minitest-great_expectations
|
57
58
|
requirement: !ruby/object:Gem::Requirement
|
58
59
|
requirements:
|
59
60
|
- - ">="
|
@@ -67,7 +68,7 @@ dependencies:
|
|
67
68
|
- !ruby/object:Gem::Version
|
68
69
|
version: '0'
|
69
70
|
- !ruby/object:Gem::Dependency
|
70
|
-
name: minitest
|
71
|
+
name: minitest-reporters
|
71
72
|
requirement: !ruby/object:Gem::Requirement
|
72
73
|
requirements:
|
73
74
|
- - ">="
|
@@ -81,7 +82,7 @@ dependencies:
|
|
81
82
|
- !ruby/object:Gem::Version
|
82
83
|
version: '0'
|
83
84
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
85
|
+
name: rake
|
85
86
|
requirement: !ruby/object:Gem::Requirement
|
86
87
|
requirements:
|
87
88
|
- - ">="
|
@@ -95,7 +96,49 @@ dependencies:
|
|
95
96
|
- !ruby/object:Gem::Version
|
96
97
|
version: '0'
|
97
98
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
99
|
+
name: rubocop
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: simplecov
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 0.17.1
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.17.1
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: simplecov-console
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: yard
|
99
142
|
requirement: !ruby/object:Gem::Requirement
|
100
143
|
requirements:
|
101
144
|
- - ">="
|
@@ -110,7 +153,8 @@ dependencies:
|
|
110
153
|
version: '0'
|
111
154
|
description: Multiget ExifTool wrapper for ruby
|
112
155
|
email:
|
113
|
-
- matthew
|
156
|
+
- matthew+github@mceachen.org
|
157
|
+
- morozgrafix@gmail.com
|
114
158
|
executables: []
|
115
159
|
extensions: []
|
116
160
|
extra_rdoc_files: []
|
@@ -119,7 +163,7 @@ files:
|
|
119
163
|
- lib/exiftool/field_parser.rb
|
120
164
|
- lib/exiftool/result.rb
|
121
165
|
- lib/exiftool/version.rb
|
122
|
-
homepage: https://github.com/
|
166
|
+
homepage: https://github.com/exiftool-rb/exiftool.rb
|
123
167
|
licenses:
|
124
168
|
- MIT
|
125
169
|
metadata: {}
|
@@ -131,16 +175,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
175
|
requirements:
|
132
176
|
- - ">="
|
133
177
|
- !ruby/object:Gem::Version
|
134
|
-
version: '
|
178
|
+
version: '2.4'
|
135
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
180
|
requirements:
|
137
181
|
- - ">="
|
138
182
|
- !ruby/object:Gem::Version
|
139
183
|
version: '0'
|
140
184
|
requirements:
|
141
|
-
- ExifTool (see http://
|
142
|
-
|
143
|
-
rubygems_version: 2.6.8
|
185
|
+
- ExifTool (see http://exiftool.org)
|
186
|
+
rubygems_version: 3.1.2
|
144
187
|
signing_key:
|
145
188
|
specification_version: 4
|
146
189
|
summary: Multiget ExifTool wrapper for ruby
|