aspera-cli 4.6.0 → 4.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +427 -300
- data/bin/ascli +2 -1
- data/bin/asession +1 -0
- data/docs/test_env.conf +2 -0
- data/examples/aoc.rb +4 -3
- data/examples/faspex4.rb +21 -19
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +15 -15
- data/lib/aspera/aoc.rb +135 -124
- data/lib/aspera/ascmd.rb +85 -75
- 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 +138 -111
- 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 +13 -16
- data/lib/aspera/cli/main.rb +122 -130
- data/lib/aspera/cli/manager.rb +146 -154
- data/lib/aspera/cli/plugin.rb +38 -34
- data/lib/aspera/cli/plugins/alee.rb +6 -6
- data/lib/aspera/cli/plugins/aoc.rb +273 -276
- data/lib/aspera/cli/plugins/ats.rb +82 -76
- data/lib/aspera/cli/plugins/bss.rb +14 -16
- data/lib/aspera/cli/plugins/config.rb +350 -306
- 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 +180 -159
- data/lib/aspera/cli/plugins/faspex5.rb +64 -54
- data/lib/aspera/cli/plugins/node.rb +147 -140
- data/lib/aspera/cli/plugins/orchestrator.rb +68 -66
- 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 +23 -24
- data/lib/aspera/cli/plugins/sync.rb +20 -22
- data/lib/aspera/cli/transfer_agent.rb +40 -39
- 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/agent_base.rb +22 -20
- data/lib/aspera/fasp/agent_connect.rb +13 -11
- data/lib/aspera/fasp/agent_direct.rb +48 -59
- data/lib/aspera/fasp/agent_httpgw.rb +33 -39
- data/lib/aspera/fasp/agent_node.rb +15 -13
- data/lib/aspera/fasp/agent_trsdk.rb +12 -14
- data/lib/aspera/fasp/error.rb +2 -1
- data/lib/aspera/fasp/error_info.rb +68 -52
- data/lib/aspera/fasp/installation.rb +106 -94
- data/lib/aspera/fasp/listener.rb +1 -0
- data/lib/aspera/fasp/parameters.rb +83 -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 -90
- data/lib/aspera/hash_ext.rb +4 -3
- data/lib/aspera/id_generator.rb +8 -7
- data/lib/aspera/keychain/encrypted_hash.rb +17 -16
- data/lib/aspera/keychain/macos_security.rb +6 -10
- data/lib/aspera/log.rb +25 -20
- data/lib/aspera/nagios.rb +13 -12
- data/lib/aspera/node.rb +30 -22
- 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 +115 -113
- 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 +64 -21
- data/docs/Makefile +0 -65
- data/docs/README.erb.md +0 -4424
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/fasp/default.rb +0 -17
@@ -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);
|