Module: Metaclean::Display

Defined in:
lib/metaclean/display.rb

Constant Summary collapse

COLORS =
{
  reset:   "\e[0m",
  bold:    "\e[1m",
  dim:     "\e[2m",
  red:     "\e[31m",
  green:   "\e[32m",
  yellow:  "\e[33m",
  magenta: "\e[35m",
  cyan:    "\e[36m",
  gray:    "\e[90m"
}.freeze
NON_METADATA_GROUPS =
%w[System File ExifTool Composite].freeze
LOGO =
<<~ART
  ███╗   ███╗███████╗████████╗ █████╗  ██████╗██╗     ███████╗ █████╗ ███╗   ██╗
  ████╗ ████║██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║     ██╔════╝██╔══██╗████╗  ██║
  ██╔████╔██║█████╗     ██║   ███████║██║     ██║     █████╗  ███████║██╔██╗ ██║
  ██║╚██╔╝██║██╔══╝     ██║   ██╔══██║██║     ██║     ██╔══╝  ██╔══██║██║╚██╗██║
  ██║ ╚═╝ ██║███████╗   ██║   ██║  ██║╚██████╗███████╗███████╗██║  ██║██║ ╚████║
  ╚═╝     ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝ ╚═════╝╚══════╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═══╝
ART

Class Method Summary collapse

Class Method Details



62
63
64
65
# File 'lib/metaclean/display.rb', line 62

def banner
  LOGO.each_line { |line| puts c(line.chomp, :red) }
  puts c('  strip EXIF · IPTC · XMP · GPS · ID3 — leave the file clean', :gray)
end

.c(text, color) ⇒ Object



55
56
57
58
59
60
# File 'lib/metaclean/display.rb', line 55

def c(text, color)
  text = printable(text)
  return text unless color?

  "#{COLORS[color]}#{text}#{COLORS[:reset]}"
end

.classify_diff(before, after) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/metaclean/display.rb', line 120

def classify_diff(before, after)
  rows = [[], [], []]
  keys = (before.keys + after.keys).uniq.select { |key| embedded_key?(key) }
  keys.sort.each do |key|
    old_value = before[key]
    new_value = after[key]
    if new_value.nil? && !old_value.nil?
      rows[0] << [key, old_value]
    elsif !old_value.nil? && new_value != old_value
      rows[1] << [key, old_value, new_value]
    elsif !old_value.nil?
      rows[2] << [key, old_value]
    end
  end
  rows
end

.color?Boolean

Returns:

  • (Boolean)


43
44
45
46
47
48
49
50
51
52
53
# File 'lib/metaclean/display.rb', line 43

def color?
  return @color if defined?(@color)

  @color = if !ENV['NO_COLOR'].to_s.empty?
             false
           elsif !ENV['FORCE_COLOR'].to_s.empty?
             true
           else
             $stdout.tty?
           end
end

.configure(quiet: false, redact_values: false) ⇒ Object



30
31
32
33
# File 'lib/metaclean/display.rb', line 30

def configure(quiet: false, redact_values: false)
  @quiet = quiet
  @redact_values = redact_values
end

.count_embedded(meta) ⇒ Object



198
199
200
# File 'lib/metaclean/display.rb', line 198

def count_embedded(meta)
  meta.keys.count { |k| embedded_key?(k) }
end

.diff(before, after) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/metaclean/display.rb', line 105

def diff(before, after)
  return if quiet?

  removed, changed, kept = classify_diff(before, after)
  render_removed(removed)
  render_changed(changed)
  render_kept(kept)

  if [removed, changed, kept].all?(&:empty?)
    info 'Nothing to strip — file already clean.'
  elsif removed.empty? && changed.empty?
    info 'No tags were removed — see "Still present" above.'
  end
end

.embedded_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/metaclean/display.rb', line 170

def embedded_key?(key)
  key != 'SourceFile' && !NON_METADATA_GROUPS.include?(group_of(key))
end

.error(text) ⇒ Object



81
# File 'lib/metaclean/display.rb', line 81

def error(text); c("#{text}", :red); end

.format_value(v) ⇒ Object



174
175
176
177
178
179
180
181
# File 'lib/metaclean/display.rb', line 174

def format_value(v)
  case v
  when Hash, Array then printable(v.inspect)
  else
    s = printable(v)
    s.gsub(/\s+/, ' ')
  end
end

.group_of(key) ⇒ Object



166
167
168
# File 'lib/metaclean/display.rb', line 166

def group_of(key)
  key.to_s.split(':', 2).first.to_s
end

.header(text) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/metaclean/display.rb', line 67

def header(text)
  return if quiet?

  puts
  puts c('' * 64, :gray)
  puts c(text, :bold)
  puts c('' * 64, :gray)
end

.info(text) ⇒ Object



77
# File 'lib/metaclean/display.rb', line 77

def info(text);    puts c("  #{text}",  :gray) unless quiet?;  end

.metadata_table(meta, only_embedded: false) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/metaclean/display.rb', line 83

def (meta, only_embedded: false)
  return if quiet?

  rows = meta.reject { |k, _| k == 'SourceFile' }
  rows = rows.select { |k, _| embedded_key?(k) } if only_embedded

  if rows.empty?
    info(only_embedded ? '(no embedded metadata)' : '(no metadata)')
    return
  end

  grouped = rows.group_by { |k, _| group_of(k) }
  grouped.sort_by { |g, _| g.to_s }.each do |group, pairs|
    puts c("  [#{group}]", :magenta)
    pairs.sort_by { |k, _| k.to_s }.each do |k, v|
      tag = k.to_s.split(':', 2).last
      line = format('    %-38s %s', truncate(tag, 38), truncate(visible_value(v), 60))
      puts c(line, :dim)
    end
  end
end

.printable(text) ⇒ Object



187
188
189
190
191
# File 'lib/metaclean/display.rb', line 187

def printable(text)
  s = text.to_s
  s = s.scrub unless s.valid_encoding?
  s.gsub(/[[:cntrl:]]/, ' ')
end

.quiet?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/metaclean/display.rb', line 35

def quiet?
  @quiet == true
end

.redact_values?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/metaclean/display.rb', line 39

def redact_values?
  @redact_values == true
end

.render_changed(rows) ⇒ Object



146
147
148
149
150
151
152
153
154
155
# File 'lib/metaclean/display.rb', line 146

def render_changed(rows)
  return if rows.empty?

  section "Changed (#{rows.size})"
  rows.each do |key, old_value, new_value|
    puts "  #{c('~', :yellow)} #{c(key, :yellow)}"
    puts "      #{c('-', :red)}   #{truncate(visible_value(old_value), 60)}"
    puts "      #{c('+', :green)} #{truncate(visible_value(new_value), 60)}"
  end
end

.render_kept(rows) ⇒ Object



157
158
159
160
161
162
163
164
# File 'lib/metaclean/display.rb', line 157

def render_kept(rows)
  return if rows.empty?

  section "Still present (#{rows.size})"
  rows.each do |key, value|
    puts "  #{c('=', :gray)} #{c(key, :gray)}  #{c(truncate(visible_value(value), 60), :gray)}"
  end
end

.render_removed(rows) ⇒ Object



137
138
139
140
141
142
143
144
# File 'lib/metaclean/display.rb', line 137

def render_removed(rows)
  return if rows.empty?

  section "Removed (#{rows.size})"
  rows.each do |key, value|
    puts "  #{c('-', :red)} #{c(key, :red)}  #{c(truncate(visible_value(value), 60), :gray)}"
  end
end

.section(text) ⇒ Object



76
# File 'lib/metaclean/display.rb', line 76

def section(text); puts c("#{text}",  :cyan) unless quiet?;  end

.success(text) ⇒ Object



78
# File 'lib/metaclean/display.rb', line 78

def success(text); puts c("#{text}",  :green) unless quiet?; end

.truncate(s, n) ⇒ Object



193
194
195
196
# File 'lib/metaclean/display.rb', line 193

def truncate(s, n)
  s = s.to_s
  s.length > n ? "#{s[0, n - 1]}" : s
end

.visible_value(value) ⇒ Object



183
184
185
# File 'lib/metaclean/display.rb', line 183

def visible_value(value)
  redact_values? ? '[redacted]' : format_value(value)
end

.warning(text) ⇒ Object



79
# File 'lib/metaclean/display.rb', line 79

def warning(text); warn c("#{text}",  :yellow);end