sra2019 0.6.2 → 0.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.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/sra2019.rb +141 -13
  5. metadata +42 -2
  6. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1bf672d7d472fca296badabb57509cb9559c5cc4140461a4665e68946b009396
4
- data.tar.gz: 3c3c20b141f5f1d972055f78bb961e647d82fe5f12d12492be212c293ac59246
3
+ metadata.gz: 739c20e51f8410fedc1051d860d5f73478101d98961e33e4acbd66fadc1a19b6
4
+ data.tar.gz: d1cc50cf6530199c428d5e7b1dc827015162c4c0a2f8dce5a5f06a327d830208
5
5
  SHA512:
6
- metadata.gz: 3e7b77172be923047220f1b116e09707bab8bdb66016990e900324b16d71b4dca2c61da6db2445de67e55ac12cc8b3f08980c8305c364e6b2e2ff3c6350f9679
7
- data.tar.gz: 4d5ebaba19f49e0dd3ed8fcff0efdefb888bef1c983e8f730bfafd602be05a051932e150dc297a0bbe34bd5bb07bdc4d28e9d34c52342480cabc49d96da766b4
6
+ metadata.gz: b6c6716088a7234cfbdd731eccac19a051463ce8f1629634116442cc64c429d44b7a2967a22820b3a6a3fc2d0c1426b8a036997ee18e45bc3ab206e0ff253839
7
+ data.tar.gz: 852554f94c2df203a024f94adc0bc0345a873dfb0f9f35315e006ab62ca445952b1590f63c805faf43bb682828f98ab3a7d214163535b2ea4c20bf99c3b1bec4
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -12,6 +12,8 @@ require 'ostruct'
12
12
  require 'subunit'
13
13
  require 'zip/zip'
14
14
  require 'dynarex'
15
+ require 'ogginfo'
16
+ require 'wavefile'
15
17
  require 'rxfhelper'
16
18
  require 'wicked_pdf'
17
19
  require 'mini_magick'
@@ -20,6 +22,47 @@ require 'pollyspeech'
20
22
  require 'rexle-builder'
21
23
 
22
24
 
25
+ module WavTool
26
+ include WaveFile
27
+
28
+ def wav_silence(filename, duration: 1)
29
+
30
+ square_cycle = [0] * 100 * duration
31
+ buffer = Buffer.new(square_cycle, Format.new(:mono, :float, 44100))
32
+
33
+ Writer.new(filename, Format.new(:mono, :pcm_16, 22050)) do |writer|
34
+ 220.times { writer.write(buffer) }
35
+ end
36
+
37
+ end
38
+
39
+ def wav_concat(files, save_file='audio.wav')
40
+
41
+ Writer.new(save_file, Format.new(:stereo, :pcm_16, 22050)) do |writer|
42
+
43
+ files.each do |file_name|
44
+
45
+ Reader.new(file_name).each_buffer(samples_per_buffer=4096) do |buffer|
46
+ writer.write(buffer)
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ def ogg_to_wav(oggfile, wavfile=oggfile.sub(/\.ogg$/,'.wav'))
55
+
56
+ if block_given? then
57
+ yield(oggfile)
58
+ else
59
+ `oggdec #{oggfile}`
60
+ end
61
+
62
+ end
63
+
64
+ end
65
+
23
66
  module TimeHelper
24
67
 
25
68
  refine String do
@@ -33,14 +76,19 @@ end
33
76
  class StepsRecorderAnalyser
34
77
  using ColouredText
35
78
  using TimeHelper
79
+ include WavTool
36
80
 
37
- attr_reader :start_time, :stop_time
81
+ attr_reader :start_time, :duration
38
82
  attr_accessor :steps
39
83
 
40
84
 
41
- def initialize(s, debug: false, savepath: '/tmp', title: 'Untitled')
85
+ def initialize(s, debug: false, savepath: '/tmp', title: 'Untitled',
86
+ working_dir: '/tmp', pollyspeech: {access_key: nil,
87
+ secret_key: nil, voice_id: 'Amy',
88
+ cache_filepath: '/tmp/pollyspeech/cache'})
42
89
 
43
- @savepath, @title, @debug = savepath, title, debug
90
+ @savepath, @title, @working_dir, @debug = savepath, title,
91
+ working_dir, debug
44
92
 
45
93
  raw_content, type = RXFHelper.read(s)
46
94
 
@@ -56,7 +104,76 @@ class StepsRecorderAnalyser
56
104
  @all_steps = parse_steps content
57
105
  @doc = build @all_steps
58
106
  steps = @all_steps.select {|x| x[:user_comment]}
59
- @steps = steps.any? ? steps : tidy(@all_steps)
107
+ @steps = steps.any? ? steps : @all_steps
108
+
109
+ # find the duration for each step
110
+ @steps.each.with_index do |x, i|
111
+
112
+ x.duration = if i < @steps.length - 1 then
113
+ @steps[i+1].time - x.time
114
+ else
115
+ @duration - x.time
116
+ end
117
+
118
+ end
119
+
120
+ @pollyspeech = PollySpeech.new(pollyspeech) if pollyspeech[:access_key]
121
+
122
+ end
123
+
124
+ # adds the audio track to the video file
125
+ #
126
+ def add_audio_track(audio_file, video_file, target_video)
127
+
128
+ if block_given? then
129
+ yield(audio_file, video_file, target_video)
130
+ else
131
+ `ffmpeg -i #{video_file} -i #{audio_file} -codec copy -shortest #{target_video}`
132
+ end
133
+
134
+ end
135
+
136
+
137
+
138
+ def generate_audio(wav: true)
139
+
140
+ return nil unless @pollyspeech
141
+
142
+ @steps.each.with_index do |x, i|
143
+
144
+ puts 'x.desc: ' + x.desc.inspect if @debug
145
+ filename = "voice#{i+1}.ogg"
146
+
147
+ x.audio = filename
148
+ file = File.join(@working_dir, filename)
149
+ @pollyspeech.tts(x.desc.force_encoding('UTF-8'), file)
150
+
151
+ x.audio_duration = OggInfo.open(file) {|ogg| ogg.length.to_i }
152
+ x.silence_duration = x.duration - x.audio_duration
153
+
154
+ if wav then
155
+
156
+ silent_file = File.join(@working_dir, "silence#{(i+1).to_s}.wav")
157
+ wav_silence silent_file, duration: x.silence_duration
158
+ ogg_to_wav File.join(@working_dir, "voice#{i+1}.ogg")
159
+
160
+ end
161
+
162
+ sleep 0.6
163
+
164
+ end
165
+
166
+ if wav then
167
+
168
+ files = @steps.length.times.flat_map do |n|
169
+ [
170
+ File.join(@working_dir, "voice#{n+1}.wav"),
171
+ File.join(@working_dir, "silence#{n+1}.wav")
172
+ ]
173
+ end
174
+
175
+ wav_concat files, File.join(@working_dir, 'audio.wav')
176
+ end
60
177
 
61
178
  end
62
179
 
@@ -67,14 +184,15 @@ class StepsRecorderAnalyser
67
184
 
68
185
  end
69
186
 
70
- def tidy(steps)
187
+ def tidy!()
71
188
 
72
189
  verbose_level = 0
73
190
 
74
- steps.each do |x|
191
+ @steps.each do |x|
75
192
 
76
193
  x.desc.gsub!(/\s*\([^\)]+\)\s*/,'')
77
194
  x.desc.sub!(/ in "\w+"$/,'')
195
+ x.desc.sub!(/"User account for [^"]+"/,'the User account icon.')
78
196
 
79
197
  if x.desc =~ /User left click/ and verbose_level == 0 then
80
198
 
@@ -89,6 +207,11 @@ class StepsRecorderAnalyser
89
207
  elsif x.desc =~ /User left click/ and verbose_level == 2
90
208
 
91
209
  x.desc.sub!(/User left click/, 'Click')
210
+ verbose_level = 3
211
+
212
+ elsif x.desc =~ /User left click/ and verbose_level == 3
213
+
214
+ x.desc.sub!(/User left click on/, 'Select')
92
215
 
93
216
  else
94
217
  verbose_level = 0
@@ -118,7 +241,6 @@ class StepsRecorderAnalyser
118
241
 
119
242
  def to_kbml(options={})
120
243
 
121
-
122
244
  @doc.xml options
123
245
 
124
246
  end
@@ -185,9 +307,9 @@ EOF
185
307
  @sliml
186
308
  end
187
309
 
188
- def to_srt()
310
+ def to_srt(offset=0)
189
311
 
190
- lines = to_subtitles.strip.lines.map.with_index do |x, i|
312
+ lines = to_subtitles(offset).strip.lines.map.with_index do |x, i|
191
313
 
192
314
  raw_times, subtitle = x.split(/ /,2)
193
315
 
@@ -206,16 +328,20 @@ EOF
206
328
 
207
329
  end
208
330
 
209
- def to_subtitles()
331
+ def to_subtitles(offset=0)
210
332
 
211
- times = @all_steps.map(&:time).each_cons(2).map do |x|
333
+ raw_times = @all_steps.map(&:time)
334
+ raw_times << raw_times.last + 10
335
+
336
+ times = raw_times.each_cons(2).map do |x|
212
337
 
213
338
  x.map do |sec|
214
- a = Subunit.new(units={minutes:60, hours:60}, seconds: sec).to_h.to_a
339
+ a = Subunit.new(units={minutes:60}, seconds: sec+offset).to_h.to_a
215
340
  a.map {|x|"%d%s" % [x[1], x[0][0]] }.join('')
216
341
  end.join('-')
217
342
 
218
343
  end
344
+
219
345
  times.zip(@all_steps.map(&:desc)).map {|x| x.join(' ')}.join("\n")
220
346
 
221
347
  end
@@ -327,12 +453,14 @@ EOF
327
453
  puts 'session: ' + session.inspect if @debug
328
454
  puts 'attributes: ' + session.attributes.inspect if @debug
329
455
 
330
- @start_time, @stop_time = %w(Start Stop).map do |x|
456
+ @start_time, stop_time = %w(Start Stop).map do |x|
331
457
  v = session.attributes[(x + 'Time').to_sym]
332
458
  puts 'v: ' + v.inspect if @debug
333
459
  v.to_time
334
460
  end
335
461
 
462
+ @duration = stop_time - @start_time
463
+
336
464
  session.xpath('EachAction')
337
465
 
338
466
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sra2019
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -35,7 +35,7 @@ cert_chain:
35
35
  YgXo0DU1HUhuKAAuA0aZdb6DV5BqgZx9e27CLIKqRk5P7TikW49mFaelQfSRi675
36
36
  ugi0V/wkIOHFlKLS87IPnc09
37
37
  -----END CERTIFICATE-----
38
- date: 2019-04-29 00:00:00.000000000 Z
38
+ date: 2019-04-30 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: hlt
@@ -77,6 +77,46 @@ dependencies:
77
77
  - - "~>"
78
78
  - !ruby/object:Gem::Version
79
79
  version: '0.3'
80
+ - !ruby/object:Gem::Dependency
81
+ name: ogginfo
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '0.7'
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.7.2
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.7'
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 0.7.2
100
+ - !ruby/object:Gem::Dependency
101
+ name: wavefile
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 1.1.0
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.1'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 1.1.0
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '1.1'
80
120
  - !ruby/object:Gem::Dependency
81
121
  name: archive-zip
82
122
  requirement: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file