exiftool 1.0.1 → 1.2.3
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 +35 -25
- data/lib/exiftool/field_parser.rb +30 -23
- data/lib/exiftool/result.rb +3 -0
- data/lib/exiftool/version.rb +3 -1
- metadata +84 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 910908d5f0f83f412883644c911b63df24be598fc6ee9cc6b4e3555d3aabe4ff
|
4
|
+
data.tar.gz: 9859f9f20d72bba3dd9b8577aff0059118070ced6fdae5885521c6726f722092
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d778dba97dcdfa9f3ca613af37a36133e1f6fb724a39d93162b7bcca52fc6222f3fdfd2ef7a497d63f7af0ad4a3bfbf349b2d6357571fd864db466032af62445
|
7
|
+
data.tar.gz: f8b32e9d8414ce4adb0987a4f17046f690bf130c9492f3406325fe9c876af6ab74766294c2c5dabf479c18c0e6f34d11af4c1e9dfed2ad018f50f009a881075f
|
data/lib/exiftool.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
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
|
-
|
9
|
-
class
|
10
|
-
|
10
|
+
class NoSuchFile < StandardError; end
|
11
|
+
|
12
|
+
class NotAFile < StandardError; end
|
13
|
+
|
14
|
+
class ExiftoolNotInstalled < StandardError; end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
class NoDefaultResultWithMultiget < StandardError; end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_writer :command
|
14
20
|
end
|
15
21
|
|
16
22
|
def self.command
|
@@ -18,7 +24,7 @@ class Exiftool
|
|
18
24
|
end
|
19
25
|
|
20
26
|
def self.exiftool_installed?
|
21
|
-
exiftool_version
|
27
|
+
exiftool_version.to_f.positive?
|
22
28
|
end
|
23
29
|
|
24
30
|
# This is a string, not a float, to handle versions like "9.40" properly.
|
@@ -28,7 +34,9 @@ class Exiftool
|
|
28
34
|
|
29
35
|
def self.expand_path(filename)
|
30
36
|
raise(NoSuchFile, filename) unless File.exist?(filename)
|
37
|
+
|
31
38
|
raise(NotAFile, filename) unless File.file?(filename)
|
39
|
+
|
32
40
|
File.expand_path(filename)
|
33
41
|
end
|
34
42
|
|
@@ -38,28 +46,29 @@ class Exiftool
|
|
38
46
|
|
39
47
|
def initialize(filenames, exiftool_opts = '')
|
40
48
|
@file2result = {}
|
41
|
-
filenames = [filenames] if filenames.is_a?(String)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
49
|
+
filenames = [filenames] if filenames.is_a?(String) || filenames.is_a?(Pathname)
|
50
|
+
return if filenames.empty?
|
51
|
+
|
52
|
+
escaped_filenames = filenames.map do |f|
|
53
|
+
Shellwords.escape(self.class.expand_path(f.to_s))
|
54
|
+
end.join(' ')
|
55
|
+
# I'd like to use -dateformat, but it doesn't support timezone offsets properly,
|
56
|
+
# nor sub-second timestamps.
|
57
|
+
cmd = "#{self.class.command} #{exiftool_opts} -j -coordFormat \"%.8f\" #{escaped_filenames} 2> /dev/null"
|
58
|
+
json = `#{cmd}`.chomp
|
59
|
+
raise ExiftoolNotInstalled if json == ''
|
60
|
+
|
61
|
+
JSON.parse(json).each do |raw|
|
62
|
+
result = Result.new(raw)
|
63
|
+
@file2result[result.source_file] = result
|
55
64
|
end
|
56
65
|
end
|
57
66
|
|
58
|
-
def results(include_results_with_errors
|
67
|
+
def results(include_results_with_errors: false)
|
59
68
|
if include_results_with_errors
|
60
69
|
@file2result.values
|
61
70
|
else
|
62
|
-
@file2result.values.
|
71
|
+
@file2result.values.reject(&:errors?)
|
63
72
|
end
|
64
73
|
end
|
65
74
|
|
@@ -68,17 +77,18 @@ class Exiftool
|
|
68
77
|
end
|
69
78
|
|
70
79
|
def files_with_results
|
71
|
-
results.map
|
80
|
+
results.map(&:source_file)
|
72
81
|
end
|
73
82
|
|
74
83
|
def errors?
|
75
|
-
@file2result.values.any?
|
84
|
+
@file2result.values.any?(&:errors?)
|
76
85
|
end
|
77
86
|
|
78
87
|
private
|
79
88
|
|
80
89
|
def first_result
|
81
90
|
raise(NoDefaultResultWithMultiget, 'use #result_for when multiple filenames are used') if @file2result.size > 1
|
91
|
+
|
82
92
|
@file2result.values.first
|
83
93
|
end
|
84
94
|
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,23 +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
|
-
|
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)
|
40
46
|
end
|
41
47
|
|
42
48
|
private
|
@@ -47,10 +53,11 @@ class Exiftool
|
|
47
53
|
|
48
54
|
def as_lat_long
|
49
55
|
return raw_value if raw_value.is_a?(Numeric)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
56
|
+
|
57
|
+
value, direction = raw_value.split
|
58
|
+
return unless value =~ /\A\d+\.?\d*\z/
|
59
|
+
|
60
|
+
value.to_f * (%w[S W].include?(direction) ? -1 : 1)
|
54
61
|
end
|
55
62
|
|
56
63
|
def date?
|
@@ -79,7 +86,7 @@ class Exiftool
|
|
79
86
|
|
80
87
|
def as_fraction
|
81
88
|
scan = raw_value.scan(FRACTION_RE).first
|
82
|
-
Rational(*scan.map
|
89
|
+
Rational(*scan.map(&:to_i)) unless scan.nil?
|
83
90
|
end
|
84
91
|
end
|
85
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.
|
4
|
+
version: 1.2.3
|
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: 2021-02-05 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: json
|
@@ -24,6 +25,62 @@ dependencies:
|
|
24
25
|
- - ">="
|
25
26
|
- !ruby/object:Gem::Version
|
26
27
|
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: minitest
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: minitest-great_expectations
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: minitest-reporters
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
27
84
|
- !ruby/object:Gem::Dependency
|
28
85
|
name: rake
|
29
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,7 +96,7 @@ dependencies:
|
|
39
96
|
- !ruby/object:Gem::Version
|
40
97
|
version: '0'
|
41
98
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
99
|
+
name: rubocop
|
43
100
|
requirement: !ruby/object:Gem::Requirement
|
44
101
|
requirements:
|
45
102
|
- - ">="
|
@@ -53,7 +110,7 @@ dependencies:
|
|
53
110
|
- !ruby/object:Gem::Version
|
54
111
|
version: '0'
|
55
112
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
113
|
+
name: rubocop-minitest
|
57
114
|
requirement: !ruby/object:Gem::Requirement
|
58
115
|
requirements:
|
59
116
|
- - ">="
|
@@ -67,7 +124,7 @@ dependencies:
|
|
67
124
|
- !ruby/object:Gem::Version
|
68
125
|
version: '0'
|
69
126
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
127
|
+
name: rubocop-rake
|
71
128
|
requirement: !ruby/object:Gem::Requirement
|
72
129
|
requirements:
|
73
130
|
- - ">="
|
@@ -81,7 +138,21 @@ dependencies:
|
|
81
138
|
- !ruby/object:Gem::Version
|
82
139
|
version: '0'
|
83
140
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
141
|
+
name: simplecov
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 0.17.1
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 0.17.1
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: simplecov-console
|
85
156
|
requirement: !ruby/object:Gem::Requirement
|
86
157
|
requirements:
|
87
158
|
- - ">="
|
@@ -95,7 +166,7 @@ dependencies:
|
|
95
166
|
- !ruby/object:Gem::Version
|
96
167
|
version: '0'
|
97
168
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
169
|
+
name: yard
|
99
170
|
requirement: !ruby/object:Gem::Requirement
|
100
171
|
requirements:
|
101
172
|
- - ">="
|
@@ -110,7 +181,8 @@ dependencies:
|
|
110
181
|
version: '0'
|
111
182
|
description: Multiget ExifTool wrapper for ruby
|
112
183
|
email:
|
113
|
-
- matthew
|
184
|
+
- matthew+github@mceachen.org
|
185
|
+
- morozgrafix@gmail.com
|
114
186
|
executables: []
|
115
187
|
extensions: []
|
116
188
|
extra_rdoc_files: []
|
@@ -119,7 +191,7 @@ files:
|
|
119
191
|
- lib/exiftool/field_parser.rb
|
120
192
|
- lib/exiftool/result.rb
|
121
193
|
- lib/exiftool/version.rb
|
122
|
-
homepage: https://github.com/
|
194
|
+
homepage: https://github.com/exiftool-rb/exiftool.rb
|
123
195
|
licenses:
|
124
196
|
- MIT
|
125
197
|
metadata: {}
|
@@ -131,16 +203,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
131
203
|
requirements:
|
132
204
|
- - ">="
|
133
205
|
- !ruby/object:Gem::Version
|
134
|
-
version: '
|
206
|
+
version: '2.4'
|
135
207
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
136
208
|
requirements:
|
137
209
|
- - ">="
|
138
210
|
- !ruby/object:Gem::Version
|
139
211
|
version: '0'
|
140
212
|
requirements:
|
141
|
-
- ExifTool (see http://
|
142
|
-
|
143
|
-
rubygems_version: 2.5.1
|
213
|
+
- ExifTool (see http://exiftool.org)
|
214
|
+
rubygems_version: 3.1.4
|
144
215
|
signing_key:
|
145
216
|
specification_version: 4
|
146
217
|
summary: Multiget ExifTool wrapper for ruby
|