aspera-cli 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -0
- data/README.md +844 -861
- data/bin/ascli +20 -1
- data/bin/asession +37 -34
- data/docs/test_env.conf +11 -3
- data/examples/aoc.rb +13 -12
- data/examples/dascli +26 -0
- data/examples/faspex4.rb +34 -29
- data/examples/transfer.rb +30 -29
- data/lib/aspera/aoc.rb +151 -143
- data/lib/aspera/ascmd.rb +56 -45
- data/lib/aspera/ats_api.rb +6 -5
- data/lib/aspera/cli/basic_auth_plugin.rb +18 -16
- data/lib/aspera/cli/extended_value.rb +32 -30
- data/lib/aspera/cli/formater.rb +103 -111
- data/lib/aspera/cli/info.rb +2 -1
- data/lib/aspera/cli/listener/line_dump.rb +1 -0
- data/lib/aspera/cli/listener/logger.rb +1 -0
- data/lib/aspera/cli/listener/progress.rb +13 -12
- data/lib/aspera/cli/listener/progress_multi.rb +21 -20
- data/lib/aspera/cli/main.rb +106 -89
- data/lib/aspera/cli/manager.rb +96 -85
- data/lib/aspera/cli/plugin.rb +50 -32
- data/lib/aspera/cli/plugins/alee.rb +6 -5
- data/lib/aspera/cli/plugins/aoc.rb +521 -426
- data/lib/aspera/cli/plugins/ats.rb +84 -83
- data/lib/aspera/cli/plugins/bss.rb +30 -27
- data/lib/aspera/cli/plugins/config.rb +483 -397
- data/lib/aspera/cli/plugins/console.rb +17 -15
- data/lib/aspera/cli/plugins/cos.rb +26 -35
- data/lib/aspera/cli/plugins/faspex.rb +201 -168
- data/lib/aspera/cli/plugins/faspex5.rb +109 -74
- data/lib/aspera/cli/plugins/node.rb +378 -189
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -65
- data/lib/aspera/cli/plugins/preview.rb +131 -122
- data/lib/aspera/cli/plugins/server.rb +94 -93
- data/lib/aspera/cli/plugins/shares.rb +42 -28
- data/lib/aspera/cli/plugins/sync.rb +15 -14
- data/lib/aspera/cli/transfer_agent.rb +56 -52
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +29 -28
- data/lib/aspera/command_line_builder.rb +50 -43
- data/lib/aspera/cos_node.rb +64 -38
- data/lib/aspera/data_repository.rb +1 -0
- data/lib/aspera/environment.rb +18 -8
- data/lib/aspera/fasp/agent_base.rb +26 -23
- data/lib/aspera/fasp/agent_connect.rb +35 -30
- data/lib/aspera/fasp/agent_direct.rb +68 -60
- data/lib/aspera/fasp/agent_httpgw.rb +71 -64
- data/lib/aspera/fasp/agent_node.rb +24 -23
- data/lib/aspera/fasp/agent_trsdk.rb +19 -20
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +79 -68
- data/lib/aspera/fasp/installation.rb +122 -114
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +44 -41
- data/lib/aspera/fasp/resume_policy.rb +14 -11
- data/lib/aspera/fasp/transfer_spec.rb +6 -5
- data/lib/aspera/fasp/uri.rb +25 -24
- data/lib/aspera/faspex_gw.rb +83 -72
- data/lib/aspera/hash_ext.rb +10 -12
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +60 -45
- data/lib/aspera/keychain/macos_security.rb +26 -24
- data/lib/aspera/log.rb +34 -38
- data/lib/aspera/nagios.rb +14 -13
- data/lib/aspera/node.rb +19 -19
- data/lib/aspera/oauth.rb +121 -101
- data/lib/aspera/open_application.rb +6 -5
- data/lib/aspera/persistency_action_once.rb +9 -8
- data/lib/aspera/persistency_folder.rb +10 -9
- data/lib/aspera/preview/file_types.rb +261 -266
- data/lib/aspera/preview/generator.rb +74 -73
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +7 -6
- data/lib/aspera/preview/utils.rb +30 -33
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/proxy_auto_config.rb +25 -23
- data/lib/aspera/rest.rb +73 -74
- data/lib/aspera/rest_call_error.rb +1 -0
- data/lib/aspera/rest_error_analyzer.rb +11 -9
- data/lib/aspera/rest_errors_aspera.rb +5 -4
- data/lib/aspera/secret_hider.rb +68 -0
- data/lib/aspera/ssh.rb +12 -10
- data/lib/aspera/sync.rb +49 -47
- data/lib/aspera/temp_file_manager.rb +7 -5
- data/lib/aspera/timer_limiter.rb +9 -8
- data/lib/aspera/uri_reader.rb +11 -14
- data/lib/aspera/web_auth.rb +17 -15
- data.tar.gz.sig +0 -0
- metadata +117 -34
- metadata.gz.sig +2 -0
- data/bin/dascli +0 -13
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'open3'
|
3
4
|
require 'aspera/preview/options'
|
4
5
|
require 'aspera/preview/utils'
|
@@ -9,7 +10,7 @@ module Aspera
|
|
9
10
|
# generate one preview file for one format for one file at a time
|
10
11
|
class Generator
|
11
12
|
# values for preview_format : output format
|
12
|
-
PREVIEW_FORMATS=[
|
13
|
+
PREVIEW_FORMATS = %i[png mp4].freeze
|
13
14
|
|
14
15
|
# CLI needs to know conversion type to know if need skip it
|
15
16
|
attr_reader :conversion_type
|
@@ -27,25 +28,25 @@ module Aspera
|
|
27
28
|
# the conversion video->mp4 is implemented in methods: convert_video_to_mp4_using_<video_conversion>
|
28
29
|
# -> conversion method is one of Generator::VIDEO_CONVERSION_METHODS
|
29
30
|
def initialize(options,src,dst,main_temp_dir,api_mime_type)
|
30
|
-
@options=options
|
31
|
-
@source_file_path=src
|
32
|
-
@destination_file_path=dst
|
33
|
-
@temp_folder=File.join(main_temp_dir,@source_file_path.split('/').last.gsub(/\s/, '_').gsub(/\W/, ''))
|
31
|
+
@options = options
|
32
|
+
@source_file_path = src
|
33
|
+
@destination_file_path = dst
|
34
|
+
@temp_folder = File.join(main_temp_dir,@source_file_path.split('/').last.gsub(/\s/, '_').gsub(/\W/, ''))
|
34
35
|
# extract preview format from extension of target file
|
35
|
-
@preview_format_symb=File.extname(@destination_file_path).gsub(/^\./,'').to_sym
|
36
|
-
@conversion_type=FileTypes.instance.conversion_type(@source_file_path,api_mime_type)
|
36
|
+
@preview_format_symb = File.extname(@destination_file_path).gsub(/^\./,'').to_sym
|
37
|
+
@conversion_type = FileTypes.instance.conversion_type(@source_file_path,api_mime_type)
|
37
38
|
end
|
38
39
|
|
39
40
|
# name of processing method in this object
|
40
41
|
# combination of: conversion type and output format (and video_conversion for video)
|
41
42
|
def processing_method_symb
|
42
|
-
name="convert_#{@conversion_type}_to_#{@preview_format_symb}"
|
43
|
+
name = "convert_#{@conversion_type}_to_#{@preview_format_symb}"
|
43
44
|
if @conversion_type.eql?(:video)
|
44
45
|
case @preview_format_symb
|
45
46
|
when :mp4
|
46
|
-
name="#{name}_using_#{@options.video_conversion}"
|
47
|
+
name = "#{name}_using_#{@options.video_conversion}"
|
47
48
|
when :png
|
48
|
-
name="#{name}_using_#{@options.video_png_conv}"
|
49
|
+
name = "#{name}_using_#{@options.video_png_conv}"
|
49
50
|
end
|
50
51
|
end
|
51
52
|
Log.log.debug("method: #{name}")
|
@@ -62,19 +63,19 @@ module Aspera
|
|
62
63
|
# create preview as specified in constructor
|
63
64
|
def generate
|
64
65
|
raise 'could not detect type of file' if @conversion_type.nil?
|
65
|
-
method_symb=processing_method_symb
|
66
|
+
method_symb = processing_method_symb
|
66
67
|
Log.log.info("#{@source_file_path}->#{@destination_file_path} (#{method_symb})")
|
67
68
|
begin
|
68
69
|
send(method_symb)
|
69
70
|
# check that generated size does not exceed maximum
|
70
|
-
result_size=File.size(@destination_file_path)
|
71
|
+
result_size = File.size(@destination_file_path)
|
71
72
|
if result_size > @options.max_size
|
72
73
|
Log.log.warn("preview size exceeds maximum #{result_size} > #{@options.max_size}")
|
73
74
|
end
|
74
75
|
rescue StandardError => e
|
75
|
-
Log.log.error("Ignoging: #{e.message
|
76
|
+
Log.log.error("Ignoging: #{e.message}")
|
76
77
|
Log.log.debug(e.backtrace.join("\n").red)
|
77
|
-
FileUtils.cp(File.expand_path(@preview_format_symb.eql?(:mp4)?'video_error.png':'image_error.png',File.dirname(__FILE__)),@destination_file_path)
|
78
|
+
FileUtils.cp(File.expand_path(@preview_format_symb.eql?(:mp4) ? 'video_error.png' : 'image_error.png',File.dirname(__FILE__)),@destination_file_path)
|
78
79
|
ensure
|
79
80
|
FileUtils.rm_rf(@temp_folder)
|
80
81
|
end
|
@@ -95,7 +96,7 @@ module Aspera
|
|
95
96
|
# @param index of part (start at 1)
|
96
97
|
def get_offset(duration, start_offset, total_count, index)
|
97
98
|
raise 'duration must be Float' unless duration.is_a?(Float)
|
98
|
-
return start_offset + ((index-1)*(duration - start_offset) / total_count)
|
99
|
+
return start_offset + ((index - 1) * (duration - start_offset) / total_count)
|
99
100
|
end
|
100
101
|
|
101
102
|
def convert_video_to_mp4_using_blend
|
@@ -105,7 +106,7 @@ module Aspera
|
|
105
106
|
last_keyframe = nil
|
106
107
|
current_index = 1
|
107
108
|
1.upto(p_keyframecount) do |i|
|
108
|
-
offset_seconds=get_offset(p_duration,p_start_offset,p_keyframecount,i)
|
109
|
+
offset_seconds = get_offset(p_duration,p_start_offset,p_keyframecount,i)
|
109
110
|
Utils.video_dump_frame(@source_file_path, offset_seconds, @options.video_scale, this_tmpdir, current_index)
|
110
111
|
Utils.video_dupe_frame(this_tmpdir, current_index, @options.blend_pauseframes)
|
111
112
|
Utils.video_blend_frames(this_tmpdir,last_keyframe, current_index) unless last_keyframe.nil?
|
@@ -115,14 +116,14 @@ module Aspera
|
|
115
116
|
current_index = last_keyframe + 1 + @options.blend_transframes
|
116
117
|
end
|
117
118
|
Utils.ffmpeg(
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
119
|
+
in_f: Utils.ffmpeg_fmt(this_tmpdir),
|
120
|
+
in_p: ['-framerate',@options.blend_fps],
|
121
|
+
out_f: @destination_file_path,
|
122
|
+
out_p: [
|
123
|
+
'-filter:v',"scale='trunc(iw/2)*2:trunc(ih/2)*2'",
|
124
|
+
'-codec:v','libx264',
|
125
|
+
'-r',30,
|
126
|
+
'-pix_fmt','yuv420p'])
|
126
127
|
end
|
127
128
|
|
128
129
|
# generate n clips starting at offset
|
@@ -131,56 +132,56 @@ module Aspera
|
|
131
132
|
filelist = File.join(this_tmpdir,'clip_files.txt')
|
132
133
|
File.open(filelist, 'w+') do |f|
|
133
134
|
1.upto(@options.clips_count.to_i) do |i|
|
134
|
-
offset_seconds=get_offset(p_duration,@options.video_start_sec.to_i,@options.clips_count.to_i,i)
|
135
|
-
tmpfilename=format('clip%04d.mp4',i)
|
135
|
+
offset_seconds = get_offset(p_duration,@options.video_start_sec.to_i,@options.clips_count.to_i,i)
|
136
|
+
tmpfilename = format('clip%04d.mp4',i)
|
136
137
|
Utils.ffmpeg(
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
138
|
+
in_f: @source_file_path,
|
139
|
+
in_p: ['-ss',0.9 * offset_seconds],
|
140
|
+
out_f: File.join(this_tmpdir,tmpfilename),
|
141
|
+
out_p: [
|
142
|
+
'-ss',0.1 * offset_seconds,
|
143
|
+
'-t',@options.clips_length,
|
144
|
+
'-filter:v',"scale=#{@options.video_scale}",
|
145
|
+
'-codec:a','libmp3lame'])
|
145
146
|
f.puts("file '#{tmpfilename}'")
|
146
147
|
end
|
147
148
|
end
|
148
149
|
# concat clips
|
149
150
|
Utils.ffmpeg(
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
151
|
+
in_f: filelist,
|
152
|
+
in_p: ['-f','concat'],
|
153
|
+
out_f: @destination_file_path,
|
154
|
+
out_p: ['-codec','copy'])
|
154
155
|
end
|
155
156
|
|
156
157
|
# do a simple reencoding
|
157
158
|
def convert_video_to_mp4_using_reencode
|
158
159
|
Utils.ffmpeg(
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
160
|
+
in_f: @source_file_path,
|
161
|
+
out_f: @destination_file_path,
|
162
|
+
out_p: [
|
163
|
+
'-t','60',
|
164
|
+
'-codec:v','libx264',
|
165
|
+
'-profile:v','high',
|
166
|
+
'-pix_fmt','yuv420p',
|
167
|
+
'-preset','slow',
|
168
|
+
'-b:v','500k',
|
169
|
+
'-maxrate','500k',
|
170
|
+
'-bufsize','1000k',
|
171
|
+
'-filter:v',"scale=#{@options.video_scale}",
|
172
|
+
'-threads','0',
|
173
|
+
'-codec:a','libmp3lame',
|
174
|
+
'-ac','2',
|
175
|
+
'-b:a','128k',
|
176
|
+
'-movflags','faststart'])
|
176
177
|
end
|
177
178
|
|
178
179
|
def convert_video_to_png_using_fixed
|
179
180
|
Utils.video_dump_frame(
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
181
|
+
@source_file_path,
|
182
|
+
Utils.video_get_duration(@source_file_path) * @options.thumb_vid_fraction,
|
183
|
+
@options.thumb_vid_scale,
|
184
|
+
@destination_file_path)
|
184
185
|
end
|
185
186
|
|
186
187
|
# https://trac.ffmpeg.org/wiki/SponsoringPrograms/GSoC/2015#AnimatedPortableNetworkGraphicsAPNG
|
@@ -189,21 +190,21 @@ module Aspera
|
|
189
190
|
# ffmpeg output.png
|
190
191
|
def convert_video_to_png_using_animated
|
191
192
|
Utils.ffmpeg(
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
193
|
+
in_f: @source_file_path,
|
194
|
+
in_p: [
|
195
|
+
'-ss',10, # seek to input position
|
196
|
+
'-t',20 # max seconds
|
197
|
+
],
|
198
|
+
out_f: @destination_file_path,
|
199
|
+
out_p: [
|
200
|
+
'-vf','fps=5,scale=120:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse',
|
201
|
+
'-loop',0,
|
202
|
+
'-f','gif'
|
203
|
+
])
|
203
204
|
end
|
204
205
|
|
205
206
|
def convert_office_to_png
|
206
|
-
tmp_pdf_file=File.join(this_tmpdir,File.basename(@source_file_path,File.extname(@source_file_path))+'.pdf')
|
207
|
+
tmp_pdf_file = File.join(this_tmpdir,File.basename(@source_file_path,File.extname(@source_file_path)) + '.pdf')
|
207
208
|
Utils.external_command(:unoconv,[
|
208
209
|
'-f','pdf',
|
209
210
|
'-o',tmp_pdf_file,
|
@@ -212,7 +213,7 @@ module Aspera
|
|
212
213
|
end
|
213
214
|
|
214
215
|
def convert_pdf_to_png(source_file_path=nil)
|
215
|
-
source_file_path
|
216
|
+
source_file_path ||= @source_file_path
|
216
217
|
Utils.external_command(:convert,[
|
217
218
|
'-size',"x#{@options.thumb_img_size}",
|
218
219
|
'-background','white',
|
@@ -236,7 +237,7 @@ module Aspera
|
|
236
237
|
# text to png
|
237
238
|
def convert_plaintext_to_png
|
238
239
|
# get 100 first lines of text file
|
239
|
-
first_lines=File.open(@source_file_path){|f|100
|
240
|
+
first_lines = File.open(@source_file_path){|f|Array.new(100){f.readline rescue ''}.join}
|
240
241
|
Utils.external_command(:convert,[
|
241
242
|
'-size',"#{@options.thumb_img_size}x#{@options.thumb_img_size}",
|
242
243
|
'xc:white', # define canvas with background color (xc, or canvas) of preceding size
|
Binary file
|
@@ -1,22 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Aspera
|
3
4
|
module Preview
|
4
5
|
# generator options. Used as parameter to preview generator object.
|
5
6
|
# also settable by command line.
|
6
7
|
class Options
|
7
8
|
# types of generation for video files
|
8
|
-
VIDEO_CONVERSION_METHODS=[
|
9
|
-
VIDEO_THUMBNAIL_METHODS=[
|
9
|
+
VIDEO_CONVERSION_METHODS = %i[reencode blend clips].freeze
|
10
|
+
VIDEO_THUMBNAIL_METHODS = %i[fixed animated].freeze
|
10
11
|
# options used in generator
|
11
12
|
# for scaling see: https://trac.ffmpeg.org/wiki/Scaling
|
12
13
|
# iw/ih : input width or height
|
13
14
|
# -x : keep aspect ratio, having value a multiple of x
|
14
15
|
DESCRIPTIONS = [
|
15
|
-
{ name: :max_size, default: 1<<24,
|
16
|
+
{ name: :max_size, default: 1 << 24, description: 'maximum size (in bytes) of preview file' },
|
16
17
|
{ name: :thumb_vid_scale, default: "-1:'min(ih,100)'", description: 'png: video: size (ffmpeg scale argument)' },
|
17
|
-
{ name: :thumb_vid_fraction, default: 0.1, description: 'png: video: position of snapshot' },
|
18
|
+
{ name: :thumb_vid_fraction, default: 0.1, description: 'png: video: time percent position of snapshot' },
|
18
19
|
{ name: :thumb_img_size, default: 800, description: 'png: non-video: height (and width)' },
|
19
|
-
{ name: :thumb_text_font, default: 'Courier', description: 'png: plaintext: font to render text with
|
20
|
+
{ name: :thumb_text_font, default: 'Courier', description: 'png: plaintext: font to render text with imagemagick convert (identify -list font)'},
|
20
21
|
{ name: :video_conversion, default: :reencode, description: 'mp4: method for preview generation', values: VIDEO_CONVERSION_METHODS },
|
21
22
|
{ name: :video_png_conv, default: :fixed, description: 'mp4: method for thumbnail generation', values: VIDEO_THUMBNAIL_METHODS },
|
22
23
|
{ name: :video_start_sec, default: 10, description: 'mp4: start offset (seconds) of video preview' },
|
@@ -27,7 +28,7 @@ module Aspera
|
|
27
28
|
{ name: :blend_fps, default: 15, description: 'mp4: blend: frame per second' },
|
28
29
|
{ name: :clips_count, default: 5, description: 'mp4: clips: number of clips' },
|
29
30
|
{ name: :clips_length, default: 5, description: 'mp4: clips: length in seconds of each clips' }
|
30
|
-
]
|
31
|
+
].freeze
|
31
32
|
# add accessors
|
32
33
|
DESCRIPTIONS.each do |opt|
|
33
34
|
attr_accessor opt[:name]
|
data/lib/aspera/preview/utils.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'English'
|
3
4
|
require 'tmpdir'
|
4
5
|
require 'fileutils'
|
@@ -9,26 +10,27 @@ module Aspera
|
|
9
10
|
module Preview
|
10
11
|
class Utils
|
11
12
|
# from bash manual: meta-character need to be escaped
|
12
|
-
BASH_SPECIAL_CHARACTERS="|&;()<> \t#\n"
|
13
|
+
BASH_SPECIAL_CHARACTERS = "|&;()<> \t#\n"
|
13
14
|
# shell exit code when command is not found
|
14
|
-
BASH_EXIT_NOT_FOUND=127
|
15
|
+
BASH_EXIT_NOT_FOUND = 127
|
15
16
|
# external binaries used
|
16
|
-
EXPERNAL_TOOLS=[
|
17
|
-
TMPFMT='img%04d.jpg'
|
17
|
+
EXPERNAL_TOOLS = %i[ffmpeg ffprobe convert composite optipng unoconv].freeze
|
18
|
+
TMPFMT = 'img%04d.jpg'
|
18
19
|
private_constant :BASH_SPECIAL_CHARACTERS,:BASH_EXIT_NOT_FOUND,:EXPERNAL_TOOLS,:TMPFMT
|
19
20
|
|
20
|
-
class<<self
|
21
|
+
class << self
|
21
22
|
# returns string with single quotes suitable for bash if there is any bash metacharacter
|
22
23
|
def shell_quote(argument)
|
23
24
|
return argument unless argument.chars.any?{|c|BASH_SPECIAL_CHARACTERS.include?(c)}
|
24
|
-
return "'"+argument.gsub(/'/){|_s| "'\"'\"'"}+"'"
|
25
|
+
return "'" + argument.gsub(/'/){|_s| "'\"'\"'"} + "'"
|
25
26
|
end
|
26
27
|
|
27
28
|
# check that external tools can be executed
|
28
29
|
def check_tools(skip_types=[])
|
29
|
-
EXPERNAL_TOOLS.
|
30
|
+
tools_to_check=EXPERNAL_TOOLS.dup
|
31
|
+
tools_to_check.delete(:unoconv) if skip_types.include?(:office)
|
30
32
|
# Check for binaries
|
31
|
-
|
33
|
+
tools_to_check.each do |command_symb|
|
32
34
|
external_command(command_symb,['-h'])
|
33
35
|
end
|
34
36
|
end
|
@@ -39,15 +41,15 @@ module Aspera
|
|
39
41
|
def external_command(command_symb,command_args)
|
40
42
|
raise "unexpected command #{command_symb}" unless EXPERNAL_TOOLS.include?(command_symb)
|
41
43
|
# build command line, and quote special characters
|
42
|
-
command=command_args.clone.unshift(command_symb).map{|i| shell_quote(i.to_s)}.join(' ')
|
44
|
+
command = command_args.clone.unshift(command_symb).map{|i| shell_quote(i.to_s)}.join(' ')
|
43
45
|
Log.log.debug("cmd=#{command}".blue)
|
44
46
|
# capture3: only in ruby2+
|
45
|
-
if Open3.respond_to?(
|
47
|
+
if Open3.respond_to?(:capture3)
|
46
48
|
stdout, stderr, exit_status = Open3.capture3(command)
|
47
49
|
else
|
48
|
-
stderr='<merged with stdout>'
|
49
|
-
stdout
|
50
|
-
exit_status
|
50
|
+
stderr = '<merged with stdout>'
|
51
|
+
stdout = %x(#{command} 2>&1)
|
52
|
+
exit_status = $CHILD_STATUS
|
51
53
|
end
|
52
54
|
if BASH_EXIT_NOT_FOUND.eql?(exit_status)
|
53
55
|
raise "Error: #{command_symb} is not in the PATH"
|
@@ -65,19 +67,19 @@ module Aspera
|
|
65
67
|
def ffmpeg(a)
|
66
68
|
raise 'error: hash expected' unless a.is_a?(Hash)
|
67
69
|
#input_file,input_args,output_file,output_args
|
68
|
-
a[:gl_p]||=[
|
70
|
+
a[:gl_p] ||= [
|
69
71
|
'-y', # overwrite output without asking
|
70
72
|
'-loglevel','error' # show only errors and up]
|
71
73
|
]
|
72
|
-
a[:in_p]||=[]
|
73
|
-
a[:out_p]||=[]
|
74
|
-
raise "wrong params (#{a.keys.sort})" unless [
|
74
|
+
a[:in_p] ||= []
|
75
|
+
a[:out_p] ||= []
|
76
|
+
raise "wrong params (#{a.keys.sort})" unless %i[gl_p in_f in_p out_f out_p].eql?(a.keys.sort)
|
75
77
|
external_command(:ffmpeg,[a[:gl_p],a[:in_p],'-i',a[:in_f],a[:out_p],a[:out_f]].flatten)
|
76
78
|
end
|
77
79
|
|
78
80
|
# @return Float in seconds
|
79
81
|
def video_get_duration(input_file)
|
80
|
-
result=external_command(:ffprobe,[
|
82
|
+
result = external_command(:ffprobe,[
|
81
83
|
'-loglevel','error',
|
82
84
|
'-show_entries','format=duration',
|
83
85
|
'-print_format','default=noprint_wrappers=1:nokey=1',
|
@@ -94,16 +96,16 @@ module Aspera
|
|
94
96
|
end
|
95
97
|
|
96
98
|
def video_dupe_frame(temp_folder, index, count)
|
97
|
-
input_file=get_tmp_num_filepath(temp_folder,index)
|
99
|
+
input_file = get_tmp_num_filepath(temp_folder,index)
|
98
100
|
1.upto(count) do |i|
|
99
|
-
FileUtils.ln_s(input_file,get_tmp_num_filepath(temp_folder,index+i))
|
101
|
+
FileUtils.ln_s(input_file,get_tmp_num_filepath(temp_folder,index + i))
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
103
105
|
def video_blend_frames(temp_folder, index1, index2)
|
104
|
-
img1=get_tmp_num_filepath(temp_folder,index1)
|
105
|
-
img2=get_tmp_num_filepath(temp_folder,index2)
|
106
|
-
count=index2-index1-1
|
106
|
+
img1 = get_tmp_num_filepath(temp_folder,index1)
|
107
|
+
img2 = get_tmp_num_filepath(temp_folder,index2)
|
108
|
+
count = index2 - index1 - 1
|
107
109
|
1.upto(count) do |i|
|
108
110
|
percent = 100 * i / (count + 1)
|
109
111
|
filename = get_tmp_num_filepath(temp_folder, index1 + i)
|
@@ -112,19 +114,14 @@ module Aspera
|
|
112
114
|
end
|
113
115
|
|
114
116
|
def video_dump_frame(input_file, offset_seconds, scale, output_file, index=nil)
|
115
|
-
output_file=get_tmp_num_filepath(output_file,index) unless index.nil?
|
117
|
+
output_file = get_tmp_num_filepath(output_file,index) unless index.nil?
|
116
118
|
ffmpeg(
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
119
|
+
in_f: input_file,
|
120
|
+
in_p: ['-ss',offset_seconds],
|
121
|
+
out_f: output_file,
|
122
|
+
out_p: ['-frames:v',1,'-filter:v',"scale=#{scale}"])
|
121
123
|
return output_file
|
122
124
|
end
|
123
|
-
|
124
|
-
def unused_message_to_png(_message)
|
125
|
-
# convert -size 400x -background '#666666' -fill '#ffffff' -interword-spacing 10 -kerning 4 -pointsize 10 -gravity West -size x22 label:"Lorem dolor sit amet" -flatten xxx.png
|
126
|
-
external_command(:convert,[])
|
127
|
-
end
|
128
125
|
end
|
129
126
|
end # Options
|
130
127
|
end # Preview
|
Binary file
|
@@ -1,14 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'uri'
|
3
4
|
require 'resolv'
|
4
5
|
|
5
6
|
module URI
|
6
7
|
class Generic
|
7
8
|
# save original method that finds proxy in URI::Generic, it uses env var http_proxy
|
8
|
-
|
9
|
-
def self.register_proxy_finder
|
10
|
-
|
11
|
-
|
9
|
+
alias_method :find_proxy_orig, :find_proxy
|
10
|
+
def self.register_proxy_finder
|
11
|
+
raise 'mandatory block missing' unless Kernel.block_given?
|
12
|
+
# overload the method in URI : call user's provided block and fallback to original method
|
13
|
+
define_method(:find_proxy) {|envars=ENV| yield(to_s) || find_proxy_orig(envars)}
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -18,8 +20,8 @@ module Aspera
|
|
18
20
|
class ProxyAutoConfig
|
19
21
|
# template file is read once, it contains functions that can be used in a proxy autoconf script
|
20
22
|
# it is similar to mozilla ascii_pac_utils.inc
|
21
|
-
PAC_FUNCTIONS_FILE=__FILE__.gsub(/\.rb$/,'.js').freeze
|
22
|
-
PAC_MAIN_FUNCTION='FindProxyForURL'
|
23
|
+
PAC_FUNCTIONS_FILE = __FILE__.gsub(/\.rb$/,'.js').freeze
|
24
|
+
PAC_MAIN_FUNCTION = 'FindProxyForURL'
|
23
25
|
private_constant :PAC_FUNCTIONS_FILE,:PAC_MAIN_FUNCTION
|
24
26
|
|
25
27
|
private
|
@@ -28,12 +30,12 @@ module Aspera
|
|
28
30
|
# I did not find an easy way for the javascript to callback ruby
|
29
31
|
# and anyway, it only needs to get DNS translation
|
30
32
|
def pac_dns_functions(context_host)
|
31
|
-
context_self='127.0.0.1'
|
32
|
-
context_ip=nil
|
33
|
-
Resolv::DNS.open{|dns|dns.each_address(context_host){|r_addr|context_ip=r_addr.to_s if r_addr.is_a?(Resolv::IPv4)}}
|
33
|
+
context_self = '127.0.0.1'
|
34
|
+
context_ip = nil
|
35
|
+
Resolv::DNS.open{|dns|dns.each_address(context_host){|r_addr|context_ip = r_addr.to_s if r_addr.is_a?(Resolv::IPv4)}}
|
34
36
|
raise "DNS name not found: #{context_host}" if context_ip.nil?
|
35
37
|
# NOTE: Javascript code here with string inclusions
|
36
|
-
javascript
|
38
|
+
javascript = <<END_OF_JAVASCRIPT
|
37
39
|
function dnsResolve(host) {
|
38
40
|
if (host == '#{context_host}' || host == '#{context_ip}')
|
39
41
|
return '#{context_ip}';
|
@@ -51,10 +53,10 @@ END_OF_JAVASCRIPT
|
|
51
53
|
# @param proxy_auto_config the proxy auto config script to be evaluated
|
52
54
|
def initialize(proxy_auto_config)
|
53
55
|
# user provided javascript with FindProxyForURL function
|
54
|
-
@proxy_auto_config=proxy_auto_config
|
56
|
+
@proxy_auto_config = proxy_auto_config
|
55
57
|
# avoid multiple execution, this does not support load balancing
|
56
|
-
@cache={}
|
57
|
-
@pac_functions=nil
|
58
|
+
@cache = {}
|
59
|
+
@pac_functions = nil
|
58
60
|
end
|
59
61
|
|
60
62
|
def register_uri_generic
|
@@ -66,18 +68,18 @@ END_OF_JAVASCRIPT
|
|
66
68
|
# execute proxy auto config script for the given URL : https://en.wikipedia.org/wiki/Proxy_auto-config
|
67
69
|
# @return either nil, or a String formated following PAC standard
|
68
70
|
def find_proxy_for_url(service_url)
|
69
|
-
uri=URI.parse(service_url)
|
70
|
-
simple_url="#{uri.scheme}://#{uri.host}"
|
71
|
+
uri = URI.parse(service_url)
|
72
|
+
simple_url = "#{uri.scheme}://#{uri.host}"
|
71
73
|
if !@cache.has_key?(simple_url)
|
72
74
|
Log.log.debug("PAC: starting javascript for #{service_url}")
|
73
75
|
# require at runtime, in case there is no js engine
|
74
76
|
require 'execjs'
|
75
77
|
# read template lib
|
76
|
-
@pac_functions=File.read(PAC_FUNCTIONS_FILE).freeze if @pac_functions.nil?
|
78
|
+
@pac_functions = File.read(PAC_FUNCTIONS_FILE).freeze if @pac_functions.nil?
|
77
79
|
# to be executed is dns + utils + user function
|
78
|
-
js_to_execute="#{pac_dns_functions(uri.host)}#{@pac_functions}#{@proxy_auto_config}"
|
80
|
+
js_to_execute = "#{pac_dns_functions(uri.host)}#{@pac_functions}#{@proxy_auto_config}"
|
79
81
|
executable_js = ExecJS.compile(js_to_execute)
|
80
|
-
@cache[simple_url]=executable_js.call(PAC_MAIN_FUNCTION, simple_url, uri.host)
|
82
|
+
@cache[simple_url] = executable_js.call(PAC_MAIN_FUNCTION, simple_url, uri.host)
|
81
83
|
Log.log.debug("PAC: result: #{@cache[simple_url]}")
|
82
84
|
end
|
83
85
|
return @cache[simple_url]
|
@@ -87,9 +89,9 @@ END_OF_JAVASCRIPT
|
|
87
89
|
# @return Array of URI, possibly empty
|
88
90
|
def get_proxies(service_url)
|
89
91
|
# prepare result
|
90
|
-
uri_list=[]
|
92
|
+
uri_list = []
|
91
93
|
# execute PAC script
|
92
|
-
proxy_list_str=find_proxy_for_url(service_url)
|
94
|
+
proxy_list_str = find_proxy_for_url(service_url)
|
93
95
|
if !proxy_list_str.is_a?(String)
|
94
96
|
Log.log.warn("PAC: did not return a String, returned #{proxy_list_str.class}")
|
95
97
|
return uri_list
|
@@ -98,16 +100,16 @@ END_OF_JAVASCRIPT
|
|
98
100
|
proxy_list_str.gsub!(/\s+/,' ')
|
99
101
|
proxy_list_str.split(';').each do |item|
|
100
102
|
# strip and split by space
|
101
|
-
parts=item.strip.split
|
103
|
+
parts = item.strip.split
|
102
104
|
case parts.shift
|
103
105
|
when 'DIRECT'
|
104
106
|
raise 'DIRECT has no param' unless parts.empty?
|
105
107
|
when 'PROXY'
|
106
|
-
addr_port=parts.shift
|
108
|
+
addr_port = parts.shift
|
107
109
|
raise 'PROXY shall have one param' unless addr_port.is_a?(String) && parts.empty?
|
108
110
|
begin
|
109
111
|
# PAC proxy addresses are <host>:<port>
|
110
|
-
if
|
112
|
+
if /:[0-9]+$/.match?(addr_port)
|
111
113
|
# we want to return URIs, so add dummy scheme
|
112
114
|
uri_list.push(URI.parse("proxy://#{addr_port}"))
|
113
115
|
else
|