aspera-cli 4.4.0 → 4.7.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
- data/README.md +2095 -1503
- data/bin/ascli +2 -1
- data/bin/asession +4 -5
- data/docs/test_env.conf +3 -0
- data/examples/aoc.rb +4 -3
- data/examples/faspex4.rb +25 -25
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +17 -17
- data/lib/aspera/aoc.rb +238 -185
- data/lib/aspera/ascmd.rb +93 -83
- data/lib/aspera/ats_api.rb +11 -10
- data/lib/aspera/cli/basic_auth_plugin.rb +13 -14
- data/lib/aspera/cli/extended_value.rb +42 -33
- data/lib/aspera/cli/formater.rb +142 -108
- data/lib/aspera/cli/info.rb +17 -0
- data/lib/aspera/cli/listener/line_dump.rb +3 -2
- data/lib/aspera/cli/listener/logger.rb +2 -1
- data/lib/aspera/cli/listener/progress.rb +16 -18
- data/lib/aspera/cli/listener/progress_multi.rb +18 -21
- data/lib/aspera/cli/main.rb +173 -149
- data/lib/aspera/cli/manager.rb +163 -168
- data/lib/aspera/cli/plugin.rb +43 -31
- data/lib/aspera/cli/plugins/alee.rb +6 -6
- data/lib/aspera/cli/plugins/aoc.rb +405 -370
- data/lib/aspera/cli/plugins/ats.rb +86 -79
- data/lib/aspera/cli/plugins/bss.rb +14 -16
- data/lib/aspera/cli/plugins/config.rb +580 -362
- data/lib/aspera/cli/plugins/console.rb +23 -19
- data/lib/aspera/cli/plugins/cos.rb +18 -18
- data/lib/aspera/cli/plugins/faspex.rb +201 -158
- data/lib/aspera/cli/plugins/faspex5.rb +80 -57
- data/lib/aspera/cli/plugins/node.rb +183 -166
- data/lib/aspera/cli/plugins/orchestrator.rb +71 -67
- data/lib/aspera/cli/plugins/preview.rb +92 -96
- data/lib/aspera/cli/plugins/server.rb +79 -75
- data/lib/aspera/cli/plugins/shares.rb +35 -19
- data/lib/aspera/cli/plugins/sync.rb +20 -22
- data/lib/aspera/cli/transfer_agent.rb +76 -113
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/colors.rb +35 -27
- data/lib/aspera/command_line_builder.rb +48 -34
- data/lib/aspera/cos_node.rb +29 -21
- data/lib/aspera/data_repository.rb +3 -2
- data/lib/aspera/environment.rb +50 -45
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +28 -25
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +52 -43
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +58 -72
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +37 -43
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +35 -16
- data/lib/aspera/fasp/agent_trsdk.rb +104 -0
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +68 -52
- data/lib/aspera/fasp/installation.rb +152 -124
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +87 -92
- data/lib/aspera/fasp/parameters.yaml +305 -249
- data/lib/aspera/fasp/resume_policy.rb +11 -14
- data/lib/aspera/fasp/transfer_spec.rb +26 -0
- data/lib/aspera/fasp/uri.rb +22 -21
- data/lib/aspera/faspex_gw.rb +55 -89
- data/lib/aspera/hash_ext.rb +4 -3
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +121 -0
- data/lib/aspera/keychain/macos_security.rb +90 -0
- data/lib/aspera/log.rb +55 -37
- data/lib/aspera/nagios.rb +13 -12
- data/lib/aspera/node.rb +30 -25
- data/lib/aspera/oauth.rb +175 -226
- data/lib/aspera/open_application.rb +4 -3
- data/lib/aspera/persistency_action_once.rb +6 -6
- data/lib/aspera/persistency_folder.rb +5 -9
- data/lib/aspera/preview/file_types.rb +6 -5
- data/lib/aspera/preview/generator.rb +25 -24
- data/lib/aspera/preview/options.rb +16 -14
- data/lib/aspera/preview/utils.rb +98 -98
- data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
- data/lib/aspera/proxy_auto_config.rb +111 -20
- data/lib/aspera/rest.rb +154 -135
- data/lib/aspera/rest_call_error.rb +2 -2
- data/lib/aspera/rest_error_analyzer.rb +23 -25
- data/lib/aspera/rest_errors_aspera.rb +15 -14
- data/lib/aspera/ssh.rb +12 -10
- data/lib/aspera/sync.rb +42 -41
- data/lib/aspera/temp_file_manager.rb +18 -14
- data/lib/aspera/timer_limiter.rb +2 -1
- data/lib/aspera/uri_reader.rb +7 -5
- data/lib/aspera/web_auth.rb +79 -76
- metadata +116 -29
- data/docs/Makefile +0 -66
- data/docs/README.erb.md +0 -3973
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/secrets.rb +0 -20
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'open3'
|
|
2
3
|
require 'aspera/preview/options'
|
|
3
4
|
require 'aspera/preview/utils'
|
|
@@ -60,18 +61,18 @@ module Aspera
|
|
|
60
61
|
|
|
61
62
|
# create preview as specified in constructor
|
|
62
63
|
def generate
|
|
63
|
-
raise
|
|
64
|
+
raise 'could not detect type of file' if @conversion_type.nil?
|
|
64
65
|
method_symb=processing_method_symb
|
|
65
66
|
Log.log.info("#{@source_file_path}->#{@destination_file_path} (#{method_symb})")
|
|
66
67
|
begin
|
|
67
|
-
|
|
68
|
+
send(method_symb)
|
|
68
69
|
# check that generated size does not exceed maximum
|
|
69
70
|
result_size=File.size(@destination_file_path)
|
|
70
71
|
if result_size > @options.max_size
|
|
71
72
|
Log.log.warn("preview size exceeds maximum #{result_size} > #{@options.max_size}")
|
|
72
73
|
end
|
|
73
|
-
rescue => e
|
|
74
|
-
Log.log.error("#{e.message}")
|
|
74
|
+
rescue StandardError => e
|
|
75
|
+
Log.log.error("Ignoging: #{e.message.to_s}")
|
|
75
76
|
Log.log.debug(e.backtrace.join("\n").red)
|
|
76
77
|
FileUtils.cp(File.expand_path(@preview_format_symb.eql?(:mp4)?'video_error.png':'image_error.png',File.dirname(__FILE__)),@destination_file_path)
|
|
77
78
|
ensure
|
|
@@ -93,10 +94,11 @@ module Aspera
|
|
|
93
94
|
# @param total_count of parts
|
|
94
95
|
# @param index of part (start at 1)
|
|
95
96
|
def get_offset(duration, start_offset, total_count, index)
|
|
96
|
-
|
|
97
|
+
raise 'duration must be Float' unless duration.is_a?(Float)
|
|
98
|
+
return start_offset + ((index-1)*(duration - start_offset) / total_count)
|
|
97
99
|
end
|
|
98
100
|
|
|
99
|
-
def convert_video_to_mp4_using_blend
|
|
101
|
+
def convert_video_to_mp4_using_blend
|
|
100
102
|
p_duration = Utils.video_get_duration(@source_file_path)
|
|
101
103
|
p_start_offset = @options.video_start_sec.to_i
|
|
102
104
|
p_keyframecount = @options.blend_keyframes.to_i
|
|
@@ -124,13 +126,13 @@ module Aspera
|
|
|
124
126
|
end
|
|
125
127
|
|
|
126
128
|
# generate n clips starting at offset
|
|
127
|
-
def convert_video_to_mp4_using_clips
|
|
129
|
+
def convert_video_to_mp4_using_clips
|
|
128
130
|
p_duration = Utils.video_get_duration(@source_file_path)
|
|
129
131
|
filelist = File.join(this_tmpdir,'clip_files.txt')
|
|
130
132
|
File.open(filelist, 'w+') do |f|
|
|
131
133
|
1.upto(@options.clips_count.to_i) do |i|
|
|
132
134
|
offset_seconds=get_offset(p_duration,@options.video_start_sec.to_i,@options.clips_count.to_i,i)
|
|
133
|
-
tmpfilename=
|
|
135
|
+
tmpfilename=format('clip%04d.mp4',i)
|
|
134
136
|
Utils.ffmpeg(
|
|
135
137
|
in_f: @source_file_path,
|
|
136
138
|
in_p: ['-ss',0.9*offset_seconds],
|
|
@@ -152,7 +154,7 @@ module Aspera
|
|
|
152
154
|
end
|
|
153
155
|
|
|
154
156
|
# do a simple reencoding
|
|
155
|
-
def convert_video_to_mp4_using_reencode
|
|
157
|
+
def convert_video_to_mp4_using_reencode
|
|
156
158
|
Utils.ffmpeg(
|
|
157
159
|
in_f: @source_file_path,
|
|
158
160
|
out_f: @destination_file_path,
|
|
@@ -173,7 +175,7 @@ module Aspera
|
|
|
173
175
|
'-movflags','faststart'])
|
|
174
176
|
end
|
|
175
177
|
|
|
176
|
-
def convert_video_to_png_using_fixed
|
|
178
|
+
def convert_video_to_png_using_fixed
|
|
177
179
|
Utils.video_dump_frame(
|
|
178
180
|
@source_file_path,
|
|
179
181
|
Utils.video_get_duration(@source_file_path)*@options.thumb_vid_fraction,
|
|
@@ -185,12 +187,12 @@ module Aspera
|
|
|
185
187
|
# ffmpeg -h muxer=apng
|
|
186
188
|
# thumb is 32x32
|
|
187
189
|
# ffmpeg output.png
|
|
188
|
-
def convert_video_to_png_using_animated
|
|
190
|
+
def convert_video_to_png_using_animated
|
|
189
191
|
Utils.ffmpeg(
|
|
190
192
|
in_f: @source_file_path,
|
|
191
193
|
in_p: [
|
|
192
194
|
'-ss',10, # seek to input position
|
|
193
|
-
'-t',20
|
|
195
|
+
'-t',20 # max seconds
|
|
194
196
|
],
|
|
195
197
|
out_f: @destination_file_path,
|
|
196
198
|
out_p: [
|
|
@@ -200,7 +202,7 @@ module Aspera
|
|
|
200
202
|
])
|
|
201
203
|
end
|
|
202
204
|
|
|
203
|
-
def convert_office_to_png
|
|
205
|
+
def convert_office_to_png
|
|
204
206
|
tmp_pdf_file=File.join(this_tmpdir,File.basename(@source_file_path,File.extname(@source_file_path))+'.pdf')
|
|
205
207
|
Utils.external_command(:unoconv,[
|
|
206
208
|
'-f','pdf',
|
|
@@ -219,7 +221,7 @@ module Aspera
|
|
|
219
221
|
@destination_file_path])
|
|
220
222
|
end
|
|
221
223
|
|
|
222
|
-
def convert_image_to_png
|
|
224
|
+
def convert_image_to_png
|
|
223
225
|
Utils.external_command(:convert,[
|
|
224
226
|
'-auto-orient',
|
|
225
227
|
'-thumbnail',"#{@options.thumb_img_size}x#{@options.thumb_img_size}>",
|
|
@@ -232,23 +234,22 @@ module Aspera
|
|
|
232
234
|
end
|
|
233
235
|
|
|
234
236
|
# text to png
|
|
235
|
-
def convert_plaintext_to_png
|
|
237
|
+
def convert_plaintext_to_png
|
|
236
238
|
# get 100 first lines of text file
|
|
237
|
-
first_lines=File.open(@source_file_path){|f|100.times.map{f.readline rescue ''}
|
|
239
|
+
first_lines=File.open(@source_file_path){|f|100.times.map{f.readline rescue ''}.join}
|
|
238
240
|
Utils.external_command(:convert,[
|
|
239
241
|
'-size',"#{@options.thumb_img_size}x#{@options.thumb_img_size}",
|
|
240
|
-
'xc:white',
|
|
241
|
-
'-font',
|
|
242
|
+
'xc:white', # define canvas with background color (xc, or canvas) of preceding size
|
|
243
|
+
'-font',@options.thumb_text_font,
|
|
242
244
|
'-pointsize',12,
|
|
243
|
-
'-fill','black',
|
|
244
|
-
'-annotate','+
|
|
245
|
-
'-trim',
|
|
246
|
-
'-bordercolor','
|
|
247
|
-
'-border',
|
|
245
|
+
'-fill','black', # font color
|
|
246
|
+
'-annotate','+0+0',first_lines,
|
|
247
|
+
'-trim', # avoid large blank regions
|
|
248
|
+
'-bordercolor','white',
|
|
249
|
+
'-border',8,
|
|
248
250
|
'+repage',
|
|
249
251
|
@destination_file_path])
|
|
250
252
|
end
|
|
251
|
-
|
|
252
253
|
end # Generator
|
|
253
254
|
end # Preview
|
|
254
255
|
end # Aspera
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Aspera
|
|
2
3
|
module Preview
|
|
3
4
|
# generator options. Used as parameter to preview generator object.
|
|
@@ -11,20 +12,21 @@ module Aspera
|
|
|
11
12
|
# iw/ih : input width or height
|
|
12
13
|
# -x : keep aspect ratio, having value a multiple of x
|
|
13
14
|
DESCRIPTIONS = [
|
|
14
|
-
{ name: :max_size, default: 1<<24, description:
|
|
15
|
-
{ name: :thumb_vid_scale, default: "-1:'min(ih,100)'", description:
|
|
16
|
-
{ name: :thumb_vid_fraction, default: 0.1, description:
|
|
17
|
-
{ name: :thumb_img_size, default: 800, description:
|
|
18
|
-
{ name: :
|
|
19
|
-
{ name: :
|
|
20
|
-
{ name: :
|
|
21
|
-
{ name: :
|
|
22
|
-
{ name: :
|
|
23
|
-
{ name: :
|
|
24
|
-
{ name: :
|
|
25
|
-
{ name: :
|
|
26
|
-
{ name: :
|
|
27
|
-
{ name: :
|
|
15
|
+
{ name: :max_size, default: 1<<24, description: 'maximum size (in bytes) of preview file' },
|
|
16
|
+
{ 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_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 image magick convert, list with: identify -list font' },
|
|
20
|
+
{ name: :video_conversion, default: :reencode, description: 'mp4: method for preview generation', values: VIDEO_CONVERSION_METHODS },
|
|
21
|
+
{ name: :video_png_conv, default: :fixed, description: 'mp4: method for thumbnail generation', values: VIDEO_THUMBNAIL_METHODS },
|
|
22
|
+
{ name: :video_start_sec, default: 10, description: 'mp4: start offset (seconds) of video preview' },
|
|
23
|
+
{ name: :video_scale, default: "'min(iw,360)':-2", description: 'mp4: video scale (ffmpeg)' },
|
|
24
|
+
{ name: :blend_keyframes, default: 30, description: 'mp4: blend: # key frames' },
|
|
25
|
+
{ name: :blend_pauseframes, default: 3, description: 'mp4: blend: # pause frames' },
|
|
26
|
+
{ name: :blend_transframes, default: 5, description: 'mp4: blend: # transition blend frames' },
|
|
27
|
+
{ name: :blend_fps, default: 15, description: 'mp4: blend: frame per second' },
|
|
28
|
+
{ name: :clips_count, default: 5, description: 'mp4: clips: number of clips' },
|
|
29
|
+
{ name: :clips_length, default: 5, description: 'mp4: clips: length in seconds of each clips' }
|
|
28
30
|
]
|
|
29
31
|
# add accessors
|
|
30
32
|
DESCRIPTIONS.each do |opt|
|
data/lib/aspera/preview/utils.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'English'
|
|
1
3
|
require 'tmpdir'
|
|
2
4
|
require 'fileutils'
|
|
3
5
|
require 'aspera/log'
|
|
@@ -12,119 +14,117 @@ module Aspera
|
|
|
12
14
|
BASH_EXIT_NOT_FOUND=127
|
|
13
15
|
# external binaries used
|
|
14
16
|
EXPERNAL_TOOLS=[:ffmpeg,:ffprobe,:convert,:composite,:optipng,:unoconv]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# returns string with single quotes suitable for bash if there is any bash metacharacter
|
|
18
|
-
def self.shell_quote(argument)
|
|
19
|
-
return argument unless argument.split('').any?{|c|BASH_SPECIAL_CHARACTERS.include?(c)}
|
|
20
|
-
return "'"+argument.gsub(/'/){|s| "'\"'\"'"}+"'"
|
|
21
|
-
end
|
|
17
|
+
TMPFMT='img%04d.jpg'
|
|
18
|
+
private_constant :BASH_SPECIAL_CHARACTERS,:BASH_EXIT_NOT_FOUND,:EXPERNAL_TOOLS,:TMPFMT
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
`#{bin} -h 2>&1`
|
|
29
|
-
raise "Error: #{bin} is not in the PATH" if $?.exitstatus.eql?(BASH_EXIT_NOT_FOUND)
|
|
20
|
+
class<<self
|
|
21
|
+
# returns string with single quotes suitable for bash if there is any bash metacharacter
|
|
22
|
+
def shell_quote(argument)
|
|
23
|
+
return argument unless argument.chars.any?{|c|BASH_SPECIAL_CHARACTERS.include?(c)}
|
|
24
|
+
return "'"+argument.gsub(/'/){|_s| "'\"'\"'"}+"'"
|
|
30
25
|
end
|
|
31
|
-
end
|
|
32
26
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Log.log.debug("cmd=#{command}".blue)
|
|
41
|
-
# capture3: only in ruby2+
|
|
42
|
-
if Open3.respond_to?('capture3') then
|
|
43
|
-
stdout, stderr, exit_status = Open3.capture3(command)
|
|
44
|
-
else
|
|
45
|
-
stderr='<merged with stdout>'
|
|
46
|
-
stdout=%x[#{command} 2>&1]
|
|
47
|
-
exit_status=$?
|
|
48
|
-
end
|
|
49
|
-
if BASH_EXIT_NOT_FOUND.eql?(exit_status)
|
|
50
|
-
raise "Error: #{bin} is not in the PATH"
|
|
51
|
-
end
|
|
52
|
-
unless exit_status.success?
|
|
53
|
-
Log.log.error("commandline: #{command}")
|
|
54
|
-
Log.log.error("Error code: #{exit_status}")
|
|
55
|
-
Log.log.error("stdout: #{stdout}")
|
|
56
|
-
Log.log.error("stderr: #{stderr}")
|
|
57
|
-
raise "command returned error"
|
|
27
|
+
# check that external tools can be executed
|
|
28
|
+
def check_tools(skip_types=[])
|
|
29
|
+
EXPERNAL_TOOLS.delete(:unoconv) if skip_types.include?(:office)
|
|
30
|
+
# Check for binaries
|
|
31
|
+
EXPERNAL_TOOLS.each do |command_symb|
|
|
32
|
+
external_command(command_symb,['-h'])
|
|
33
|
+
end
|
|
58
34
|
end
|
|
59
|
-
stdout_return.replace(stdout) unless stdout_return.nil?
|
|
60
|
-
return exit_status.success?
|
|
61
|
-
end
|
|
62
35
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
36
|
+
# execute external command
|
|
37
|
+
# one could use "system", but we would need to redirect stdout/err
|
|
38
|
+
# @return true if su
|
|
39
|
+
def external_command(command_symb,command_args)
|
|
40
|
+
raise "unexpected command #{command_symb}" unless EXPERNAL_TOOLS.include?(command_symb)
|
|
41
|
+
# build command line, and quote special characters
|
|
42
|
+
command=command_args.clone.unshift(command_symb).map{|i| shell_quote(i.to_s)}.join(' ')
|
|
43
|
+
Log.log.debug("cmd=#{command}".blue)
|
|
44
|
+
# capture3: only in ruby2+
|
|
45
|
+
if Open3.respond_to?('capture3')
|
|
46
|
+
stdout, stderr, exit_status = Open3.capture3(command)
|
|
47
|
+
else
|
|
48
|
+
stderr='<merged with stdout>'
|
|
49
|
+
stdout=%x(#{command} 2>&1)
|
|
50
|
+
exit_status=$CHILD_STATUS
|
|
51
|
+
end
|
|
52
|
+
if BASH_EXIT_NOT_FOUND.eql?(exit_status)
|
|
53
|
+
raise "Error: #{command_symb} is not in the PATH"
|
|
54
|
+
end
|
|
55
|
+
unless exit_status.success?
|
|
56
|
+
Log.log.error("commandline: #{command}")
|
|
57
|
+
Log.log.error("Error code: #{exit_status}")
|
|
58
|
+
Log.log.error("stdout: #{stdout}")
|
|
59
|
+
Log.log.error("stderr: #{stderr}")
|
|
60
|
+
raise "#{command_symb} error #{exit_status}"
|
|
61
|
+
end
|
|
62
|
+
return {status: exit_status, stdout: stdout}
|
|
63
|
+
end
|
|
75
64
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
65
|
+
def ffmpeg(a)
|
|
66
|
+
raise 'error: hash expected' unless a.is_a?(Hash)
|
|
67
|
+
#input_file,input_args,output_file,output_args
|
|
68
|
+
a[:gl_p]||=[
|
|
69
|
+
'-y', # overwrite output without asking
|
|
70
|
+
'-loglevel','error' # show only errors and up]
|
|
71
|
+
]
|
|
72
|
+
a[:in_p]||=[]
|
|
73
|
+
a[:out_p]||=[]
|
|
74
|
+
raise "wrong params (#{a.keys.sort})" unless [:gl_p, :in_f, :in_p, :out_f, :out_p].eql?(a.keys.sort)
|
|
75
|
+
external_command(:ffmpeg,[a[:gl_p],a[:in_p],'-i',a[:in_f],a[:out_p],a[:out_f]].flatten)
|
|
76
|
+
end
|
|
85
77
|
|
|
86
|
-
|
|
78
|
+
# @return Float in seconds
|
|
79
|
+
def video_get_duration(input_file)
|
|
80
|
+
result=external_command(:ffprobe,[
|
|
81
|
+
'-loglevel','error',
|
|
82
|
+
'-show_entries','format=duration',
|
|
83
|
+
'-print_format','default=noprint_wrappers=1:nokey=1',
|
|
84
|
+
input_file])
|
|
85
|
+
return result[:stdout].to_f
|
|
86
|
+
end
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
def ffmpeg_fmt(temp_folder)
|
|
89
|
+
return File.join(temp_folder,TMPFMT)
|
|
90
|
+
end
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
def get_tmp_num_filepath(temp_folder, file_number)
|
|
93
|
+
return File.join(temp_folder,format(TMPFMT,file_number))
|
|
94
|
+
end
|
|
95
95
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
def video_dupe_frame(temp_folder, index, count)
|
|
97
|
+
input_file=get_tmp_num_filepath(temp_folder,index)
|
|
98
|
+
1.upto(count) do |i|
|
|
99
|
+
FileUtils.ln_s(input_file,get_tmp_num_filepath(temp_folder,index+i))
|
|
100
|
+
end
|
|
100
101
|
end
|
|
101
|
-
end
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
103
|
+
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
|
|
107
|
+
1.upto(count) do |i|
|
|
108
|
+
percent = 100 * i / (count + 1)
|
|
109
|
+
filename = get_tmp_num_filepath(temp_folder, index1 + i)
|
|
110
|
+
external_command(:composite,['-blend',percent,img2,img1,filename])
|
|
111
|
+
end
|
|
111
112
|
end
|
|
112
|
-
end
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
114
|
+
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?
|
|
116
|
+
ffmpeg(
|
|
117
|
+
in_f: input_file,
|
|
118
|
+
in_p: ['-ss',offset_seconds],
|
|
119
|
+
out_f: output_file,
|
|
120
|
+
out_p: ['-frames:v',1,'-filter:v',"scale=#{scale}"])
|
|
121
|
+
return output_file
|
|
122
|
+
end
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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
128
|
end
|
|
129
129
|
end # Options
|
|
130
130
|
end # Preview
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
// inspired by PACSuppport.js, 2003-2004 by Apple Computer, Inc., all rights reserved
|
|
2
|
-
function dnsResolve(host) {
|
|
3
|
-
if (host == '<%=context_host%>' || host == '<%=context_ip%>')
|
|
4
|
-
return '<%=context_ip%>';
|
|
5
|
-
throw 'only DNS for initial host, not '+host;
|
|
6
|
-
}
|
|
7
|
-
function myIpAddress() {
|
|
8
|
-
return '<%=context_self%>';
|
|
9
|
-
}
|
|
10
2
|
function isPlainHostName(host) {
|
|
11
3
|
return (host.indexOf('.') == -1 ? true : false);
|
|
12
4
|
}
|
|
13
|
-
function dnsDomainIs(host, domain) {
|
|
5
|
+
function dnsDomainIs(host, domain) {
|
|
14
6
|
var h = host.toLowerCase();
|
|
15
7
|
var d = domain.toLowerCase();
|
|
16
8
|
var sub = h.substring(h.length - d.length, h.length);
|
|
@@ -35,7 +27,7 @@ function isInNet(host, pattern, mask) {
|
|
|
35
27
|
var a = ip.split('.');
|
|
36
28
|
if ((p.length == m.length) && (m.length == a.length)) {
|
|
37
29
|
for (i = 0; i < p.length; i++) {
|
|
38
|
-
if ((p[i]& m[i]) != (m[i]& a[i]))
|
|
30
|
+
if ((p[i] & m[i]) != (m[i] & a[i]))
|
|
39
31
|
return false;
|
|
40
32
|
}
|
|
41
33
|
return true;
|
|
@@ -108,7 +100,7 @@ function dateRange() {
|
|
|
108
100
|
var today = new Date();
|
|
109
101
|
var num = arguments.length;
|
|
110
102
|
var gmt = arguments[num - 1];
|
|
111
|
-
if (typeof gmt !=
|
|
103
|
+
if (typeof gmt != "string")
|
|
112
104
|
gmt = false;
|
|
113
105
|
else {
|
|
114
106
|
gmt = gmt.toUpperCase();
|
|
@@ -137,8 +129,7 @@ function dateRange() {
|
|
|
137
129
|
y2 = arg;
|
|
138
130
|
else
|
|
139
131
|
return false;
|
|
140
|
-
}
|
|
141
|
-
else if (!arg)
|
|
132
|
+
} else if (!arg)
|
|
142
133
|
return false;
|
|
143
134
|
else if (!d1)
|
|
144
135
|
d1 = arg;
|
|
@@ -146,13 +137,12 @@ function dateRange() {
|
|
|
146
137
|
d2 = arg;
|
|
147
138
|
else
|
|
148
139
|
return false;
|
|
149
|
-
}
|
|
150
|
-
else if (typeof arg == "string") {
|
|
140
|
+
} else if (typeof arg == "string") {
|
|
151
141
|
var months = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
|
|
152
142
|
arg = arg.toUpperCase();
|
|
153
143
|
arg = months.indexOf(arg);
|
|
154
144
|
if (arg == -1)
|
|
155
|
-
return false;
|
|
145
|
+
return false;
|
|
156
146
|
arg /= 3;
|
|
157
147
|
arg += 1;
|
|
158
148
|
if (!m1)
|
|
@@ -161,23 +151,27 @@ function dateRange() {
|
|
|
161
151
|
m2 = arg;
|
|
162
152
|
else
|
|
163
153
|
return false;
|
|
164
|
-
}
|
|
165
|
-
else
|
|
154
|
+
} else
|
|
166
155
|
return false;
|
|
167
156
|
}
|
|
168
|
-
if (!y1)
|
|
169
|
-
|
|
170
|
-
if (!
|
|
171
|
-
|
|
172
|
-
if (!
|
|
173
|
-
|
|
157
|
+
if (!y1)
|
|
158
|
+
y1 = gmt ? today.getUTCFullYear() : today.getFullYear();
|
|
159
|
+
if (!y2)
|
|
160
|
+
y2 = y1;
|
|
161
|
+
if (!m1)
|
|
162
|
+
m1 = (gmt ? today.getUTCMonth() : today.getMonth()) + 1;
|
|
163
|
+
if (!m2)
|
|
164
|
+
m2 = m1;
|
|
165
|
+
if (!d1)
|
|
166
|
+
d1 = gmt ? today.getUTCDate() : today.getDate();
|
|
167
|
+
if (!d2)
|
|
168
|
+
d2 = d1;
|
|
174
169
|
var date1;
|
|
175
170
|
var date2;
|
|
176
171
|
if (gmt) {
|
|
177
172
|
date1 = Date.UTC(y1, m1 - 1, d1, 0, 0, 0, 0);
|
|
178
173
|
date2 = Date.UTC(y2, m2 - 1, d2, 23, 59, 59, 999);
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
174
|
+
} else {
|
|
181
175
|
date1 = (Date(y1, m1 - 1, d1, 0, 0, 0, 0)).valueOf();
|
|
182
176
|
date2 = (Date(y2, m2 - 1, d2, 23, 59, 59, 999)).valueOf();
|
|
183
177
|
}
|
|
@@ -190,7 +184,7 @@ function timeRange() {
|
|
|
190
184
|
var date2 = new Date();
|
|
191
185
|
var num = arguments.length;
|
|
192
186
|
var gmt = arguments[num - 1];
|
|
193
|
-
if (typeof gmt !=
|
|
187
|
+
if (typeof gmt != "string")
|
|
194
188
|
gmt = false;
|
|
195
189
|
else {
|
|
196
190
|
gmt = gmt.toUpperCase();
|
|
@@ -226,8 +220,7 @@ function timeRange() {
|
|
|
226
220
|
date2.setUTCSeconds(arg);
|
|
227
221
|
break;
|
|
228
222
|
}
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
223
|
+
} else {
|
|
231
224
|
switch (i) {
|
|
232
225
|
case 0:
|
|
233
226
|
date1.setHours(arg);
|
|
@@ -262,8 +255,7 @@ function timeRange() {
|
|
|
262
255
|
date2.setUTCSeconds(arg);
|
|
263
256
|
break;
|
|
264
257
|
}
|
|
265
|
-
}
|
|
266
|
-
else {
|
|
258
|
+
} else {
|
|
267
259
|
switch (i) {
|
|
268
260
|
case 0:
|
|
269
261
|
date2.setHours(arg);
|