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 = []) ⇒ Object

check that external tools can be executed



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

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

.external_command(command_sym, command_args, check_code: true) ⇒ Object

execute external command one could use “system”, but we would need to redirect stdout/err

Returns:

  • true if su



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/aspera/preview/utils.rb', line 46

def external_command(command_sym, command_args, check_code: true)
  Aspera.assert_values(command_sym, EXTERNAL_TOOLS){'command'}
  # build command line, and quote special characters
  command_line = command_args.clone.unshift(command_sym).map{|i| shell_quote(i.to_s)}.join(' ')
  Log.log.debug{"cmd=#{command_line}".blue}
  stdout, stderr, status = Open3.capture3(command_line)
  if check_code && !status.success?
    Log.log.error{"status: #{status}"}
    Log.log.error{"stdout: #{stdout}"}
    Log.log.error{"stderr: #{stderr}"}
    raise "#{command_sym} error #{status}"
  end
  return {status: status, stdout: stdout}
end

.ffmpeg(a) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/aspera/preview/utils.rb', line 61

def ffmpeg(a)
  Aspera.assert_type(a, Hash)
  # input_file,input_args,output_file,output_args
  a[:gl_p] ||= [
    '-y', # overwrite output without asking
    '-loglevel', 'error' # show only errors and up
  ]
  a[:in_p] ||= []
  a[:out_p] ||= []
  Aspera.assert(%i[gl_p in_f in_p out_f out_p].eql?(a.keys.sort)){"wrong params (#{a.keys.sort})"}
  external_command(:ffmpeg, [a[:gl_p], a[:in_p], '-i', a[:in_f], a[:out_p], a[:out_f]].flatten)
end

.ffmpeg_fmt(temp_folder) ⇒ Object



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

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

.get_tmp_num_filepath(temp_folder, file_number) ⇒ Object



88
89
90
# File 'lib/aspera/preview/utils.rb', line 88

def get_tmp_num_filepath(temp_folder, file_number)
  return File.join(temp_folder, format(TEMP_FORMAT, file_number))
end

.shell_quote(argument) ⇒ Object

returns string with single quotes suitable for bash if there is any bash meta-character



23
24
25
26
27
# File 'lib/aspera/preview/utils.rb', line 23

def shell_quote(argument)
  return argument unless argument.chars.any?{|c|BASH_SPECIAL_CHARACTERS.include?(c)}
  # surround with single quotes, and escape single quotes
  return %Q{'#{argument.gsub("'"){|_s| %q{'"'"'}}}'}
end

.video_blend_frames(temp_folder, index1, index2) ⇒ Object



99
100
101
102
103
104
105
106
107
108
# File 'lib/aspera/preview/utils.rb', line 99

def video_blend_frames(temp_folder, index1, index2)
  img1 = get_tmp_num_filepath(temp_folder, index1)
  img2 = get_tmp_num_filepath(temp_folder, index2)
  count = index2 - index1 - 1
  1.upto(count) do |i|
    percent = i * 100 / (count + 1)
    filename = get_tmp_num_filepath(temp_folder, index1 + i)
    external_command(:composite, ['-blend', percent, img2, img1, filename])
  end
end

.video_dump_frame(input_file, offset_seconds, scale, output_file, index = nil) ⇒ Object



110
111
112
113
114
115
116
117
118
# File 'lib/aspera/preview/utils.rb', line 110

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

.video_dupe_frame(temp_folder, index, count) ⇒ Object



92
93
94
95
96
97
# File 'lib/aspera/preview/utils.rb', line 92

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



75
76
77
78
79
80
81
82
# File 'lib/aspera/preview/utils.rb', line 75

def video_get_duration(input_file)
  result = external_command(:ffprobe, [
    '-loglevel', 'error',
    '-show_entries', 'format=duration',
    '-print_format', 'default=noprint_wrappers=1:nokey=1', # cspell:disable-line
    input_file])
  return result[:stdout].to_f
end