Module: Metaclean::Ffmpeg

Defined in:
lib/metaclean/ffmpeg.rb

Class Method Summary collapse

Class Method Details

.available?Boolean

Memoized PATH check (same pattern as the other wrappers).

Returns:

  • (Boolean)


23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/metaclean/ffmpeg.rb', line 23

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

  out, _err, status = Open3.capture3('ffmpeg', '-version')
  @available = status.success?
  # First line is "ffmpeg version 7.1.1 Copyright ..."; grab the 3rd token.
  @version = @available ? out.lines.first.to_s.split[2] : nil
  @available
rescue Errno::ENOENT
  @version = nil
  @available = false
end

.file_url(path) ⇒ Object



80
81
82
# File 'lib/metaclean/ffmpeg.rb', line 80

def file_url(path)
  "file:#{File.expand_path(path)}"
end

.strip!(path) ⇒ Object

Strips all metadata from ‘path` in place, losslessly. Returns true on success, raises Metaclean::Error on failure.

-map 0            keep every stream (video, audio, subtitles)
-map_metadata -1  drop global/container metadata
-map_chapters -1  drop chapter markers (they can carry titles)
-c copy           remux without re-encoding — bit-identical streams


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/metaclean/ffmpeg.rb', line 47

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

  tmp  = tmp_path_for(path)
  # Clear any stale temp from an earlier crashed run before muxing.
  File.delete(tmp) if File.exist?(tmp)

  _out, err, status = Open3.capture3(
    'ffmpeg', '-y', '-v', 'error', '-nostdin', '-i', file_url(path),
    '-map', '0', '-map_metadata', '-1', '-map_chapters', '-1', '-c', 'copy',
    file_url(tmp)
  )
  # ffmpeg can exit 0 yet write nothing on some odd inputs, so require the
  # output to actually exist before we trust it and move it into place.
  raise Error, "ffmpeg failed: #{err.strip}" unless status.success? && File.exist?(tmp)

  FileUtils.mv(tmp, path)
  true
ensure
  # Interrupt-safety: drop the temp if we were killed between mux and rename.
  # On the success path it's already moved, so this is a no-op.
  File.delete(tmp) if tmp && File.exist?(tmp)
end

.tmp_path_for(path) ⇒ Object

Sibling temp with the SAME extension (ffmpeg picks the muxer from it) in the SAME directory (so the final rename is an atomic same-fs move). The “.metaclean.tmp.” marker means Runner#skip? ignores any stray leftover.



74
75
76
77
78
# File 'lib/metaclean/ffmpeg.rb', line 74

def tmp_path_for(path)
  dir  = File.dirname(path)
  ext  = File.extname(path)
  File.join(dir, ".metaclean.tmp.ff.#{Process.pid}.#{SecureRandom.hex(8)}#{ext}")
end

.versionObject



36
37
38
# File 'lib/metaclean/ffmpeg.rb', line 36

def version
  available? ? @version : nil
end