Module: Metaclean::Mat2

Defined in:
lib/metaclean/mat2.rb

Constant Summary collapse

SUPPORTED_EXTS =

File extensions we know mat2 can handle. Keep this list conservative —if mat2 doesn’t actually support an extension, the call will fail gracefully via UNSUPPORTED_RE below, but we’d rather not even try.

%w[
  pdf png jpg jpeg tif tiff gif bmp svg webp
  mp3 flac ogg opus wav m4a
  mp4 avi mkv mov wmv webm
  docx xlsx pptx odt ods odp odg odf epub
  zip torrent
].freeze
UNSUPPORTED_RE =

Regex matching the messages mat2 prints when it can’t handle a file. We use this to distinguish “soft skip” from a real error. ‘i` flag = case-insensitive.

/(not supported|isn't supported|cannot be cleaned|unsupported file)/i.freeze

Class Method Summary collapse

Class Method Details

.available?Boolean

Memoized PATH check (same pattern as Exiftool.available?).

Returns:

  • (Boolean)


39
40
41
42
43
44
45
46
# File 'lib/metaclean/mat2.rb', line 39

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

  _out, _err, status = Open3.capture3('mat2', '--version')
  @available = status.success?
rescue Errno::ENOENT
  @available = false
end

.cleaned_path_for(path) ⇒ Object

Builds the path mat2 will write to: ‘name.cleaned.ext`. We use File.dirname/basename/join instead of string concatenation so this works on Windows (\ separator) too.



116
117
118
119
120
121
# File 'lib/metaclean/mat2.rb', line 116

def cleaned_path_for(path)
  dir  = File.dirname(path)
  ext  = File.extname(path)
  stem = File.basename(path, ext)
  File.join(dir, "#{stem}.cleaned#{ext}")
end

.strip!(path) ⇒ Object

Strips metadata from ‘path` in place. Returns:

true           — stripped successfully
:no_metadata   — mat2 ran but found nothing to strip
:unsupported   — mat2 cannot handle this file type

Raises Metaclean::Error on hard failure.

We return symbols (instead of always raising) so the runner can show a friendly “skipped” message and continue with the next tool.

Raises:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/metaclean/mat2.rb', line 75

def strip!(path)
  raise Error, 'mat2 not available' unless available?

  cleaned = cleaned_path_for(path)

  # Defensive: if a stale `<name>.cleaned.<ext>` exists from an earlier
  # crashed run, remove it so we don't accidentally use old data.
  File.delete(cleaned) if File.exist?(cleaned)

  out, err, status = Open3.capture3('mat2', path.to_s)
  combined = "#{out}\n#{err}"

  # Soft skip — mat2 itself told us it can't process this file.
  # Defensive: if mat2 still wrote a partial `<name>.cleaned.<ext>`,
  # remove it so a later run doesn't pick up stale output.
  if combined.match?(UNSUPPORTED_RE)
    File.delete(cleaned) if File.exist?(cleaned)
    return :unsupported
  end

  unless status.success?
    File.delete(cleaned) if File.exist?(cleaned)
    # `err.strip.empty? ? out.strip : err.strip` picks whichever stream
    # has actual content — some tools log to stdout, others to stderr.
    raise Error, "mat2 failed: #{err.strip.empty? ? out.strip : err.strip}"
  end

  # mat2 only creates `<name>.cleaned.<ext>` when it actually stripped
  # something. If the file didn't exist after a successful run, there
  # was nothing to remove.
  if File.exist?(cleaned)
    FileUtils.mv(cleaned, path.to_s)
    true
  else
    :no_metadata
  end
end

.supports?(path) ⇒ Boolean

Quick check before we even try mat2 on a file. Used by Strategy to decide whether to add :mat2 to the pipeline.

Returns:

  • (Boolean)


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

def supports?(path)
  return false unless available?

  SUPPORTED_EXTS.include?(File.extname(path).downcase.delete('.'))
end

.versionObject



48
49
50
51
52
53
54
55
56
57
# File 'lib/metaclean/mat2.rb', line 48

def version
  return nil unless available?

  out, _err, status = Open3.capture3('mat2', '--version')
  # `mat2 --version` prints "mat2 0.14.0" — `.split.last` grabs the
  # version number regardless of whatever prefix appears.
  status.success? ? out.strip.split.last : nil
rescue Errno::ENOENT
  nil
end