Skip to content

Commit

Permalink
EMRG-183 - test gif capture system
Browse files Browse the repository at this point in the history
  • Loading branch information
greeneca committed Nov 9, 2016
1 parent dda52f2 commit cb6500f
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 6 deletions.
2 changes: 2 additions & 0 deletions Gemfile.lock
Expand Up @@ -8,6 +8,7 @@ PATH
net-ping (~> 2.0)
net-telnet (~> 0.1)
nokogiri (~> 1.6)
rmagick (~> 2.16)
rubyzip (~> 1.2)

GEM
Expand Down Expand Up @@ -82,6 +83,7 @@ GEM
rb-fsevent (0.9.7)
rb-inotify (0.9.7)
ffi (>= 0.5.0)
rmagick (2.16.0)
ruby_dep (1.4.0)
rubyzip (1.2.0)
shellany (0.0.1)
Expand Down
12 changes: 10 additions & 2 deletions bin/roku
Expand Up @@ -3,7 +3,7 @@

$:.unshift File.join(File.dirname(__FILE__), "..", "lib")

#require "byebug"
require "byebug"
require "roku_builder"
require "optparse"
require "pathname"
Expand Down Expand Up @@ -64,6 +64,10 @@ parser = OptionParser.new do |opts|
options[:screencapture] = true
end

opts.on("-G", "--gif LENGTH", "Command: save a gif to the output file/folder") do |g|
options[:gifcapture] = g
end

opts.on("-y", "--type TEXT", "Command: type the given text on the roku device") do |t|
options[:text] = t
end
Expand Down Expand Up @@ -108,10 +112,14 @@ parser = OptionParser.new do |opts|
options[:update] = true
end

opts.on("-A", "--app-list", "Command: List currently installed apps") do
opts.on("--app-list", "Command: List currently installed apps") do
options[:applist] = true
end

opts.on("-A", "--actions ACTIONS", "Actions to be run during gif capture") do |a|
options[:actions] = a
end

opts.on("-r", "--ref REF", "Git referance to use for sideloading") do |r|
options[:ref] = r
end
Expand Down
7 changes: 7 additions & 0 deletions lib/roku_builder.rb
Expand Up @@ -20,6 +20,8 @@
require 'nokogiri'
#navigator
require 'io/console'
#inspector
require 'rmagick'

require "roku_builder/controller"
require "roku_builder/controller_commands"
Expand All @@ -42,6 +44,8 @@
require "roku_builder/monitor"
require "roku_builder/version"

include Magick

# Wrapping module for the Roku Builder Gem
module RokuBuilder

Expand Down Expand Up @@ -145,6 +149,9 @@ module RokuBuilder

# Bad print attribute
BAD_PRINT_ATTRIBUTE = 14

# Failed to capture gif
FAILED_GIFCAPTURE = 15
end

class ::String
Expand Down
8 changes: 7 additions & 1 deletion lib/roku_builder/config_parser.rb
Expand Up @@ -71,7 +71,7 @@ def self.setup_outfile(options:)
options[:out_folder] = nil
options[:out_file] = nil
if options[:out]
if options[:out].end_with?(".zip") or options[:out].end_with?(".pkg") or options[:out].end_with?(".jpg")
if options[:out].end_with?(".zip") or options[:out].end_with?(".pkg") or options[:out].end_with?(".jpg") or options[:out].end_with?(".gif")
options[:out_folder], options[:out_file] = Pathname.new(options[:out]).split.map{|p| p.to_s}
if options[:out_folder] = "." and not options[:out].start_with?(".")
options[:out_folder] = nil
Expand Down Expand Up @@ -250,6 +250,12 @@ def self.setup_simple_configs(config:, configs:, options:, logger:)
out_folder: options[:out_folder],
out_file: options[:out_file]
}
configs[:gifcapture_config] = {
length: options[:gifcapture].to_i,
out_folder: options[:out_folder],
out_file: options[:out_file],
actions: options[:actions]
}
if options[:screen]
configs[:screen_config] = {type: options[:screen].to_sym}
end
Expand Down
6 changes: 3 additions & 3 deletions lib/roku_builder/controller.rb
Expand Up @@ -162,8 +162,8 @@ def self.check_devices(options:, config:, configs:, logger:)
def self.commands
[:sideload, :package, :test, :deeplink,:configure, :validate, :delete,
:navigate, :navigator, :text, :build, :monitor, :update, :screencapture,
:key, :screen, :screens, :applist, :print, :profile, :dostage,
:dounstage]
:gifcapture, :key, :screen, :screens, :applist, :print, :profile,
:dostage, :dounstage]
end

# List of depricated options
Expand Down Expand Up @@ -194,7 +194,7 @@ def self.exclude_commands
# @return [Array<Symbol>] List of commands that require a device
def self.device_commands
[:sideload, :package, :test, :deeplink, :delete, :navigate, :navigator,
:text, :monitor, :screencapture, :applist, :profile ]
:text, :monitor, :screencapture, :gifcapture, :applist, :profile ]
end


Expand Down
2 changes: 2 additions & 0 deletions lib/roku_builder/controller_commands.rb
Expand Up @@ -24,6 +24,8 @@ def self.simple_commands
test: { klass: Tester, method: :run_tests, config_key: :test_config },
screencapture: { klass: Inspector, method: :screencapture, config_key: :screencapture_config,
failure: FAILED_SCREENCAPTURE },
gifcapture: { klass: Inspector, method: :gifcapture, config_key: :gifcapture_config,
failure: FAILED_GIFCAPTURE },
applist: {klass: Linker, method: :list},
profile: {klass: Profiler, method: :run, config_key: :profiler_config}
}
Expand Down
81 changes: 81 additions & 0 deletions lib/roku_builder/inspector.rb
Expand Up @@ -75,5 +75,86 @@ def screencapture(out_folder:, out_file: nil)
@logger.info "Screen captured to #{File.join(out_folder, out_file)}"
return response.success?
end

# Capture a gifcapture of the currently sideloaded app
# @param length [Integer] length in seconds of the animation
# @param out_folder [String] folder to save the animation to
# @param out_file [String] filename to save animation as (default: animation.gif)
# @param actions [String] comma seperated actions (should be integers or device commands)
# @return [Boolean] Success
def gifcapture(length:, out_folder:, out_file: nil, actions:)
fps = 15
delay = 2000
frame_count = length * fps
frames = Array.new(frame_count)
bad_frames = []

running = true
while running
start_time = Time.now
actions_thread = Thread.new("#{delay},#{actions}", @device_config) { |actions,config|
@logger.debug("Start actions: "+actions)
navigator = Navigator.new(**config)
actions = actions.split(",")
@logger.debug("Action Count: #{actions.count}")
while actions.count > 0
sleep_time = 0.0
while actions.count > 0 and actions[0].to_i.to_s == actions[0]
sleep_time += actions.shift.to_i
end
@logger.debug("Sleeping: #{sleep_time/1000}")
sleep sleep_time/1000
commands = []
while actions.count > 0 and actions[0].to_i.to_s != actions[0]
commands.push(actions.shift.to_sym)
end
@logger.debug("Navigating: #{commands.join(", ")}")
navigator.nav(commands: commands)
end
}
while Time.now - start_time < length
filename = "capture_#{Time.now.to_i}.jpg"
if screencapture(out_folder: out_folder, out_file: filename)
frame_timestamp = Time.now
frame_num = ((frame_timestamp-start_time-(delay/1000.0)) * fps).to_i + fps
@logger.debug("Frame: #{frame_num}")
if frames[frame_num]
bad_frames.push(File.join(out_folder, filename))
else
frames[frame_num] = File.join(out_folder, filename)
end
end
end
if frames.uniq.count >= frame_count*0.8
running = false
else
@logger.info ("#{frames.uniq.count} of #{frame_count} frames")
@logger.unknown("Return to animation start position. Press Enter when ready")
gets
delay -= 1000/fps
end
actions_thread.join
end


@logger.debug("Removeing bad frames")
bad_frames.each {|file| FileUtils.rm(file)} if bad_frames.count > 0

if frames.count > 0
out_file = "anim_#{Time.now.to_i}.gif" unless out_file
out = File.join(out_folder, out_file)

@logger.info("Generating Animation")
animation = ImageList.new(*frames)
animation.delay = 10
animation.write(out)

@logger.debug("Removeing frames")
frames.each {|file| FileUtils.rm(file)}
true
else
false
end
end
end
end
1 change: 1 addition & 0 deletions roku_builder.gemspec
Expand Up @@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "net-ping", "~> 2.0"
spec.add_dependency "net-telnet", "~> 0.1"
spec.add_dependency "nokogiri", "~> 1.6"
spec.add_dependency "rmagick", "~> 2.16"

spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 11.2"
Expand Down

0 comments on commit cb6500f

Please sign in to comment.