Class: Aspera::Preview::Utils

Inherits:
Object
  • Object
show all
Defined in:
lib/aspera/preview/utils.rb

Class Method Summary collapse

Class Method Details

.check_tools(skip_types = []) ⇒ nil

Check that external tools can be executed

Parameters:

  • skip_types (Array<Symbol>) (defaults to: [])

    list of tools to skip

Returns:

  • (nil)


29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/aspera/preview/utils.rb', line 29

def check_tools(skip_types = [])
  tools_to_check = EXTERNAL_TOOLS.dup
  if skip_types.include?(:office)
    tools_to_check.delete(:unoconv)
    tools_to_check.delete(:soffice)
  end
  # Check for binaries
  tools_to_check.each do |command_sym|
    silent_execute(command_sym, '-h')
  rescue Errno::ENOENT => e
    raise "missing #{command_sym} binary: #{e}"
  rescue
    nil
  end
end

.execute(*args, **kwargs) ⇒ Object

Execute external command, verify it is in the supported list



46
47
48
49
# File 'lib/aspera/preview/utils.rb', line 46

def execute(*args, **kwargs)
  Aspera.assert_values(args.first, EXTERNAL_TOOLS){'command'}
  Environment.secure_execute(*args, **kwargs)
end

.ffmpeg(gl_p: FFMPEG_DEFAULT_PARAMS, in_p: [], in_f:, out_p: [], out_f:) ⇒ nil

Execute ‘ffmpeg`

Returns:

  • (nil)


60
61
62
63
64
65
# File 'lib/aspera/preview/utils.rb', line 60

def ffmpeg(gl_p: FFMPEG_DEFAULT_PARAMS, in_p: [], in_f:, out_p: [], out_f:)
  Aspera.assert_type(gl_p, Array)
  Aspera.assert_type(in_p, Array)
  Aspera.assert_type(out_p, Array)
  silent_execute(:ffmpeg, *gl_p, *in_p, '-i', in_f, *out_p, out_f)
end

.ffmpeg_fmt(temp_folder) ⇒ Object

File output format, including temp folder



80
81
82
# File 'lib/aspera/preview/utils.rb', line 80

def ffmpeg_fmt(temp_folder)
  return File.join(temp_folder, TEMP_FORMAT)
end

.get_tmp_num_filepath(temp_folder, file_number) ⇒ Object



84
85
86
87
# File 'lib/aspera/preview/utils.rb', line 84

def get_tmp_num_filepath(temp_folder, file_number)
  # Format using {Kernel.format}
  return File.join(temp_folder, format(TEMP_FORMAT, file_number))
end

.parse_magick_fonts(output) ⇒ Hash

Parse the output of ‘magick identify -list font` command

Parameters:

  • output (String)

    the output from ‘magick -list font`

Returns:

  • (Hash)

    with keys :path and :fonts :path [String] the path to the type.xml file :fonts [Array<Hash>] array of font hashes with keys:

    :name, :family, :style, :stretch, :weight, :metrics, :glyphs, :index
    


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/aspera/preview/utils.rb', line 128

def parse_magick_fonts(output)
  result = {path: nil, fonts: []}
  current_font = nil
  output.each_line do |line|
    line = line.strip
    # Parse the Path line
    if line.start_with?('Path:')
      result[:path] = line.sub(/^Path:\s*/, '')
    # Parse Font name
    elsif line.start_with?('Font:')
      # Save previous font if exists
      result[:fonts] << current_font if current_font
      # Start new font
      current_font = {name: line.sub(/^Font:\s*/, '')}
    # Parse font properties
    elsif current_font && line.include?(':')
      key, value = line.split(':', 2)
      key = key.strip.gsub(/\s+/, '_').to_sym
      value = value.strip
      # Convert numeric values
      value = value.to_i if key == :weight || key == :index
      current_font[key] = value
    end
  end
  # Don't forget the last font
  result[:fonts] << current_font if current_font
  result
end

.silent_execute(*args) ⇒ nil

Execute external command silently

Returns:

  • (nil)


53
54
55
56
# File 'lib/aspera/preview/utils.rb', line 53

def silent_execute(*args)
  execute(*args, out: File::NULL, err: File::NULL)
  nil
end

.video_blend_frames(temp_folder, index_begin, index_end) ⇒ Object



96
97
98
99
100
101
102
103
104
105
# File 'lib/aspera/preview/utils.rb', line 96

def video_blend_frames(temp_folder, index_begin, index_end)
  img1 = get_tmp_num_filepath(temp_folder, index_begin)
  img2 = get_tmp_num_filepath(temp_folder, index_end)
  count = index_end - index_begin - 1
  1.upto(count) do |i|
    percent = i * 100 / (count + 1)
    filename = get_tmp_num_filepath(temp_folder, index_begin + i)
    silent_execute(:magick, 'composite', '-blend', percent, img2, img1, filename)
  end
end

.video_dump_frame(input_file, offset_seconds, scale, output_file) ⇒ nil

Dump a frame from a video file

Parameters:

  • input_file (String)

    the input file path

  • offset_seconds (Integer)

    the offset in seconds

  • scale (String)

    the scale of the output frame

  • output_file (String)

    the output file path

Returns:

  • (nil)


113
114
115
116
117
118
119
120
# File 'lib/aspera/preview/utils.rb', line 113

def video_dump_frame(input_file, offset_seconds, scale, output_file)
  ffmpeg(
    in_f: input_file,
    in_p: ['-ss', offset_seconds],
    out_f: output_file,
    out_p: ['-frames:v', 1, '-filter:v', "scale=#{scale}"]
  )
end

.video_dupe_frame(temp_folder, index, count) ⇒ Object



89
90
91
92
93
94
# File 'lib/aspera/preview/utils.rb', line 89

def video_dupe_frame(temp_folder, index, count)
  input_file = get_tmp_num_filepath(temp_folder, index)
  1.upto(count) do |i|
    FileUtils.ln_s(input_file, get_tmp_num_filepath(temp_folder, index + i))
  end
end

.video_get_duration(input_file) ⇒ Object

Returns Float in seconds.

Returns:

  • Float in seconds



68
69
70
71
72
73
74
75
76
77
# File 'lib/aspera/preview/utils.rb', line 68

def video_get_duration(input_file)
  return execute(
    :ffprobe,
    '-loglevel', 'error',
    '-show_entries', 'format=duration',
    '-print_format', 'default=noprint_wrappers=1:nokey=1', # cspell:disable-line
    input_file,
    mode: :capture
  ).first.to_f
end